/*  party.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 <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "gwiz.h"
#include "playerpawn.h"
#include "uiloop.h"
#include "prefsdat.h"
#include "text.h"
#include "maploader.h"
#include "menus.h"
#include "party.h"
#include "joystick.h"

extern GwizApp gwiz;
extern const SDL_Color fg, bg;

void AddPawnToParty(void)
{
    int i;

    CompactPartyPawns();
    for (i = 0; i < MAXPAWNS; i++)
	{
	    if (gwiz.pawnno[i] < 0)
		{
		    gwiz.pawnno[i] = NewPawnList();
		    if (gwiz.pawnno[i] == -1)
			break;
		    LoadPawn(gwiz.pawnno[i], &gwiz.pawn[i]);
     		}
	}
}

void RemovePawnFromParty(void)
{
    int i = 0;
    while ((i = NewMiniPawnList("Remove who?")) != -1)
	{
	    SavePawn(gwiz.pawn[i],
		     gwiz.pawnno[i]);
	    gwiz.pawnno[i] = -1;
	    gwiz.pawn[i].ali = NEUTRAL;
	}
    /* to keep the party compacted (all empty pawns at the end */
    CompactPartyPawns();
}

void EmptyParty(void)
{
    int i = 0;
    
    for (i = 0; i < 6; i++)
	{
	    if (gwiz.pawnno[i] > -1)
		{
		    SavePawn (gwiz.pawn[i], gwiz.pawnno[i]);
		    /* note the pawn is not flushed; it's save position
		       is simply set to an ignored value */
		    gwiz.pawnno[i] = -1;
		    gwiz.pawn[i].ali = NEUTRAL;
		}
	}
}

int NewMiniPawnList(char *prompt)
{
    GwizMiniPawnList gmpl;
    SDL_Surface *screen;
    SDL_Surface *box;
    SDL_Surface *text;
    SDL_Rect trect;
    SDL_Rect brect;
    int i = 0;

    text = GwizRenderText (prompt);
    box = NewTextBox (text->w, text->h);
    brect.x = gwiz.canvas->w/2 - box->w/2;
    brect.y = gwiz.canvas->h/2 - box->h/2;
    brect.h = box->h;
    brect.w = box->w;
    trect.x = BORDERWIDTH;
    trect.y = BORDERHEIGHT;
    trect.h = text->h;
    trect.w = text->w;
    SDL_BlitSurface (text, NULL, box, &trect);
    SDL_FreeSurface (text);

    gmpl.maxposition = -1;
    gmpl.position = 0;
    gmpl.requiredwidth = gwiz.cursor->w;
    gmpl.cdest.x = 8;
    gmpl.cdest.y = 8 + gwiz.font.height/2 - gwiz.cursor->h/2;
    gmpl.cdest.h = gwiz.cursor->h;
    gmpl.cdest.w = gwiz.cursor->w;
    
    for (i = 0; i < 6; i++)
	if (gwiz.pawnno[i] > -1)
	    gmpl.maxposition++; /* set the maximum positions */
    
    if (gmpl.maxposition == -1)
	return (-1);
    
    screen = SDL_DisplayFormat (gwiz.canvas);
    SDL_BlitSurface (box, NULL, gwiz.canvas, &brect);
    
    LoadMiniPawnListPix (&gmpl);
    
    i = MiniPawnListLoop(&gmpl);
    
    SDL_FreeSurface (gmpl.area);
    SDL_BlitSurface (screen, NULL, gwiz.canvas, NULL);
    SDL_FreeSurface (screen);
    SDL_Flip (gwiz.canvas);
    
    return (i);
}

