//Copyright Paul Reiche, Fred Ford. 1992-2002

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "../colors.h"
#include "../controls.h"
#include "../gamestr.h"
#include "../shipcont.h"
#include "../setup.h"
#include "../sounds.h"
#include "../util.h"
#include "../sis.h"
		// for ClearSISRect(), DrawStatusMessage()
#include "planets.h"
#include "libs/graphics/drawable.h"
		// for GetFrameBounds()


#define ELEMENT_ORG_Y      35
#define FREE_ORG_Y         (ELEMENT_ORG_Y + (NUM_ELEMENT_CATEGORIES \
							* ELEMENT_SPACING_Y))
#define BIO_ORG_Y          119
#define ELEMENT_SPACING_Y  9

#define ELEMENT_COL_0      7
#define ELEMENT_COL_1      32
#define ELEMENT_COL_2      58

#define ELEMENT_SEL_ORG_X  (ELEMENT_COL_0 + 7 + 5)
#define ELEMENT_SEL_WIDTH  (ELEMENT_COL_2 - ELEMENT_SEL_ORG_X + 1)

#define TEXT_BASELINE      6


void
ShowRemainingCapacity (void)
{
	RECT r;
	TEXT t;
	CONTEXT OldContext;
	UNICODE buf[40];

	OldContext = SetContext (StatusContext);
	SetContextFont (TinyFont);

	r.corner.x = 40;
	r.corner.y = FREE_ORG_Y;

	snprintf (buf, sizeof buf, "%u",
			GetStorageBayCapacity () - GLOBAL_SIS (TotalElementMass));
	t.baseline.x = ELEMENT_COL_2 + 1;
	t.baseline.y = r.corner.y + TEXT_BASELINE;
	t.align = ALIGN_RIGHT;
	t.pStr = buf;
	t.CharCount = (COUNT)~0;

	r.extent.width = t.baseline.x - r.corner.x + 1;
	r.extent.height = ELEMENT_SPACING_Y - 2;

	BatchGraphics ();
	// erase previous free amount
	SetContextForeGroundColor (CARGO_BACK_COLOR);
	DrawFilledRectangle (&r);
	// print the new free amount
	SetContextForeGroundColor (CARGO_WORTH_COLOR);
	font_DrawText (&t);
	UnbatchGraphics ();
	
	SetContext (OldContext);
}

static void
DrawElementAmount (COUNT element, bool selected)
{
	RECT r;
	TEXT t;
	UNICODE buf[40];

	r.corner.x = ELEMENT_SEL_ORG_X;
	r.extent.width = ELEMENT_SEL_WIDTH;
	r.extent.height = ELEMENT_SPACING_Y - 2;

	if (element == NUM_ELEMENT_CATEGORIES)
		r.corner.y = BIO_ORG_Y;
	else
		r.corner.y = ELEMENT_ORG_Y + (element * ELEMENT_SPACING_Y);
	
	// draw line background
	SetContextForeGroundColor (selected ?
			CARGO_SELECTED_BACK_COLOR : CARGO_BACK_COLOR);
	DrawFilledRectangle (&r);

	t.align = ALIGN_RIGHT;
	t.pStr = buf;
	t.baseline.y = r.corner.y + TEXT_BASELINE;

	if (element == NUM_ELEMENT_CATEGORIES)
	{	// Bio
		snprintf (buf, sizeof buf, "%u", GLOBAL_SIS (TotalBioMass));
	}
	else
	{	// Element
		// print element's worth
		SetContextForeGroundColor (selected ?
				CARGO_SELECTED_WORTH_COLOR : CARGO_WORTH_COLOR);
		t.baseline.x = ELEMENT_COL_1;
		snprintf (buf, sizeof buf, "%u", GLOBAL (ElementWorth[element]));
		t.CharCount = (COUNT)~0;
		font_DrawText (&t);
		
		snprintf (buf, sizeof buf, "%u", GLOBAL_SIS (ElementAmounts[element]));
	}

	// print the element/bio amount
	SetContextForeGroundColor (selected ?
			CARGO_SELECTED_AMOUNT_COLOR : CARGO_AMOUNT_COLOR);
	t.baseline.x = ELEMENT_COL_2;
	t.CharCount = (COUNT)~0;
	font_DrawText (&t);
}

