/*
 *  IGUI.CC - IT-HE GUI library prototype 1
 */

#include "igui.hpp"
#include "../ithelib.h"
#include "../core.hpp"
#include "../oscli.h"
#include "menusys.h"

#ifdef __DJGPP__
#define DEBUGIO stdout
#else
#define DEBUGIO stderr
#endif

#ifdef __BEOS__
#include <OS.h>
#endif

#if defined(__linux__) || defined(__DJGPP__)
#include <unistd.h>
#endif


// Defines

// Variables

int ITG_LIGHTGRAY;
int ITG_LIGHTGREEN;
int ITG_DARKGRAY;
int ITG_YELLOW;
int ITG_RED;
int ITG_DARKRED;
int ITG_BLUE;
int ITG_BLACK;
int ITG_WHITE;

static int max_buttons;
static BUTTON *ButtonList;
static KEYBIND KeyList[128];

BITMAP *swapscreen;
char running,dragflag,didkill=0;
int x,y,z;        // Mouse X,Y and buttonlevel (z)

// Functions

void IG_Init(int max_button);
void IG_Term();
static int firstfree();

// Code

// Initialise the library

void IG_Init(int max_button)
    {
    if(max_buttons)
        return;
    InitGfx();
	show_mouse(swapscreen);

    ITG_LIGHTGRAY=makecol(128,128,128);     //0 10000 10000 10000   lgray  4210
    ITG_DARKGRAY=makecol(96,96,96);         //0 01100 01100 01100   dgray  318c
    ITG_YELLOW=makecol(255,255,0);          //0 11111 11111 00000   yellow 7fe0
    ITG_RED=makecol(200,0,0);               //0 11001 00000 00000   red    6400
    ITG_LIGHTGREEN=makecol(0,200,0);        //0 00000 11001 00000   lgreen 0210

    ITG_BLUE=makecol(0,0,200);
    ITG_BLACK=makecol(0,0,0);
    ITG_WHITE=makecol(255,255,255);
    ITG_DARKRED=makecol(160,0,0);

	setcolor(ITG_BLACK);

    max_buttons = max_button;
    ButtonList = (BUTTON *)M_get(sizeof(BUTTON),max_buttons);
    running = 1;

    x = 100;
    y = 300;
    }

// Shut down the library

void IG_Term()
	{
	if(!max_buttons)
		return;

	TermGfx();

	M_free(ButtonList);
	running = 0;
	}

// Create a common-or-garden button

int IG_TextButton(int nx,int ny,char *text,FPTR l,FPTR m,FPTR r)
   {
    int ID;
    ID = firstfree();
    ButtonList[ID].textlen = strlen(text);
    ButtonList[ID].flag |= 1;

    ButtonList[ID].w=(ButtonList[ID].textlen+1)*8;
    ButtonList[ID].h=3*8;

    ButtonList[ID].x=nx;
    ButtonList[ID].y=ny;

    ButtonList[ID].x2=nx+ButtonList[ID].w;
    ButtonList[ID].y2=ny+ButtonList[ID].h;

    ButtonList[ID].state=ST_OUT;
    ButtonList[ID].type=NORMAL;

    ButtonList[ID].left_ptr=l;
    ButtonList[ID].right_ptr=r;
    ButtonList[ID].middle_ptr=m;

	IG_UpdateText(ID,text);
	IG_SetInText(ID,text);

    draw_button(ID);
    return ID;
}

// Create a button with no physical appearance.  Used for tile bars, maps etc

