/* indent:4  tabsize:8  font:fixed-width */

#import "SmallCard.h"

/*-----------------------------------------------------------------------------
|
|    Card Globals
|
|    The arrays _CardPipPositions and _CardCardPips provide information about
|    the positioning of pips on cards.  There are 17 possible positions,
|    described in pipPositions, which are selectively refrerred to for each of
|    13 possible card values by a character string.
|
|    The letters A-Q are used to represent pips present in the given card.
|
|    The id's _CardFront, _CardBack etc... are images shared by all instances
|    of Card
|
\----------------------------------------------------------------------------*/

static NXPoint _CardPipPositions[] = {
    {13, 91}, {30, 91}, {47, 91},
    {30, 78},
    {30, 71},
    {13, 64}, {47, 64},
    {13, 52}, {30, 52}, {47, 52},
    {13, 39}, {47, 39},
    {30, 32},
    {30, 25},
    {13, 13}, {30, 13}, {47, 13}
};

extern char *_CardCardPips[];

// WARNING:  Because these static variables have the same names as static
//           variables in the superclass, override any methods that access
//           them.  The same goes for "_CardPipPositions" above.

static id _CardFrontImage, _CardBackImage, _CardSymbolsImage,
    _CardKingClubsImage, _CardKingDiamondsImage, _CardKingHeartsImage,
    _CardKingSpadesImage, _CardQueenClubsImage, _CardQueenDiamondsImage,
    _CardQueenHeartsImage, _CardQueenSpadesImage, _CardJackClubsImage,
    _CardJackDiamondsImage, _CardJackHeartsImage, _CardJackSpadesImage,
    _CardAceOfSpadesImage;

static id _preDrawnImage[52];

static BOOL _preDrawnImagesAvailable;
static BOOL _setCustomImage;


@implementation SmallCard

/*----------------------------------------------------------------------------
|
|    + initialize
|
|    returns:  (id) [super initialize]
|
|-----------------------------------------------------------------------------
|
|    Initialize the private pasteboard type used by the CardPileView and load
|    all images used by the CardPileView class.
|			
\----------------------------------------------------------------------------*/

+ initialize
{
    if (self == [SmallCard class])
    {
        _CardFrontImage = [NXImage findImageNamed:"sCard"];
        _CardBackImage = [NXImage findImageNamed:"sBack"];
        _CardKingClubsImage = [NXImage findImageNamed:"sKingClubs"];
        _CardKingDiamondsImage = [NXImage findImageNamed:"sKingDiamonds"];
        _CardKingHeartsImage = [NXImage findImageNamed:"sKingHearts"];
        _CardKingSpadesImage = [NXImage findImageNamed:"sKingSpades"];
        _CardQueenClubsImage = [NXImage findImageNamed:"sQueenClubs"];
        _CardQueenDiamondsImage = [NXImage findImageNamed:"sQueenDiamonds"];
        _CardQueenHeartsImage = [NXImage findImageNamed:"sQueenHearts"];
        _CardQueenSpadesImage = [NXImage findImageNamed:"sQueenSpades"];
        _CardJackClubsImage = [NXImage findImageNamed:"sJackClubs"];
        _CardJackDiamondsImage = [NXImage findImageNamed:"sJackDiamonds"];
        _CardJackHeartsImage = [NXImage findImageNamed:"sJackHearts"];
        _CardJackSpadesImage = [NXImage findImageNamed:"sJackSpades"];
        _CardAceOfSpadesImage = [NXImage findImageNamed:"sAceOfSpades"];
        _CardSymbolsImage = [NXImage findImageNamed:"sSymbols"];
    }
    [super initialize];
    return self;
}


/*----------------------------------------------------------------------------
|
|    + drawCardImages
|
|    returns:  (id) self
|
|-----------------------------------------------------------------------------
|
|    Draws the pre-cached images for every card in the deck.
|			
\----------------------------------------------------------------------------*/

+ drawCardImages
{
    id tempCard;
    int i,j;
    NXSize aSize;

    if(_preDrawnImagesAvailable) return self;	// don't draw again
    [_CardFrontImage getSize:&aSize];
    for(i=0; i<4; i++){
	for(j=0; j<13; j++){
	    tempCard = [[SmallCard alloc] initSuit:i value:j faceUp:YES];
	    _preDrawnImage[(i*13)+j] = [[NXImage alloc] initSize:&aSize];
	    [_preDrawnImage[(i*13)+j] useDrawMethod:@selector(preDrawCard:) inObject:tempCard];
	    if([_preDrawnImage[(i*13)+j] lockFocus])
		[_preDrawnImage[(i*13)+j] unlockFocus];
	    [tempCard free];
	}
    }
    _preDrawnImagesAvailable = YES;
    return self;
}


