/*  shop.c: (c) 2002 sibn

    This file is part of GWiz.

    GWiz 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.

    GWiz 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 GWiz; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>
#include "gwiz.h"
#include "text.h"
#include "shop.h"
#include "items.h"
#include "menus.h"
#include "party.h"
#include "joystick.h"
#include "uiloop.h"
#include "equip.h"

extern GwizApp gwiz;
GwizShopWindow gsw; /* You can only have one of these at a time. Guaranteed. */

/* Clear the last values used for the shop window */
void PrepShopWindow (int maxposition)
{
    SDL_Surface *instructions = GwizRenderText ("What\'s your fancy?");
    SDL_Rect idest;
    int listwidth = gwiz.font.width*25 + gwiz.cursor->w;
    int areawidth = listwidth;

    if (instructions->w > listwidth)
	areawidth = instructions->w;
    gsw.maxposition = maxposition; /* FIXME: should detect type */
    gsw.area = NewTextBox (areawidth, gwiz.font.height*12);

    idest.x = gwiz.tbord[0]->w;
    idest.y = gwiz.tbord[0]->h;
    idest.h = gwiz.font.height;
    idest.w = instructions->w;

    SDL_BlitSurface (instructions, NULL, gsw.area, &idest);
    SDL_FreeSurface (instructions);

    gsw.disrect.x = gwiz.canvas->w/2 - gsw.area->w/2;
    gsw.disrect.y = gwiz.canvas->h/2 - gsw.area->h/2;
    gsw.disrect.h = gsw.area->h;
    gsw.disrect.w = gsw.area->w;

    gsw.displace = NewGwizSurface (gsw.area->w, gsw.area->h);
    if (gsw.displace == NULL)
	BailCall ("shop.c: unable to create gsw.displace: ", SDL_GetError());
    gsw.list = NewGwizSurface (gwiz.font.width*25, 
			       gsw.maxposition*gwiz.font.height);
    if (gsw.list == NULL)
	BailCall ("shop.c: unable to create gsw.list: ", SDL_GetError());

    gsw.lrect.x = gwiz.tbord[0]->w + gwiz.cursor->w + 1;
    gsw.lrect.y = gwiz.tbord[0]->h;
    gsw.lrect.h = gwiz.font.height*10;
    gsw.lrect.w = gwiz.font.width*25;

    gsw.prect.x = gsw.lrect.x + gsw.lrect.w - gwiz.font.width*7;
    gsw.prect.y = gsw.lrect.y;
    gsw.prect.h = gsw.lrect.h;
    gsw.prect.w = gwiz.font.width*7;

    gsw.crect.x = gwiz.tbord[0]->w;
    gsw.crect.y = gwiz.tbord[0]->h + gwiz.font.height*2 -
	gwiz.cursor->h/2 + gwiz.font.height/2;
    gsw.crect.h = gwiz.cursor->h;
    gsw.crect.w = gwiz.cursor->w;

    gsw.focusposition = 0;
    gsw.position = 0;
}

void Buy (int which)
{
    switch (which)
	{
	case 0: /* weapon */
	    MakeWeaponList();
	    gsw.gsn = gwiz.shop.wpn;
	    if (gwiz.shop.wpncount == 0)
		{
		    MsgBox ("No weapons in stock");
		    return;
		}
	    PrepShopWindow (gwiz.shop.wpncount);
	    break;
	case 1: /* armor */
	    MakeArmorList();
	    gsw.gsn = gwiz.shop.arm;
	    if (gwiz.shop.armcount == 0)
		{
		    MsgBox ("No armor in stock");
		    return;
		}
	    PrepShopWindow (gwiz.shop.armcount);
	    break;
	case 2: /* shield */
	    MakeShieldList();
	    gsw.gsn = gwiz.shop.shld;
	    if (gwiz.shop.shldcount == 0)
		{
		    MsgBox ("No shields in stock");
		    return;
		}
	    PrepShopWindow (gwiz.shop.shldcount);
	    break;
	case 3: /* helmet */
	    MakeHelmetList();
	    gsw.gsn = gwiz.shop.hlm;
	    if (gwiz.shop.hlmcount == 0)
		{
		    MsgBox ("No helmets in stock");
		    return;
		}
	    PrepShopWindow (gwiz.shop.hlmcount);
	    break;
	case 4: /* gauntlet */
	    MakeGauntletList();
	    gsw.gsn = gwiz.shop.gnt;
	    if (gwiz.shop.gntcount == 0)
		{
		    MsgBox ("No gauntlets in stock");
		    return;
		}
	    PrepShopWindow (gwiz.shop.gntcount);
	    break;
	case 5: /* misc */
	    MakeMiscList();
	    gsw.gsn = gwiz.shop.misc;
	    if (gwiz.shop.misccount == 0)
		{
		    MsgBox ("No misc. items in stock");
		    return;
		}
	    PrepShopWindow (gwiz.shop.misccount);
	    break;
	case 6: /* scroll */
	    MakeScrollList();
	    gsw.gsn = gwiz.shop.scrl;
	    if (gwiz.shop.scrlcount == 0)
		{
		    MsgBox ("No scrolls in stock");
		    return;
		}
	    PrepShopWindow (gwiz.shop.scrlcount);
	    break;
	}
    ShopListLoop();

    SDL_BlitSurface (gsw.displace, NULL, gwiz.canvas, &gsw.disrect);
    SDL_Flip (gwiz.canvas);
    SDL_FreeSurface (gsw.area);
    SDL_FreeSurface (gsw.displace);
    SDL_FreeSurface (gsw.list);
}