void MoveMiniPawnListCursor (GwizMiniPawnList *gmpl, int direction)
{
    switch (direction)
	{
	case 0:
	    if (gmpl->position == 0)
		break;
	    gmpl->position--;
	    SDL_FillRect (gmpl->area, &gmpl->cdest, 0);
	    gmpl->cdest.y -= gwiz.font.height;
	    SDL_BlitSurface (gwiz.cursor, NULL, gmpl->area, &gmpl->cdest);
	    break;
	case 1:
	    if (gmpl->position == gmpl->maxposition)
		break;
	    gmpl->position++;
	    SDL_FillRect (gmpl->area, &gmpl->cdest, 0);
	    gmpl->cdest.y += gwiz.font.height;
	    SDL_BlitSurface (gwiz.cursor, NULL, gmpl->area, &gmpl->cdest);
	    break;
	}
}

void LoadMiniPawnListPix (GwizMiniPawnList *gmpl)
{
    SDL_Surface *columns[6];
    SDL_Rect dest;
    
    columns[0] = RenderMiniPawnListNames(gmpl);
    columns[1] = RenderMiniPawnListSexes(gmpl);
    columns[2] = RenderMiniPawnListAlis(gmpl);
    columns[3] = RenderMiniPawnListClasses(gmpl);
    columns[4] = RenderMiniPawnListHps(gmpl);
    columns[5] = RenderMiniPawnListHpMaxes(gmpl);
    gmpl->area = NewTextBox (gmpl->requiredwidth, gwiz.font.height*6);
    
    dest.x = 8 + gwiz.cursor->w;
    dest.y = 8;
    dest.h = gwiz.font.height*6;
    dest.w = columns[0]->w;
    SDL_BlitSurface (columns[0], NULL, gmpl->area, &dest);
    SDL_FreeSurface (columns[0]);
    
    dest.x += columns[0]->w + gwiz.font.width;
    dest.w = columns[1]->w;
    SDL_BlitSurface (columns[1], NULL, gmpl->area, &dest);
    SDL_FreeSurface(columns[1]);
    
    dest.x += columns[1]->w + gwiz.font.width;
    dest.w = columns[2]->w;
    SDL_BlitSurface (columns[2], NULL, gmpl->area, &dest);
    SDL_FreeSurface (columns[2]);
    
    dest.x += columns[2]->w + gwiz.font.width;
    dest.w = columns[3]->w;
    SDL_BlitSurface (columns[3], NULL, gmpl->area, &dest);
    SDL_FreeSurface (columns[3]);

    dest.x += columns[3]->w + gwiz.font.width;
    dest.w = columns[4]->w;
    SDL_BlitSurface (columns[4], NULL, gmpl->area, &dest);
    SDL_FreeSurface (columns[4]);

    dest.x += columns[4]->w + gwiz.font.width;
    dest.w = columns[5]->w;
    SDL_BlitSurface(columns[5], NULL, gmpl->area, &dest);
    SDL_FreeSurface (columns[5]);
}

SDL_Surface *RenderMiniPawnListNames (GwizMiniPawnList *gmpl)
{
    SDL_Surface *names[6];
    SDL_Surface *list;
    SDL_Rect dest;
    char name[16];
    int i = 0;
    int widest = 0;
    
    for (i = 0; i < 6; i++)
	names[i] = NULL;
    
    for (i = 0; i < 6; i++)
	{
	    /* if this is 1, then the requested pawn -is- in the party */
	    if ((CheckPawnUsage (gwiz.pawnno[i]) == 1) &&
		(gwiz.pawnno[i] > -1))
		{
		    snprintf(name, sizeof(char)*16, "%-15s",
			     gwiz.pawn[i].name);
		    names[i] = GwizRenderText(name);
		    if (names[i] == NULL)
			BailCall ("party.c: unable to render name: ",
				  gwiz.pawn[i].name);
		    if (names[i]->w > widest)
			widest = names[i]->w;
		}
	}
    
    gmpl->requiredwidth += widest + gwiz.font.width;
    
    list = NewGwizSurface (widest, gwiz.font.height*6);
    if (list == NULL)
	BailCall ("party.c: unable to create pawn name list: ",
		  SDL_GetError());
    
    dest.x = 0;
    dest.y = 0;
    dest.h = list->h;
    dest.w = widest;
    
    for (i = 0; i < 6; i++)
	{
	    if (gwiz.pawnno[i] > -1)
		{
		    dest.w = names[i]->w;
		    SDL_BlitSurface (names[i], NULL, list, &dest);
		    dest.y += gwiz.font.height;
		    SDL_FreeSurface (names[i]);
		}
	}
    return (list);
}