/*----------------------------------------------------------------------------
|
|    + freeCardImages
|
|    returns:  (id) self
|
|-----------------------------------------------------------------------------
|
|    Frees the pre-cached images for every card in the deck.
|			
\----------------------------------------------------------------------------*/

+ freeCardImages
{
    int i;

    if(!_preDrawnImagesAvailable) return self;	// don't free again    
    for(i=0; i<52; i++){
    	[_preDrawnImage[i] free];
    }
    _preDrawnImagesAvailable = NO;
    return self;
}


/*----------------------------------------------------------------------------
|
|    + setCardBackImage:(id)theImage
|
|    returns:  (id) self
|
|-----------------------------------------------------------------------------
|
|    Sets the image used to draw the card backs.
|			
\----------------------------------------------------------------------------*/

+ setCardBackImage:theImage
{
    if(theImage){
        if(_setCustomImage) [_CardBackImage free];
    	_CardBackImage = [theImage copyFromZone:[self zone]];
	_setCustomImage = YES;
    }
    return self;
}


/*----------------------------------------------------------------------------
|
|    + setCardBack:(CardBack)aBack
|
|    returns:  (id) self
|
|-----------------------------------------------------------------------------
|
|    Sets the id # and corresponding image used to draw the card backs.
|			
\----------------------------------------------------------------------------*/

+ setCardBack:(CardBack)aBack
{
    if(_setCustomImage) [_CardBackImage free];
    _setCustomImage = NO;

    switch (aBack)
    {
    case CS_DEFAULT:
	_CardBackImage = [NXImage findImageNamed:"sBack"];
	break;
    case CS_TRAD:
	_CardBackImage = [NXImage findImageNamed:"sTradBack"];
	break;
    case CS_SHIP:
	_CardBackImage = [NXImage findImageNamed:"sShip"];
	break;
    default:
	_CardBackImage = [NXImage findImageNamed:"sBack"];
	break;
    }
    return self;
}


/*---------------------------------------------------------------------------
|
|    - copyFromZone:(NXZone *)zone
|
|    returns: (id)  an object which is a duplicate of the sender
|
|----------------------------------------------------------------------------
|
|    Create a copy of a small card.
|			
\----------------------------------------------------------------------------*/

- copyFromZone:(NXZone *)zone
{
    return [[SmallCard allocFromZone:zone]
                            initSuit:suit 
		               value:value 
			      faceUp:faceUp];
}


/*---------------------------------------------------------------------------
|
|    - preDrawCard :(id) theImage
|
|    returns:  (id)  self
|
|----------------------------------------------------------------------------
|
|    Pre-draw a visual representation of ourself.
|
\----------------------------------------------------------------------------*/

- preDrawCard:theImage
{
    NXPoint thePoint={0.,0.};
    
    [self drawOutlineAt:&thePoint];
    [self drawContentsAt:&thePoint];
    return self;
}


/*---------------------------------------------------------------------------
|
|    - drawCardAt :(NXPoint *) thePoint
|
|    returns:  (id)  self
|
|----------------------------------------------------------------------------
|
|    Draw a visual representation of ourself at a given location.
|
\----------------------------------------------------------------------------*/

- drawCardAt:(NXPoint *)thePoint
{
    if(_preDrawnImagesAvailable && faceUp){
    	[_preDrawnImage[(suit*13)+value] composite:NX_SOVER toPoint:thePoint];
	return self;
    }
    [self drawOutlineAt:thePoint];
    [self drawContentsAt:thePoint];
    return self;
}


/*---------------------------------------------------------------------------
|
|    - drawOutlineAt:(NXPoint *)thePoint
|
|    returns: (id)  self
|
|----------------------------------------------------------------------------
|
|    Draw the outline of a card at a given location.
|
\----------------------------------------------------------------------------*/

- drawOutlineAt:(NXPoint *)thePoint
{
    [_CardFrontImage composite:NX_SOVER toPoint:thePoint];
    return self;
}


/*---------------------------------------------------------------------------
|
|    - drawContentsAt:(NXPoint *)thePoint
|
|    returns: (id)  self
|
|----------------------------------------------------------------------------
|
|    Draw our contents at a given location
|
\----------------------------------------------------------------------------*/