void PrepSellWindow (void)
{
    int i;

    gsw.maxposition = -1;

    CompactPawnItems (gsw.pawn);

    for (i = 0; i < 8; i++)
	if (gsw.pawn->item[i].usage != USAGE_NONE)
	    gsw.maxposition++;

    if (gsw.maxposition < 0) /* no items */
	{
	    char *tmp = MakePath (gsw.pawn->name, " has nothing to sell");
	    MsgBox (tmp);
	    Sfree (tmp);
	    return;
	}

    gsw.position = 0;

    gsw.lrect.x = 1 + gwiz.tbord[0]->w + gwiz.cursor->w;
    gsw.lrect.y = 1 + gwiz.tbord[0]->h;
    gsw.lrect.h = gwiz.font.height*8;
    gsw.lrect.w = gwiz.font.width*25;

    gsw.crect.x = gwiz.tbord[0]->w;
    gsw.crect.y = gwiz.tbord[0]->h - gwiz.cursor->h/2 + gwiz.font.height/2;
    gsw.crect.h = gwiz.cursor->h;
    gsw.crect.w = gwiz.cursor->w;

    gsw.area = NewTextBox (gwiz.font.width*25+gwiz.cursor->w, 
			   gwiz.font.height*8);
    gsw.displace = NewGwizSurface (gsw.area->w, gsw.area->h);
    if (gsw.displace == NULL)
	BailCall ("Unable to create gsw.displace for sale list: ",
		  SDL_GetError());
    gsw.disrect.x = CenterHoriz (gwiz.canvas, gsw.displace);
    gsw.disrect.y = CenterVert (gwiz.canvas, gsw.displace);
    gsw.disrect.h = gsw.displace->h;
    gsw.disrect.w = gsw.displace->w;

    SDL_BlitSurface (gwiz.canvas, &gsw.disrect, gsw.displace, NULL);
}

void Sell (int which)
{
    CompactPawnItems (gsw.pawn);
    PrepSellWindow();
    if (gsw.maxposition < 0)
	return;
    RenderItemsForSale();

    SalesLoop();

    SDL_FreeSurface (gsw.area);
    SDL_BlitSurface (gsw.displace, NULL, gwiz.canvas, &gsw.disrect);
    SDL_FreeSurface (gsw.displace);
}

int RequestSale (Inventory *item)
{
    int itemno = item->itemno;

    if (item->usage & USAGE_EQUIPPED)
	{
	    MsgBox ("Cannot sell an item you\'re wearing");
	    return FALSE;
	}
    if (itemno != -1)
	if (gwiz.shopstocks[itemno] != -1)
	    gwiz.shopstocks[itemno]++;
    item->usage = USAGE_NONE;
    item->version = -1;
    gsw.pawn->counter.gp += item->sellfor;
    gsw.maxposition--;
    if (gsw.maxposition < 0)
	{
	    MsgBox ("Nothing more to sell");
	    return (TRUE);
	}
    if (gsw.position > gsw.maxposition)
	gsw.position = gsw.maxposition;
    return (FALSE);
}