SDL_Surface *RenderMiniPawnListSexes (GwizMiniPawnList *gmpl)
{
    SDL_Surface *sexes[6];
    SDL_Surface *list = NULL;
    SDL_Rect dest;
    char sex[2];
    int i = 0;
    int widest = 0;
    
    for (i = 0; i < 6; i++)
	{
	    if ((CheckPawnUsage(gwiz.pawnno[i]) == 1) &&
		(gwiz.pawnno[i] > -1))
		{
		    if (gwiz.pawn[i].sex == FEMALE)
			strncpy(sex, "F", 2);
		    else
			strncpy(sex, "M", 2);
		    sexes[i] = GwizRenderText(sex);
		    if (sexes[i] == NULL)
			BailCall("party.c: unable to render sex: ",
				 sex);
		    if (sexes[i]->w > widest)
			widest = sexes[i]->w;
		}
	}
    
    gmpl->requiredwidth += widest + gwiz.font.width;
    
    list = NewGwizSurface (widest, gwiz.font.height*6);
    
    if (list == NULL)
	BailCall ("party.c: unable to create pawn sex list: ",
		  SDL_GetError());
    
    dest.x = 0;
    dest.y = 0;
    dest.h = list->h;
    dest.w = widest;
    
    for (i = 0; i < 6; i++)
	{
	    if (gwiz.pawnno[i] > -1)
		{
		    dest.w = sexes[i]->w;
		    SDL_BlitSurface(sexes[i], NULL, list, &dest);
		    dest.y += gwiz.font.height;
		    SDL_FreeSurface(sexes[i]);
		}
	}
    return (list);
}

SDL_Surface *RenderMiniPawnListAlis (GwizMiniPawnList *gmpl)
{
    SDL_Surface *alis[6];
    SDL_Surface *list = NULL;
    SDL_Rect dest;
    char ali[2] = "G";
    int i = 0;
    int widest = 0;
    
    for (i = 0; i < 6; i++)
	{
	    if ((CheckPawnUsage(gwiz.pawnno[i]) == 1) &&
		(gwiz.pawnno[i] > -1))
		{
		    if (gwiz.pawn[i].ali == NEUTRAL)
			strncpy(ali, "N", 2);
		    else if (gwiz.pawn[i].ali == EVIL)
			strncpy(ali, "E", 2);
		    alis[i] = GwizRenderText(ali);
		    if (alis[i] == NULL)
			BailCall("party.c: unable to render align: ",
				 ali);
		    if (alis[i]->w > widest)
			widest = alis[i]->w;
		}
	}
    
    gmpl->requiredwidth += widest + gwiz.font.width;
    
    list = NewGwizSurface (widest, gwiz.font.height*6);
    
    if (list == NULL)
	BailCall ("party.c: unable to create pawn alignment list: ",
		  SDL_GetError());
    
    dest.x = 0;
    dest.y = 0;
    dest.h = list->h;
    dest.w = widest;
    
    for (i = 0; i < 6; i++)
	{
	    if (gwiz.pawnno[i] > -1)
		{
		    dest.w = alis[i]->w;
		    SDL_BlitSurface(alis[i], NULL, list, &dest);
		    dest.y += gwiz.font.height;
		    SDL_FreeSurface(alis[i]);
		}
	}
    return (list);
}