int IG_Region(int nx,int ny,int w,int h,FPTR l,FPTR m,FPTR r)
   {
    int ID;
    ID = firstfree();
    ButtonList[ID].flag |= 1;
    ButtonList[ID].flag |= 2;	// Regions should have repeat

    ButtonList[ID].w=w;
    ButtonList[ID].h=h;
    ButtonList[ID].x=nx;
    ButtonList[ID].y=ny;

    ButtonList[ID].x2=nx+ButtonList[ID].w;
    ButtonList[ID].y2=ny+ButtonList[ID].h;

    ButtonList[ID].state=0;
    ButtonList[ID].type=REGION;

    ButtonList[ID].left_ptr=l;
    ButtonList[ID].right_ptr=r;
    ButtonList[ID].middle_ptr=m;

    draw_button(ID);
    return ID;
}

// Create a button that looks like an input box

int IG_InputButton(int nx,int ny,char *text,FPTR l,FPTR m,FPTR r)
    {
    int ID;
    ID = firstfree();
    ButtonList[ID].textlen = strlen(text);
    ButtonList[ID].flag |= 1;

    ButtonList[ID].w=(ButtonList[ID].textlen+1)*8;
    ButtonList[ID].h=3*8;

    ButtonList[ID].x=nx;
    ButtonList[ID].y=ny;

    ButtonList[ID].x2=nx+ButtonList[ID].w;
    ButtonList[ID].y2=ny+ButtonList[ID].h;

    ButtonList[ID].state=ST_OUT;
    ButtonList[ID].type=SUNK;

    ButtonList[ID].left_ptr=l;
    ButtonList[ID].right_ptr=r;
    ButtonList[ID].middle_ptr=m;

	IG_UpdateText(ID,text);
	IG_SetInText(ID,text);

    draw_button(ID);
    return ID;
}

// Create a toggle button that reads and writes to an INT with the flag

int IG_ToggleButton(int nx,int ny,char *text,FPTR l,FPTR m,FPTR r,int *tog)
    {
    int ID;
    ID = firstfree();
    ButtonList[ID].textlen = strlen(text);
    ButtonList[ID].flag |= 1;

    ButtonList[ID].w=(ButtonList[ID].textlen+1)*8;
    ButtonList[ID].h=3*8;

    ButtonList[ID].x=nx;
    ButtonList[ID].y=ny;

    ButtonList[ID].x2=nx+ButtonList[ID].w;
    ButtonList[ID].y2=ny+ButtonList[ID].h;

    ButtonList[ID].state=0;
    ButtonList[ID].type=TOGGLE;

    ButtonList[ID].left_ptr=l;
    ButtonList[ID].right_ptr=r;
    ButtonList[ID].middle_ptr=m;
    ButtonList[ID].toggle = tog;

	IG_UpdateText(ID,text);
	IG_SetInText(ID,text);

    draw_button(ID);
    return ID;
}

// Create a menu tab

int IG_Tab(int nx,int ny,char *text,FPTR l,FPTR m,FPTR r)
{
int ID;
ID = firstfree();
ButtonList[ID].textlen = strlen(text);
ButtonList[ID].flag |= 1;

ButtonList[ID].w=(ButtonList[ID].textlen+1)*8;
ButtonList[ID].h=3*8;

ButtonList[ID].x=nx;
ButtonList[ID].y=ny;

ButtonList[ID].x2=nx+ButtonList[ID].w;
ButtonList[ID].y2=ny+ButtonList[ID].h;

ButtonList[ID].state=ST_3;
ButtonList[ID].type=RADIOBUTTON;

ButtonList[ID].left_ptr=l;
ButtonList[ID].right_ptr=r;
ButtonList[ID].middle_ptr=m;

IG_UpdateText(ID,text);
IG_SetInText(ID,text);

draw_button(ID);
return ID;
}

// (re)set text displayed when the button is out

void IG_UpdateText(int ID,char *text)
{
if(ID<0)
	return;

if(ButtonList[ID].textlen >= (int)sizeof(ButtonList[ID].text))
	ButtonList[ID].textlen = sizeof(ButtonList[ID].text)-1;

// Safely copy string
strncpy(ButtonList[ID].text,text,ButtonList[ID].textlen);
// Force terminator
ButtonList[ID].text[ButtonList[ID].textlen]=0;

draw_button(ID);
}

