//
// This file is a part of Risk by Mike Ferris.
//

#import "Risk.h"

RCSID ("$Id: CardPanelController.m,v 1.3 1997/12/15 07:43:41 nygard Exp $");

#import "CardPanelController.h"

#import "RiskCard.h"
#import "RiskPlayer.h"
#import "Country.h"
#import "RiskGameManager.h"
#import "CardSet.h"

//======================================================================
// The CardPanelController provides interactive Risk players with an
// interface for reviewing their hand and choosing card sets to turn
// in.  It will force the player to turn in cards when they are able to
// and have more than four cards in their hand.
//
// The cards are not turned in until all sets have been chosen.  The
// RiskPlayer is notified about the number of extra armies for each
// set turned in.
//======================================================================

#define CardPanelController_VERSION 1

static NSImage *_cardBackImage = nil;
static NSImage *_littleStarImage = nil;

struct image_names
{
    NSString *i_name;
    NSImage **i_image;
};

static struct image_names class_images[] =
{
    { @"CardBack.tiff",    &_cardBackImage },
    { @"LittleStar.tiff",  &_littleStarImage },
};

@implementation CardPanelController

+ (void) initialize
{
    if (self == [CardPanelController class])
    {
        [self setVersion:CardPanelController_VERSION];

        if ([NSBundle bundleForClass:self] == nil)
        {
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                  selector:@selector (loadClassImages)
                                                  name:NSApplicationDidFinishLaunchingNotification
                                                  object:NSApp];
        }
        else
        {
            [self loadClassImages];
        }
    }
}

//----------------------------------------------------------------------