void RenderItemsForSale (void)
{
    SDL_Surface *area;
    SDL_Surface *asterisk;
    SDL_Rect dest;
    PlayerPawn *pawn = gsw.pawn;
    int i;
    char price[9];

    dest.x = 0;
    dest.y = 0;
    dest.h = gwiz.font.height;
    dest.w = gwiz.font.width;

    CompactPawnItems (gsw.pawn);

    area = NewGwizSurface (gwiz.font.width*25, gwiz.font.height*8);
    asterisk = GwizRenderText ("*");

    for (i = 0; i < 8; i++)
	if (pawn->item[i].usage != USAGE_NONE)
	    {
		SDL_Surface *name = GwizRenderText (pawn->item[i].name);
		SDL_Surface *profit;

		if ((pawn->item[i].usage & USAGE_EQUIPPED) == USAGE_EQUIPPED)
		    SDL_BlitSurface (asterisk, NULL, area, &dest);
		dest.x += gwiz.font.width;
		dest.w = gwiz.font.width*15;

		SDL_BlitSurface (name, NULL, area, &dest);

		snprintf (price, sizeof(char)*8, "%d", pawn->item[i].sellfor);
		price[9] = '\0';
		profit = GwizRenderText (price);
		dest.x = area->w - profit->w;
		dest.w = profit->w;
		
		SDL_BlitSurface (profit, NULL, area, &dest);

		dest.y += gwiz.font.height;
		dest.x = 0;
		dest.w = gwiz.font.width;

		SDL_FreeSurface (name);
		SDL_FreeSurface (profit);
	    }
    SDL_BlitSurface (area, NULL, gsw.area, &gsw.lrect);

    SDL_FreeSurface (area);
    SDL_FreeSurface (asterisk);
}

void MoveSaleCursor (int goingup)
{
    int yoffset = gwiz.tbord[0]->h - gwiz.cursor->h/2 + gwiz.font.height/2;

    SDL_FillRect (gsw.area, &gsw.crect, 0);
    if (goingup)
	{
	    if (gsw.position == 0)
		gsw.position = gsw.maxposition;
	    else
		gsw.position--;
	} else {
	    if (gsw.position == gsw.maxposition)
		gsw.position = 0;
	    else
		gsw.position++;
	}
    gsw.crect.y = yoffset + gwiz.font.height*gsw.position;
    SDL_BlitSurface (gwiz.cursor, NULL, gsw.area, &gsw.crect);
}

void SalesLoop (void)
{
    int breakout = FALSE;
    SDL_Event event;

    SDL_BlitSurface (gwiz.cursor, NULL, gsw.area, &gsw.crect);
    SDL_BlitSurface (gsw.area, NULL, gwiz.canvas, &gsw.disrect);
    SDL_Flip (gwiz.canvas);

    while (SDL_WaitEvent (&event) != 0)
	{
	    SDL_Event *e = &event;
	    if (EventIsCancel (e))
		breakout = TRUE;
	    if (EventIsUp (e))
		MoveSaleCursor (TRUE);
	    if (EventIsDown (e))
		MoveSaleCursor (FALSE);
	    if (EventIsOk (e))
		breakout = RequestSale (&gsw.pawn->item[gsw.position]);

	    if (breakout)
		break;
	    RenderItemsForSale(); /* in case items are sold, refresh */
	    SDL_BlitSurface (gsw.area, NULL, gwiz.canvas, &gsw.disrect);
	    SDL_Flip (gwiz.canvas);
	}
    SDL_BlitSurface (gsw.displace, NULL, gwiz.canvas, &gsw.disrect);
}

/* create a new surface showing your options */
void RenderShopListView (void)
{
    SDL_Surface *hash = GwizRenderText ("#");
    SDL_Surface *hyphen = GwizRenderText ("-");
    Inventory item;
    SDL_Rect dest;
    SDL_Rect urect;
    int i;

    dest.x = gwiz.font.width;
    dest.y = 0;
    dest.h = gwiz.font.height;
    urect.x = 0;
    urect.y = 0;
    urect.h = gwiz.font.height;
    urect.w = gwiz.font.width;

    for (i = 0; i < gsw.maxposition; i++)
	{
	    SDL_Surface *name;

	    name = GwizRenderText (GetNodeName (gsw.gsn, i));
	    dest.w = name->w;
	    SDL_BlitSurface (name, NULL, gsw.list, &dest);
	    dest.y += gwiz.font.height;

	    SDL_FreeSurface (name);

	    LoadItem (&item, i+1);
	    if ((item.special & CURSED) == CURSED)
		SDL_BlitSurface (hyphen, NULL, gsw.list, &urect);
	    if (!PawnItemCompatible (gsw.pawn->class, item.usage))
		SDL_BlitSurface (hash, NULL, gsw.list, &urect);
	    urect.y += gwiz.font.height;
	}

    dest.y = 0;

    for (i = 0; i < gsw.maxposition; i++)
	{
	    SDL_Surface *priceimg;
	    char *price;

	    price = ItoA (GetNodePrice (gsw.gsn, i), 7);
	    priceimg = GwizRenderText (price);
	    dest.w = priceimg->w;
	    dest.x = gsw.list->w - dest.w;
	    SDL_BlitSurface (priceimg, NULL, gsw.list, &dest);
	    dest.y += gwiz.font.height;

	    SDL_FreeSurface (priceimg);
	    Sfree (price);	    
	}
    SetShopViewCoords();

    SDL_BlitSurface (gsw.list, &gsw.rlist, gsw.area, &gsw.txtrect);
    SDL_BlitSurface (gwiz.cursor, NULL, gsw.area, &gsw.crect);
    SDL_BlitSurface (gsw.area, NULL, gwiz.canvas, &gsw.disrect);
    SDL_Flip (gwiz.canvas);
    SDL_FreeSurface (hash);
    SDL_FreeSurface (hyphen);
}