SDL_Surface *RenderMiniPawnListClasses (GwizMiniPawnList *gmpl)
{
    SDL_Surface *classes[6];
    SDL_Surface *list = NULL;
    SDL_Rect dest;
    char class[4];
    int i = 0;
    int widest = 0;
    
    for (i = 0; i < 6; i++)
	{
	    if ((CheckPawnUsage(gwiz.pawnno[i]) == 1) &&
		(gwiz.pawnno[i] > -1))
		{
		    GetClassAbbr(gwiz.pawn[i].class, class);
		    classes[i] = GwizRenderText(class);
		    if (classes[i] == NULL)
			BailCall("party.c: unable to render class: ",
				 class);
		    if (classes[i]->w > widest)
			widest = classes[i]->w;
		}
	}
    
    gmpl->requiredwidth += widest + gwiz.font.width;
    
    list = NewGwizSurface (widest, gwiz.font.height*6);
    
    if (list == NULL)
	BailCall ("party.c: unable to create pawn class list: ",
		  SDL_GetError());
    
    dest.x = 0;
    dest.y = 0;
    dest.h = list->h;
    dest.w = widest;
    
    for (i = 0; i < 6; i++)
	{
	    if (gwiz.pawnno[i] > -1)
		{
		    dest.w = classes[i]->w;
		    SDL_BlitSurface(classes[i], NULL, list, &dest);
		    dest.y += gwiz.font.height;
		    SDL_FreeSurface(classes[i]);
		}
	}
    return (list);
}

SDL_Surface *RenderMiniPawnListHps (GwizMiniPawnList *gmpl)
{
    SDL_Surface *hps[6];
    SDL_Surface *list = NULL;
    SDL_Rect dest;
    char hp[5];
    int i = 0;
    int widest = 0;
    
    for (i = 0; i < 6; i++)
	{
	    if ((CheckPawnUsage(gwiz.pawnno[i]) == 1) &&
		(gwiz.pawnno[i] > -1))
		{
		    snprintf (hp, sizeof(char)*5, "%-4d", 
			      gwiz.pawn[i].counter.hp);
		    hps[i] = GwizRenderText(hp);
		    if (hps[i] == NULL)
			BailCall("party.c: unable to render HP: ",
				 hp);
		    if (hps[i]->w > widest)
			widest = hps[i]->w;
		}
	}
    
    gmpl->requiredwidth += widest + gwiz.font.height;
    
    list = NewGwizSurface (widest, gwiz.font.height*6);
    
    if (list == NULL)
	BailCall ("party.c: unable to create pawn HP list: ",
		  SDL_GetError());
    
    dest.x = 0;
    dest.y = 0;
    dest.h = list->h;
    dest.w = widest;
    
    for (i = 0; i < 6; i++)
	{
	    if (gwiz.pawnno[i] > -1)
		{
		    dest.w = hps[i]->w;
		    SDL_BlitSurface(hps[i], NULL, list, &dest);
		    dest.y += gwiz.font.height;
		    SDL_FreeSurface(hps[i]);
		}
	}
    return (list);
}

SDL_Surface *RenderMiniPawnListHpMaxes (GwizMiniPawnList *gmpl)
{
    SDL_Surface *hpmaxes[6];
    SDL_Surface *list = NULL;
    SDL_Rect dest;
    char hpmax[5];
    int i = 0;
    int widest = 0;
    
    for (i = 0; i < 6; i++)
	{
	    if ((CheckPawnUsage(gwiz.pawnno[i]) == 1) &&
		(gwiz.pawnno[i] > -1))
		{
		    snprintf(hpmax, sizeof(char)*5, "%-4d",
			     gwiz.pawn[i].counter.hp_max);
		    hpmaxes[i] = GwizRenderText(hpmax);
		    if (hpmaxes[i] == NULL)
			BailCall("party.c: unable to render HP Max: ",
				 hpmax);
		    if (hpmaxes[i]->w > widest)
			widest = hpmaxes[i]->w;
		}
	}
    
    gmpl->requiredwidth += widest + gwiz.font.width;
    
    list = NewGwizSurface (widest, gwiz.font.height*6);
    
    if (list == NULL)
	BailCall ("party.c: unable to create pawn HP Max list: ",
		  SDL_GetError());
    
    dest.x = 0;
    dest.y = 0;
    dest.h = list->h;
    dest.w = widest;
    
    for (i = 0; i < 6; i++)
	{
	    if (gwiz.pawnno[i] > -1)
		{
		    dest.w = hpmaxes[i]->w;
		    SDL_BlitSurface(hpmaxes[i], NULL, list, &dest);
		    dest.y += gwiz.font.height;
		    SDL_FreeSurface(hpmaxes[i]);
		}
	}
    return (list);
}