+ (void) loadClassImages
{
    int l;
    NSBundle *thisBundle;
    NSString *imagePath;

    if (self == [CardPanelController class])
    {
        thisBundle = [NSBundle bundleForClass:self];
        NSAssert (thisBundle != nil, @"Could not get bundle.");

        // load class images
        for (l = 0; l < sizeof (class_images) / sizeof (struct image_names); l++)
        {
            imagePath = [thisBundle pathForImageResource:class_images[l].i_name];
            NSAssert1 (imagePath != nil, @"Could not find image: '%@'", class_images[l].i_name);

            *(class_images[l].i_image) = [[NSImage alloc] initByReferencingFile:imagePath];
            NSAssert1 (*(class_images[l].i_image) != nil, @"Couldn't load image: '%@'\n", class_images[l].i_name);
        }
    }

    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

//----------------------------------------------------------------------

- init
{
    BOOL loaded;
    NSString *nibFile;

    if ([super init] == nil)
        return nil;

    nibFile = @"CardPanel.nib";
    loaded = [NSBundle loadNibNamed:nibFile owner:self];
    if (loaded == NO)
    {
        NSLog (@"Could not load %@.", nibFile);
        [super dealloc];
        return nil;
    }

    currentPlayerNumber = 0;

    gameManager = nil;
    playerCards = nil;
    cardSets = [[NSMutableArray array] retain];

    return self;
}

//----------------------------------------------------------------------

- (void) dealloc
{
    SNRelease (currentSet[0]);
    SNRelease (currentSet[1]);
    SNRelease (currentSet[2]);

    SNRelease (gameManager);
    SNRelease (playerCards);
    SNRelease (cardSets);
    
    [super dealloc];
}

//----------------------------------------------------------------------

// Note: We can't use a matrix of NSImageCells, because it seems that
// they don't allow a selected cell, and so we can't tell which cell
// was clicked.

- (void) handAction:sender
{
    NSCell *cell;
    int index;

    index = [handMatrix selectedColumn];
	
    if (index != -1 && canTurnInCards == YES && setMatrixCount < 3 )
    {
        cell = [handMatrix cellAtRow:0 column:index];
        
        // if there is room in the box and they didn't click on an empty cell
        if ([cell image] == _cardBackImage)
        {
            return;
        }

        if (setMatrixCount == 2)
        {
            RiskCard *lastCard;

            lastCard = [playerCards objectAtIndex:index];

            // check to see if this one will make a third
            if ([CardSet isValidCardSet:currentSet[0]:currentSet[1]:lastCard] == NO)
            {
                NSBeep();
                return;
            }
        }

        // turn the card over
        [cell setImage:_cardBackImage];

        // record which card it is
        currentSet[setMatrixCount] = [playerCards objectAtIndex:index];
        currentIndices[setMatrixCount] = index;

        // put it down below
        [[setMatrix cellAtRow:0 column:setMatrixCount] setImage:[currentSet[setMatrixCount] image]];
        [[setStarMatrix cellAtRow:0 column:setMatrixCount] setImage:[[handStarMatrix cellAtRow:0 column:index] image]];
		
        setMatrixCount++;

        [handMatrix setNeedsDisplay:YES];
        [setMatrix setNeedsDisplay:YES];
        [handStarMatrix setNeedsDisplay:YES];
        [setStarMatrix setNeedsDisplay:YES];

        if (setMatrixCount == 3)
        {
            [turnInButton setEnabled:YES];
        }
    }
}

//----------------------------------------------------------------------

- (void) setAction:sender
{
    int index;
    int l;
	
    index = [setMatrix selectedColumn];

    // put it back up above
    if (index >= 0 && index < setMatrixCount)
    {
        [[handMatrix cellAtRow:0 column:currentIndices[index]] setImage:[currentSet[index] image]];

        // move the others back a step
        for (l = index; l < setMatrixCount - 1; l++)
        {
            [[setMatrix cellAtRow:0 column:l] setImage:[[setMatrix cellAtRow:0 column:l + 1] image]];
            [[setStarMatrix cellAtRow:0 column:l] setImage:[[setStarMatrix cellAtRow:0 column:l + 1] image]];
            currentSet[l] = currentSet[l + 1];
            currentIndices[l] = currentIndices[l + 1];
        }

        [[setMatrix cellAtRow:0 column:setMatrixCount - 1] setImage:nil];
        [[setStarMatrix cellAtRow:0 column:setMatrixCount - 1] setImage:nil];
        currentSet[setMatrixCount - 1] = nil;
        currentIndices[setMatrixCount - 1] = -1;
        setMatrixCount--;

        [handMatrix setNeedsDisplay:YES];
        [setMatrix setNeedsDisplay:YES];
        [handStarMatrix setNeedsDisplay:YES];
        [setStarMatrix setNeedsDisplay:YES];
    }

    if (setMatrixCount < 3)
    {
        [turnInButton setEnabled:NO];
    }
}

//----------------------------------------------------------------------

- (void) doneAction:sender
{
    NSEnumerator *cardSetEnumerator;
    CardSet *cardSet;

    // Go through list of sets, and instruct the game manager to turn
    // in those card sets on behalf of the player.

    cardSetEnumerator = [cardSets objectEnumerator];
    while (cardSet = [cardSetEnumerator nextObject])
    {
        [gameManager turnInCardSet:cardSet forPlayerNumber:currentPlayerNumber];
    }

    [cardSets removeAllObjects];

    [NSApp stopModal];
}

//----------------------------------------------------------------------

// Cancel sets -- remove cards sets, show all cards again, and enable
// the done button.

- (void) stopAction:sender
{
    [cardSets removeAllObjects];
    [self enableButtons];
    [self resetPanel];
}

//----------------------------------------------------------------------

- (void) turnInSetAction:sender
{
    CardSet *cardSet;
    int l;
	
    if (setMatrixCount == 3)
    {
        cardSet = [CardSet cardSet:currentSet[0]:currentSet[1]:currentSet[2]];
        NSAssert (cardSet != nil, @"Invalid card set.");
        
        for (l = 0; l < 3; l++)
        {
            currentSet[l] = nil;
            currentIndices[l] = -1;
            [[setMatrix cellAtRow:0 column:l] setImage:nil];
            [[setStarMatrix cellAtRow:0 column:l] setImage:nil];
        }

        setMatrixCount = 0;
        [setMatrix setNeedsDisplay:YES];
        [setStarMatrix setNeedsDisplay:YES];

        [amassedTextField setIntValue:[amassedTextField intValue] + currentCardSetValue];
        currentCardSetValue = [gameManager _valueOfNextCardSet:currentCardSetValue];

        [cardSets addObject:cardSet];
        [self enableButtons];
    }

    [worthTextField setIntValue:currentCardSetValue];
}

//----------------------------------------------------------------------

- (void) enableButtons
{
    if (canTurnInCards == YES && [playerCards count] - ([cardSets count] * 3) > 4)
        [doneButton setEnabled:NO];
    else
        [doneButton setEnabled:YES];

    if ([cardSets count] > 0)
        [cancelButton setEnabled:YES];
    else
        [cancelButton setEnabled:NO];
}

//----------------------------------------------------------------------

- (void) resetPanel
{
    int l, cardCount;
    NSRect aFrame, boundsRect;
    RiskCard *card;
    NSView *superView;

    cardCount = [playerCards count];

    [handMatrix renewRows:1 columns:cardCount];
    [handStarMatrix renewRows:1 columns:cardCount];

    [handMatrix sizeToCells];
    [handStarMatrix sizeToCells];

    aFrame = NSUnionRect ([handMatrix frame], [handStarMatrix frame]);

    superView = [handMatrix superview];
    boundsRect = [superView bounds];

    boundsRect.size.width = aFrame.origin.x + aFrame.size.width;
    [superView setFrameSize:boundsRect.size]; // -setBounds: is ineffective..
    [superView setNeedsDisplay:YES];

    for (l = 0; l < cardCount; l++)
    {
        card = [playerCards objectAtIndex:l];
        [[handMatrix cellAtRow:0 column:l] setImage:[card image]];
        if ([[card country] playerNumber] == currentPlayerNumber)
            [[handStarMatrix cellAtRow:0 column:l] setImage:_littleStarImage];
        else
            [[handStarMatrix cellAtRow:0 column:l] setImage:nil];
    }

    for (l = 0; l < 3; l++)
    {
        [[setMatrix cellAtRow:0 column:l] setImage:nil];
        [[setStarMatrix cellAtRow:0 column:l] setImage:nil];
    }

    [setMatrix setNeedsDisplay:YES];
    [setStarMatrix setNeedsDisplay:YES];

    [turnInButton setEnabled:NO];

    if (cardCount > 4 && canTurnInCards == YES)
    {
        [forceTextField setStringValue:@"You must turn in cards."];
    }
    else
    {
        [forceTextField setStringValue:@""];
    }

    [self enableButtons];
    [amassedTextField setIntValue:0];

    setMatrixCount = 0;

    currentCardSetValue = [gameManager armiesForNextCardSet];
    [worthTextField setIntValue:currentCardSetValue];

    [cardSets removeAllObjects];
}

//----------------------------------------------------------------------

- (void) setupPanelForPlayer:(RiskPlayer *)player
{
    SNRelease (playerCards);

    currentPlayerNumber = [player playerNumber];
    playerCards = [[player playerCards] retain];
    [self resetPanel];
}

//----------------------------------------------------------------------

- (void) runCardPanel:(BOOL)canTurnInCardsFlag forPlayer:(RiskPlayer *)player
{
    canTurnInCards = canTurnInCardsFlag;
    [self setupPanelForPlayer:player];

    [cardPanel makeKeyAndOrderFront:self];
    [NSApp runModalForWindow:cardPanel];
    [cardPanel orderOut:self];
}

//----------------------------------------------------------------------

- (void) setGameManager:(RiskGameManager *)newGameManager
{
    SNRelease (gameManager);

    gameManager = [newGameManager retain];
}

@end