- drawContentsAt:(NXPoint *)thePoint
{
    if (!faceUp)
    {
    
	/*------------------------------------------------------ 
	|
	|    Draw the back of the card
	|
	\------------------------------------------------------*/

        NXPoint destPoint = {thePoint->x + 6, thePoint->y + 5};

        [_CardBackImage composite:NX_SOVER toPoint:&destPoint];
	
    } else {
    
	/*---------------------------------------------------------
	|
	|    Draw the upper left / lower right value indicator
	|
	\---------------------------------------------------------*/

        {
            NXRect sourceRect = {value * 16, 60, 8, 15};
            NXPoint destPoint = {thePoint->x + 3, thePoint->y + 106};
			
            if (([self cardColor] == CS_RED))
	    {
                sourceRect.origin.x += 8;
            }
            [_CardSymbolsImage composite:NX_SOVER
                                fromRect:&sourceRect 
				 toPoint:&destPoint];
			
            sourceRect.origin.y -= 16;
            destPoint.x = thePoint->x + 69;
            destPoint.y = thePoint->y + 6;
			
            [_CardSymbolsImage composite:NX_SOVER
                                fromRect:&sourceRect
	 			 toPoint:&destPoint];
        }

	/*----------------------------------------------------------
	|
	|    Draw the upper left / lower right suit indicator
	|
	\----------------------------------------------------------*/

        {
            NXRect sourceRect = {suit * 10, 10, 10, 12};
            NXPoint destPoint = {thePoint->x + 2, thePoint->y + 94};
			
	    [_CardSymbolsImage composite:NX_SOVER
				fromRect:&sourceRect
				 toPoint:&destPoint];
            sourceRect.origin.x += 40;
            destPoint.x = thePoint->x + 69;
            destPoint.y = thePoint->y + 21;
	    [_CardSymbolsImage composite:NX_SOVER
				fromRect:&sourceRect 
				 toPoint:&destPoint];
        }

	/*---------------------------------------------------------
	|
	|    Draw special card images for face cards and the
	|    ace of spades
	|
	\---------------------------------------------------------*/

        {
            NXPoint destPoint = {thePoint->x + 12, thePoint->y + 12};
    
	    switch (value)
	    {
	    case CS_JACK:
	        switch (suit)
		{
		case CS_CLUBS:
                    [_CardJackClubsImage composite:NX_SOVER
		                           toPoint:&destPoint];
		    break;
		case CS_DIAMONDS:
                    [_CardJackDiamondsImage composite:NX_SOVER
		                              toPoint:&destPoint];
		    break;
		case CS_HEARTS:
                    [_CardJackHeartsImage composite:NX_SOVER
		                            toPoint:&destPoint];
                    break;
                case CS_SPADES:
                    [_CardJackSpadesImage composite:NX_SOVER 
		                            toPoint:&destPoint];
		    break;
		}
		return self;

            case CS_QUEEN:
                switch (suit)
		{
		case CS_CLUBS:
                    [_CardQueenClubsImage composite:NX_SOVER 
		                            toPoint:&destPoint];
		    break;
		case CS_DIAMONDS:
                    [_CardQueenDiamondsImage composite:NX_SOVER
		                               toPoint:&destPoint];
		    break;
		case CS_HEARTS:
                    [_CardQueenHeartsImage composite:NX_SOVER
		                             toPoint:&destPoint];
		    break;
		case CS_SPADES:
                    [_CardQueenSpadesImage composite:NX_SOVER
		                             toPoint:&destPoint];
		    break;
		}
		return self;
            
            case CS_KING:
	        switch (suit)
		{
		case CS_CLUBS:
		    [_CardKingClubsImage composite:NX_SOVER
		                           toPoint:&destPoint];
		    break;
		case CS_DIAMONDS:
		    [_CardKingDiamondsImage composite:NX_SOVER 
			                      toPoint:&destPoint];
		    break;
		case CS_HEARTS:
		    [_CardKingHeartsImage composite:NX_SOVER
		                            toPoint:&destPoint];
		    break;
		case CS_SPADES:
                    [_CardKingSpadesImage composite:NX_SOVER 
		                            toPoint:&destPoint];
		    break;
		}
		return self;
		
	    default:
	        break;
	    }
			
	    /*----------------------------------------------------
	    |
	    |    Not only draw the special image for the ace of
	    |    spades, but avoid the standard suit pip drawing
	    |
	    \----------------------------------------------------*/

	    if ((value == CS_ACE) && (suit == CS_SPADES))
	    {
                [_CardAceOfSpadesImage composite:NX_SOVER toPoint:&destPoint];
                return self;
	    }
        }
		
	/*------------------------------------------------------
	|
	|    Draw suit pips on the card based on patterns
	|    defined by the _CardCardSymbols and
	|    _CardCardPips arrays
	|
	\------------------------------------------------------*/

	{
            NXRect suitRect = {suit * 20, 23, 20, 21};
            NXRect upsideSuitRect = {80 + suit * 20, 23, 20, 21};
	    char *pipString = _CardCardPips[value];

	    while (*pipString)
	    {
		NXPoint tempPoint = _CardPipPositions[*pipString - 'A'];
		tempPoint.x += thePoint->x;
		tempPoint.y += thePoint->y;
		[_CardSymbolsImage composite:NX_SOVER
		    fromRect:(*pipString < 'K') ? &suitRect : &upsideSuitRect
		     toPoint:&tempPoint];
		pipString++;
	    }
        }
    }
    return self;
}

@end