// Set text displayed when the button is sunk in

void IG_SetInText(int ID,char *text)
{
if(ID<0)
	return;

if(ButtonList[ID].textlen >= (int)sizeof(ButtonList[ID].text))
	ButtonList[ID].textlen = sizeof(ButtonList[ID].text)-1;

// Safely copy string
strncpy(ButtonList[ID].intext,text,ButtonList[ID].textlen);
// Force terminator
ButtonList[ID].intext[ButtonList[ID].textlen]=0;

draw_button(ID);
}

// Make this button repeat

void IG_SetRepeat(int ID)
{
if(ID<0)
	return;

ButtonList[ID].flag |= 2;
draw_button(ID);
}

// Sink a button in

void IG_SetFocus(int ID)
{
if(ID<0)
	return;

ButtonList[ID].state = ST_IN;
draw_button(ID);
}

// Pop a button out

void IG_ResetFocus(int ID)
{
if(ID<0)
	return;

ButtonList[ID].state = ST_OUT;
draw_button(ID);
}

// Draw a panel

void IG_Panel(int x,int y,int w,int h)
{
DrawScreenBox3D(x,y,x+w,y+h);
}

// Draw a hollow panel

void IG_BlackPanel(int x,int y,int w,int h)
{
DrawScreenBoxHollow(x,y,x+w,y+h);
}

// Kill all buttons and bindings

void IG_KillAll()
{
memset(&ButtonList[0],0,sizeof(BUTTON)*max_buttons);
memset(&KeyList[0],0,sizeof(KEYBIND)*128);
didkill=1;
}

// Add a key to the key binding list

void IG_AddKey(int key,FPTR ptr)
{
int ctr;
for(ctr=0;ctr<128;ctr++)
	if(!KeyList[ctr].key)
		{
		KeyList[ctr].key = key;
		KeyList[ctr].DoKey= ptr;
		return;
		}
}

// Draw some text on the screen

void IG_Text(int nx,int ny,char *text,int colour)
{
int c;
c = getcolor();
setcolor(colour);
DrawScreenText(nx,ny,text);
setcolor(c);
}



/*
 *      Dispatcher loop
 */

void IG_Dispatch()
{
int key_,ctrx,ctr;
static int x1=100,y1=300,z2;

z=0;

x1 = mouse_x-4; y1 = mouse_y-4; z = mouse_b;

x=x1;y=y1;

didkill=0;

if(keypressed() == TRUE)
		key_ = readkey() >> 8;
	else
		key_ = 0;

	if(key_)
		{
		for(ctrx=0;ctrx<128;ctrx++)
			if( key_ == KeyList[ctrx].key)
				if(KeyList[ctrx].DoKey)
					{
					KeyList[ctrx].DoKey();
					z=0;
					break;
					}
		}

	Show();

	if(z&&running)
		{
		for(ctr=0;ctr<max_buttons;ctr++)
			if(x>=ButtonList[ctr].x&&x<=ButtonList[ctr].x2)
				if(y>=ButtonList[ctr].y&&y<=ButtonList[ctr].y2)
					{
					z2=1;
					if(z==1&&ButtonList[ctr].left_ptr==UNUSED)
						z2=0;
					if(z==2&&ButtonList[ctr].right_ptr==UNUSED)
						z2=0;
					if(z==3&&ButtonList[ctr].middle_ptr==UNUSED)
						z2=0;
					if(z2)
						{
						if(ButtonList[ctr].type==TOGGLE)
                        	*ButtonList[ctr].toggle = !(*ButtonList[ctr].toggle);
						else
							ButtonList[ctr].state=ST_IN;
						draw_button(ctr);
						Show();

						if(!(ButtonList[ctr].flag & 2))
							IG_WaitForRelease();

						if(z==1)
							ButtonList[ctr].left_ptr();
						if(z==2)
							ButtonList[ctr].right_ptr();
						if(z==3)
							ButtonList[ctr].middle_ptr();
						if(!didkill)
							{
							switch(ButtonList[ctr].type)
								{
								case NORMAL:
								case UNDEFINED:
								ButtonList[ctr].state=ST_OUT;
								break;
								}
							draw_button(ctr);
							}
						x1 = mouse_x-4; y1 = mouse_y-4; z = mouse_b;
						break; // Only dispatch one event
						}
					}
		Show();
		}
	if(dragflag) dragflag--;
}