static void
DrawCargoDisplay (void)
{
	STAMP s;
	TEXT t;
	RECT r;
	COORD cy;
	COUNT i;

	r.corner.x = 2;
	r.extent.width = FIELD_WIDTH + 1;
	r.corner.y = 20;
	// XXX: Shouldn't the height be 1 less? This draws the bottom border
	//   1 pixel too low. Or if not, why do we need another box anyway?
	r.extent.height = 129 - r.corner.y;
	DrawStarConBox (&r, 1,
			SHADOWBOX_MEDIUM_COLOR, SHADOWBOX_DARK_COLOR,
			TRUE, CARGO_BACK_COLOR);

	// draw the "CARGO" title
	SetContextFont (StarConFont);
	t.baseline.x = (STATUS_WIDTH >> 1) - 1;
	t.baseline.y = 27;
	t.align = ALIGN_CENTER;
	t.pStr = GAME_STRING (CARGO_STRING_BASE);
	t.CharCount = (COUNT)~0;
	SetContextForeGroundColor (CARGO_SELECTED_AMOUNT_COLOR);
	font_DrawText (&t);

	SetContextFont (TinyFont);

	s.frame = SetAbsFrameIndex (MiscDataFrame,
			(NUM_SCANDOT_TRANSITIONS * 2) + 3);
	r.corner.x = ELEMENT_COL_0;
	r.extent = GetFrameBounds (s.frame);
	s.origin.x = r.corner.x + (r.extent.width >> 1);

	cy = ELEMENT_ORG_Y;

	// print element column headings
	t.align = ALIGN_RIGHT;
	t.baseline.y = cy - 1;
	t.CharCount = (COUNT)~0;

	SetContextForeGroundColor (CARGO_WORTH_COLOR);
	t.baseline.x = ELEMENT_COL_1;
	t.pStr = "$";
	font_DrawText (&t);

	t.baseline.x = ELEMENT_COL_2;
	t.pStr = "#";
	font_DrawText (&t);

	// draw element icons and print amounts
	for (i = 0; i < NUM_ELEMENT_CATEGORIES; ++i, cy += ELEMENT_SPACING_Y)
	{
		// erase background under an element icon
		SetContextForeGroundColor (BLACK_COLOR);
		r.corner.y = cy;
		DrawFilledRectangle (&r);

		// draw an element icon
		s.origin.y = r.corner.y + (r.extent.height >> 1);
		DrawStamp (&s);
		s.frame = SetRelFrameIndex (s.frame, 5);

		DrawElementAmount (i, false);
	}

	// erase background under the Bio icon
	SetContextForeGroundColor (BLACK_COLOR);
	r.corner.y = BIO_ORG_Y;
	DrawFilledRectangle (&r);

	// draw the Bio icon
	s.origin.y = r.corner.y + (r.extent.height >> 1);
	s.frame = SetAbsFrameIndex (s.frame, 68);
	DrawStamp (&s);

	// print the Bio amount
	DrawElementAmount (NUM_ELEMENT_CATEGORIES, false);

	// draw the line over the Bio amount
	r.corner.x = 4;
	r.corner.y = BIO_ORG_Y - 2;
	r.extent.width = FIELD_WIDTH - 3;
	r.extent.height = 1;
	SetContextForeGroundColor (CARGO_SELECTED_BACK_COLOR);
	DrawFilledRectangle (&r);

	// print "Free"
	t.baseline.x = 5;
	t.baseline.y = FREE_ORG_Y + TEXT_BASELINE;
	t.align = ALIGN_LEFT;
	t.pStr = GAME_STRING (CARGO_STRING_BASE + 1);
	t.CharCount = (COUNT)~0;
	font_DrawText (&t);

	ShowRemainingCapacity ();
}

void
DrawCargoStrings (BYTE OldElement, BYTE NewElement)
{
	CONTEXT OldContext;

	LockMutex (GraphicsLock);

	OldContext = SetContext (StatusContext);
	SetContextFont (TinyFont);

	BatchGraphics ();

	if (OldElement > NUM_ELEMENT_CATEGORIES)
	{	// Asked for the initial display
		DrawCargoDisplay ();

		// do not draw unselected again this time
		OldElement = NewElement;
	}

	if (OldElement != NewElement)
	{	// unselect the previous element
		DrawElementAmount (OldElement, false);
	}

	if (NewElement != (BYTE)~0)
	{	// select the new element
		DrawElementAmount (NewElement, true);
	}

	UnbatchGraphics ();
	SetContext (OldContext);
	UnlockMutex (GraphicsLock);
}

static void
DrawElementDescription (COUNT element)
{
	LockMutex (GraphicsLock);
	DrawStatusMessage (GAME_STRING (element + (CARGO_STRING_BASE + 2)));
	UnlockMutex (GraphicsLock);
}

static BOOLEAN
DoDiscardCargo (MENU_STATE *pMS)
{
	BYTE NewState;
	BOOLEAN select, cancel, back, forward;
	
	select = PulsedInputState.menu[KEY_MENU_SELECT];
	cancel = PulsedInputState.menu[KEY_MENU_CANCEL];
	back = PulsedInputState.menu[KEY_MENU_UP] || PulsedInputState.menu[KEY_MENU_LEFT];
	forward = PulsedInputState.menu[KEY_MENU_DOWN] || PulsedInputState.menu[KEY_MENU_RIGHT];

	if (GLOBAL (CurrentActivity) & CHECK_ABORT)
		return FALSE;

	if (cancel)
	{
		return FALSE;
	}
	else if (select)
	{
		if (GLOBAL_SIS (ElementAmounts[pMS->CurState]))
		{
			--GLOBAL_SIS (ElementAmounts[pMS->CurState]);
			DrawCargoStrings (pMS->CurState, pMS->CurState);

			LockMutex (GraphicsLock);
			--GLOBAL_SIS (TotalElementMass);
			ShowRemainingCapacity ();
			UnlockMutex (GraphicsLock);
		}
		else
		{	// no element left in cargo hold
			PlayMenuSound (MENU_SOUND_FAILURE);
		}
	}
	else
	{
		NewState = pMS->CurState;
		if (back)
		{
			if (NewState == 0)
				NewState += NUM_ELEMENT_CATEGORIES;
			--NewState;
		}
		else if (forward)
		{
			++NewState;
			if (NewState == NUM_ELEMENT_CATEGORIES)
				NewState = 0;
		}

		if (NewState != pMS->CurState)
		{
			DrawCargoStrings (pMS->CurState, NewState);
			DrawElementDescription (NewState);
			pMS->CurState = NewState;
		}
	}

	SleepThread (ONE_SECOND / 30);

	return (TRUE);
}

void
CargoMenu (void)
{
	MENU_STATE MenuState;

	memset (&MenuState, 0, sizeof MenuState);

	// draw the initial cargo display
	DrawCargoStrings ((BYTE)~0, MenuState.CurState);
	DrawElementDescription (MenuState.CurState);

	SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT);

	MenuState.InputFunc = DoDiscardCargo;
	DoInput (&MenuState, TRUE);

	// erase the cargo display
	LockMutex (GraphicsLock);
	ClearSISRect (DRAW_SIS_DISPLAY);
	UnlockMutex (GraphicsLock);
}