int MiniPawnListLoop(GwizMiniPawnList *gmpl)
{
    SDL_Rect dest;
    SDL_Event event;
    
    dest.x = gwiz.canvas->w/2 - gmpl->area->w/2;
    dest.y = gwiz.canvas->h - gmpl->area->h;
    dest.h = gmpl->area->h;
    dest.w = gmpl->area->w;
    
    SDL_BlitSurface (gwiz.cursor, NULL, gmpl->area, &gmpl->cdest);
    
    while ((SDL_WaitEvent(&event)) != 0)
	{
	    SDL_Event *e = &event;
	    if (EventIsOk (e))
		return (GetLiteralPartyPawnNo(gmpl->position));
	    if (EventIsCancel (e))
		return (-1);
	    if (EventIsUp (e))
		MoveMiniPawnListCursor (gmpl, 0);
	    if (EventIsDown (e))
		MoveMiniPawnListCursor (gmpl, 1);

	    SDL_BlitSurface (gmpl->area, NULL, gwiz.canvas, &dest);
	    SDL_Flip (gwiz.canvas);
	}
    return (-1); /* control should never reach this point. */
}

int GetLiteralPartyPawnNo (int which)
{
    int i = 0;
    int pawnno = -1;
    for (i = 0; i < 6; i++)
	{
	    if (gwiz.pawnno[i] > -1)
		pawnno++;
	    if (pawnno == which)
		break;
	}
    return (i);
}

int CountPartyMembers(void)
{
    int i = 0;
    int pawns = -1;
    for (i = 0; i < 6; i++)
	if (gwiz.pawnno[i] > -1)
	    pawns++;
    return (pawns);
}

/* keeps the party compact so "adding" members does not constitute "inserting"
   them. */
void CompactPartyPawns(void)
{
    int i = 0;
    int j = 0;
    
    for (i = 0; i < 6; i++)
	{
	    if (gwiz.pawnno[i] < 0) /* this pawn doesn't exist */
		{
		    for (j = i; j < 6; j++)
			if (gwiz.pawnno[j] > -1)
			    {
				
				memmove(&gwiz.pawn[i], &gwiz.pawn[j],
					sizeof(PlayerPawn));
				gwiz.pawnno[i] = gwiz.pawnno[j];
				gwiz.pawnno[j] = -1;
				InitNewPlayer (&gwiz.pawn[j]);
				break;
			    }
		}
	}
}

void ReorderParty (void)
{
    PlayerPawn old[6];
    PlayerPawn pawn[6];
    int oldpnos[6];
    int pawnno[6];
    int whichpawn;
    const int members = CountPartyMembers() + 1;
    int i;

    CompactPartyPawns();
    for (i = 0; i < members; i++)
	{
	    oldpnos[i] = gwiz.pawnno[i];
	    memmove (&old[i], &gwiz.pawn[i], sizeof(PlayerPawn));
	}
    for (i = 0; i < members; i++)
	{
	    CompactPartyPawns();
	    whichpawn = NewMiniPawnList ("Who should be next?");
	    if (whichpawn < 0)
		{
		    for (i = 0; i < members; i++)
			{
			    gwiz.pawnno[i] = oldpnos[i];
			    memmove(&gwiz.pawn[i], &old[i], sizeof(PlayerPawn));
			}
		    return;
		}

	    memmove (&pawn[i], &gwiz.pawn[whichpawn], sizeof(PlayerPawn));
	    pawnno[i] = gwiz.pawnno[whichpawn];
	    gwiz.pawnno[whichpawn] = -1;
	}
    for (i = 0; i < members; i++)
	{
	    gwiz.pawnno[i] = pawnno[i];
	    memmove (&gwiz.pawn[i], &pawn[i], sizeof(PlayerPawn));
	}
}