/* Set the coordinates of the rectangles to blit */
void SetShopViewCoords (void)
{
    gsw.rlist.x = 0;
    gsw.rlist.y = gsw.focusposition*gwiz.font.height;
    gsw.rlist.h = gwiz.font.height*10;
    gsw.rlist.w = gsw.list->w;

    gsw.txtrect.x = gwiz.tbord[0]->w + gwiz.cursor->w;
    gsw.txtrect.y = gwiz.tbord[0]->h + gwiz.font.height*2;
    gsw.txtrect.h = gsw.rlist.h;
    gsw.txtrect.w = gsw.rlist.w;
}

void MoveShopCursor (int goingup)
{
    switch (goingup)
	{
	case TRUE:
	    gsw.position--;
	    if (gsw.position < 0)
		{
		    gsw.position = gsw.maxposition - 1;
		    gsw.focusposition = gsw.maxposition - 10;
		    if (gsw.focusposition < 0)
			gsw.focusposition = 0;
		}
	    if (gsw.position < gsw.focusposition)
		gsw.focusposition = gsw.position;
	    break;
	case FALSE:
	    gsw.position++;
	    if (gsw.position == gsw.maxposition)
		{
		    gsw.position = 0;
		    gsw.focusposition = 0;
		}
	    if (gsw.position == (gsw.focusposition+10))
		gsw.focusposition++;
	    break;
	}
    /* Necessary adjustments for short item lists: */
    RefreshShopCursor();
}

void RefreshShopCursor (void)
{
    int offset = gwiz.tbord[0]->h + gwiz.font.height*2 + gwiz.font.height/2 -
	gwiz.cursor->h/2;
    int pad = gsw.crect.y - offset;

    if (gsw.position - gsw.focusposition < 10)
	pad = gwiz.font.height * (gsw.position - gsw.focusposition);

    SDL_FillRect (gsw.area, &gsw.crect, 0);
    gsw.crect.y = pad + offset;
}

void ShopListLoop (void)
{
    int breakout = FALSE;
    SDL_Event event;
    SDL_Rect winrect;

    winrect.x = gwiz.canvas->w/2 - gsw.area->w/2;
    winrect.y = gwiz.canvas->h/2 - gsw.area->h/2;
    winrect.h = gsw.area->h;
    winrect.w = gsw.area->w;

    RenderShopListView();
    SDL_BlitSurface (gsw.area, NULL, gwiz.canvas, &winrect);
    SDL_Flip (gwiz.canvas);

    while (SDL_WaitEvent (&event) != 0)
	{
	    SDL_Event *e = &event;
	    if (EventIsCancel (e))
		breakout = TRUE;
	    if (EventIsUp (e))
		MoveShopCursor (TRUE);
	    if (EventIsDown (e))
		MoveShopCursor (FALSE);
	    if (EventIsOk (e))
		PurchaseItem ();

	    if (breakout)
		break;
	    RenderShopListView();
	    SDL_BlitSurface (gsw.area, NULL, gwiz.canvas, &winrect);
	    SDL_Flip (gwiz.canvas);

	}
}

void PurchaseItem (void)
{
    PlayerPawn *pawn = gsw.pawn;
    int firstitem;
    int itemprice;

    CompactPawnItems (pawn);
    firstitem = FirstEmptyPawnItem (pawn);
    itemprice = GetNodePrice (gsw.gsn, gsw.position);
    if (firstitem < 0) /* No empty space */
	{
	    MsgBox ("Pack is already full");
	    return;
	}

    if (itemprice > pawn->counter.gp) /* cannot afford this item */
	{
	    MsgBox ("You cannot afford that");
	    return;
	}
    else
	{
	    pawn->counter.gp -= itemprice;
	    SetNodeStock (gsw.gsn, gsw.position, FALSE);
	    MsgBox ("*Thanks*");
	    /* FIXME: Decrement shopstocks */
	}

    LoadItem (&pawn->item[firstitem], GetNodeItem (gsw.gsn, gsw.position));
}


