///////////////////////////////////////////////////////////////////////////////
// $Id: Deck.cxx,v 1.1 1995/01/12 02:10:42 bmott Exp $
///////////////////////////////////////////////////////////////////////////////
//
// Deck.cxx - Deck class
//
//
// Bradford W. Mott
// Copyright (C) 1994
// December 11,1994
//
///////////////////////////////////////////////////////////////////////////////
// $Log: Deck.cxx,v $
// Revision 1.1  1995/01/12  02:10:42  bmott
// Initial revision
//
///////////////////////////////////////////////////////////////////////////////

#include <time.h>
#include <stdlib.h>

#include "UIApplication.hxx"
#include "Deck.hxx"

///////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////
Deck::Deck(ContainerWidget* parent, const char *const widgetName,
        int x, int y, int width, int maxHeight, SpriteCollection* sprites)
    : DrawingArea(parent, widgetName, x, y, width, maxHeight),
      myMaximumHeight(maxHeight),
      mySprites(sprites)
{ }

///////////////////////////////////////////////////////////////////////////////
// Destructor
///////////////////////////////////////////////////////////////////////////////
Deck::~Deck()
{ }

///////////////////////////////////////////////////////////////////////////////
// Add the given card to myself
///////////////////////////////////////////////////////////////////////////////
void Deck::add(Card* card)
{
  myListOfCards.append(card);
  updateView();
}

///////////////////////////////////////////////////////////////////////////////
// Add the given cards to myself
///////////////////////////////////////////////////////////////////////////////
void Deck::add(LinkedList<Card>* cards)
{
  for(Card* card = cards->removeHead(); card != NULL;
       card = cards->removeHead())
  {
    myListOfCards.append(card);
  }
  updateView();
}

///////////////////////////////////////////////////////////////////////////////
// Remove the my top card if one exists
///////////////////////////////////////////////////////////////////////////////
Card* Deck::remove()
{
  Card* card = myListOfCards.remove();
  updateView();
  return(card);
}

///////////////////////////////////////////////////////////////////////////////
// Turn my top card over if it needs to be
///////////////////////////////////////////////////////////////////////////////
void Deck::turnTopCardFaceUp()
{
  Card* top = myListOfCards.tail();

  if(top != NULL)
  {
    top->orientation(FaceUp);
    updateView();
  }
}

///////////////////////////////////////////////////////////////////////////////
// Shuffle deck
///////////////////////////////////////////////////////////////////////////////
void Deck::shuffle()
{
  // Don't shuffle if it's empty :-)
  if(myListOfCards.size() == 0)
    return;

  // Seed the random number generator with the system time
  srand( (unsigned int)time(NULL) );

  for(int t=0; t<100; ++t)
  {
    int cardNumber = ((unsigned long)rand()) % myListOfCards.size();

    Card* card = myListOfCards.first();
    for(int i=0; i<cardNumber; ++i) 
      card = myListOfCards.next();

    // Move the card to the top of the deck
    myListOfCards.remove(card);
    myListOfCards.prepend(card); 
  }

  // Update my view
  updateView();
}

///////////////////////////////////////////////////////////////////////////////
// Determine the corresponding card index from the y coordinate in my view
///////////////////////////////////////////////////////////////////////////////
int Deck::cardIndexFromCoordinate(int y)
{
  int index = -1;

  if(myCardOffset > 0.0)
    index = (int)((double)y / myCardOffset);

  if(index >= myListOfCards.size())
    index = myListOfCards.size() - 1;

  return(index);
}

///////////////////////////////////////////////////////////////////////////////
// Update the graphical view of myself
///////////////////////////////////////////////////////////////////////////////
void Deck::updateView()
{
  Pixmap pixmap;
  char* imageData;

  Sprite* backOfCard = mySprites->getByName("StandardBack");
  Sprite* emptyDeck = mySprites->getByName("EmptyDeck");

  int numberOfCards = myListOfCards.size();
  int cardWidth = backOfCard->width();
  int cardHeight = backOfCard->height();
  int drawingAreaHeight;
  int drawingAreaWidth;

  // See if I have any cards
  if(numberOfCards > 0)
  {
    myCardOffset = (float)cardHeight * 0.25; 
    drawingAreaHeight = (int)(cardHeight + (numberOfCards-1) * myCardOffset);
    drawingAreaWidth = cardWidth;

    // See if we have to squash the cards to get them to fit
    if(drawingAreaHeight > myMaximumHeight)
    {
      myCardOffset = (float)(myMaximumHeight - cardHeight)/(float)(numberOfCards-1);
      drawingAreaHeight = myMaximumHeight;
    }

    // Build pixmap to hold my view
    pixmap = XCreatePixmap(application->display(), myWindow,
        drawingAreaWidth, drawingAreaHeight, 8);

    float pixmapOffset = 0.0;
    for(Card* card=myListOfCards.first(); card!=(Card*)0 ;
        card=myListOfCards.next())
    {
      Sprite* sprite;

      // See if the card is face up or face down
      if(card->orientation() == FaceDown)
        sprite = backOfCard;
      else
        sprite = card->face();

      if(card == myListOfCards.tail())
        pixmapOffset = drawingAreaHeight - cardHeight;

      XPutImage(application->display(), pixmap, application->gc(),
          sprite->image(), 0, 0, 0, (int)pixmapOffset, 
          sprite->width(), sprite->height());

      pixmapOffset += myCardOffset;
    }
  }
  else
  {
    Sprite* sprite = emptyDeck;
    drawingAreaHeight = sprite->height();
    drawingAreaWidth = sprite->width();

    // Build pixmap to hold my view
    pixmap = XCreatePixmap(application->display(), myWindow, 
        drawingAreaWidth, drawingAreaHeight, 8);
    
    XPutImage(application->display(), pixmap, application->gc(), 
        sprite->image(), 0, 0, 0, 0, sprite->width(), sprite->height());
  }

  // Install the pixmap on my drawing area
  XSetWindowBackgroundPixmap(application->display(), myWindow, pixmap);

  // Make sure the window refreshes
  XClearWindow(application->display(), myWindow);

  // Resize the window to fit the pixmap
  resize(drawingAreaWidth, drawingAreaHeight);

  // Free the pixmap
  XFreePixmap(application->display(), pixmap);
}

///////////////////////////////////////////////////////////////////////////////
// Called whenever an event arrives for me (I need to override the default)
///////////////////////////////////////////////////////////////////////////////
void Deck::handleEvent(XEvent* event)
{
  return;
  if ((event->type == ButtonPress) && (event->xbutton.button == Button1))
  {
    int done = 0;

    int parentRootX = 0;
    int parentRootY = 0;

    while(!done)
    {
      XEvent event;

      XNextEvent(application->display(), &event);

      switch(event.type)
      {
        case MotionNotify:
          int newX = event.xmotion.x_root - parentRootX - width()/2;
          int newY = event.xmotion.y_root - parentRootY - height()/2;

          move(newX, newY);
          break; 

        case ButtonRelease:
          done = 1;
          break;

        default:
          application->dispatchEvent(&event);
          break;
      }
    }
  }
}