// Find the first unused button

int firstfree()
{
int ctr;
for(ctr=0;ctr<max_buttons;ctr++)
	if(!(ButtonList[ctr].flag & 1))
		return ctr;
return -1;
}

// Draw each type of button

void draw_button(int no)
{
if(no<0)
	return;

switch(ButtonList[no].type)
	{
	case NORMAL:
	case RADIOBUTTON:
	if(ButtonList[no].state==ST_OUT)
		{
		setcolor(ITG_BLACK);
		DrawScreenBox3D(ButtonList[no].x,ButtonList[no].y,ButtonList[no].x2,ButtonList[no].y2);
		DrawScreenText(ButtonList[no].x+4,ButtonList[no].y+8,ButtonList[no].text);
		}

	if(ButtonList[no].state==ST_IN)
		{
		setcolor(ITG_BLACK);
		DrawSunkBox3D(ButtonList[no].x,ButtonList[no].y,ButtonList[no].x2,ButtonList[no].y2);
		DrawScreenText(ButtonList[no].x+6,ButtonList[no].y+10,ButtonList[no].intext);
		}

	if(ButtonList[no].state==ST_3)
		{
		setcolor(ITG_BLACK);
		DrawScreenBox3D(ButtonList[no].x,ButtonList[no].y,ButtonList[no].x2,ButtonList[no].y2);
		DrawScreenText(ButtonList[no].x+4,ButtonList[no].y+8,ButtonList[no].text);
		}
	break;

	case TOGGLE:
	DrawScreenBoxHollow(ButtonList[no].x,ButtonList[no].y,ButtonList[no].x2,ButtonList[no].y2);
	setcolor(ITG_WHITE);

	if(!ButtonList[no].toggle)
		ithe_panic("draw_button: Toggle Button has a NULL toggle pointer!",ButtonList[no].text);

	if(*ButtonList[no].toggle)
		DrawScreenText(ButtonList[no].x+4,ButtonList[no].y+8,ButtonList[no].intext);
	else
		DrawScreenText(ButtonList[no].x+4,ButtonList[no].y+8,ButtonList[no].text);
	break;

	case SUNK:
	DrawScreenBoxHollow(ButtonList[no].x,ButtonList[no].y,ButtonList[no].x2,ButtonList[no].y2);

	// Is the button enabled?
	if(ButtonList[no].left_ptr || ButtonList[no].middle_ptr || ButtonList[no].right_ptr)
		setcolor(ITG_WHITE);
	else
		setcolor(ITG_LIGHTGRAY);
	DrawScreenText(ButtonList[no].x+4,ButtonList[no].y+8,ButtonList[no].text);
	break;

	case REGION:
	break;
	}
setcolor(ITG_WHITE);
}


int CMP(const void *a,const void *b)
{
return strcmp(*((char **)a),*((char **)b));
}

void waitabit()
{
rest(50);
}

void IG_WaitForRelease()
{
int x,y,z=1,timeout;
timeout=254;
while(z && timeout>0)
    {
    x = mouse_x-4; y = mouse_y-4; z = mouse_b;
    waitabit();
    timeout--;
    }

if(timeout < 1)
    {
    fprintf(DEBUGIO,"IRE GUI: Timed out waiting for mouse to respond (gui/igui.cpp line %d)\n",__LINE__);
    fprintf(DEBUGIO,"Mouse says %d\n",z);
    }
}
