/*
* This code is released under the GNU General Public License.  See COPYING for 
* details.  Copyright 2003 John Spray: spray_john@users.sourceforge.net
*/


#include <SDL_opengl.h>
#include <SDL.h>
#include <SDL_ttf.h>
#include <string.h>
#include <ctype.h>

#include "Menu.h"
#include "MenuItem.h"
#include "Config.h"
extern Config GLOB_conf;




Menu::Menu(char* itemlabels[],menufunc itemfunctions[],void* itemtargets[],Visual* newvisual)
{
	int i=0;
	itemcount=0;
	while(itemlabels[i]!=NULL){
		itemcount++;
		i++;
	}

	item = new MenuItem[itemcount];

  i=0;
	while(itemlabels[i]!=NULL){
		strcpy(item[i].label,itemlabels[i]);
		item[i].function=itemfunctions[i];
		item[i].parent=this;
		item[i].target=itemtargets[i];
		i++;
	}
	i=0;
	while(item[i].function==MENU_NOSELECT) i++;
	selection=i;
	item[i].selected=1;

	visual=newvisual;
	Arrange(visual->game->screen->w,visual->game->screen->h);
	solidbackground=1;
	done=0;

	font=newvisual->menufont;

	SDL_GetMouseState(&mouse.x,&mouse.y);
}

Menu::~Menu()
{
	delete[] item;
}

void Menu::Arrange(int width,int height)
{
	int itemwidth=width/2;
	int itemheight=height/12;
	int i;

	viewportx=width;
	viewporty=height;

	for(i=0;i<itemcount;i++){
		item[i].SetPos(width/2-itemwidth/2,
			itemwidth,
			height/2-itemcount*itemheight/2 + i*itemheight,
			itemheight);
		item[i].selected=0;
	}
	item[selection].selected=1;
}

void Menu::Up()
{
	if(selection==0)
		return;
	if(item[selection-1].function!=MENU_NOSELECT){
		item[selection].selected=0;
		item[--selection].selected=1;
	}
	else{
		int i=selection-1;
		while(item[i].function==MENU_NOSELECT && i>0)
			i--;
		if(item[i].function==MENU_NOSELECT)
			return;
		else{
			item[selection].selected=0;
			item[selection=i].selected=1;
		}
	}
}

void Menu::Down()
{
	if(selection+1==itemcount)
		return;

	if(item[selection+1].function!=MENU_NOSELECT){
		item[selection].selected=0;
		item[++selection].selected=1;
	}
	else{
		int i=selection+1;
		while(item[i].function==MENU_NOSELECT && i<itemcount-1)
			i++;
		if(item[i].function==MENU_NOSELECT)
			return;
		else{
			item[selection].selected=0;
			item[selection=i].selected=1;
		}
	}
}

void Menu::HandleClick(int x,int y)
{
	int i;
	for(i=0;i<itemcount;i++){
		if(item[i].CheckClick(x,y)){
			if(item[i].function==MENU_NOSELECT) return;

			item[selection].selected=0;
			selection=i;
			item[i].selected=1;
			if(item[selection].function==MENU_BOOL)
				*(int*)item[i].target=!*(int*)item[i].target;
			if(item[selection].function==MENU_QUIT ||
				item[selection].function==MENU_QUITFULL ||
				item[selection].function==MENU_SUB1 ||
				item[selection].function==MENU_SUB2 ||
				item[selection].function==MENU_SUB3 ||
				item[selection].function==MENU_SUB4 ||
				item[selection].function==MENU_SUB5 ||
				item[selection].function==MENU_SUB6 ||
				item[selection].function==MENU_CONTINUE)
				done=1;
			return;
		}
	}
}

void Menu::HandleMotion(int x,int y)
{
	//ignore the first mousemotion event - when the menu is first
	//invoked, to have the initial selection be 0, not whatever
	//is under the mouse (the centre of the screen when running -fs)
	static int firsttime=1;
	if(firsttime){
		firsttime=0;
		return;
	}

	mouse.x=x;
	mouse.y=y;
	for(int i=0;i<itemcount;i++){
		if(item[i].CheckClick(x,y) && item[i].function!=MENU_NOSELECT){
			item[selection].selected=0;
			selection=i;
			item[i].selected=1;
			return;
		}
	}
}

void Menu::Draw()
{
	int i;

	glDisable(GL_DEPTH_TEST);
	glDisable(GL_LIGHTING);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glViewport(0, 0, viewportx, viewporty);
	gluOrtho2D(0,visual->game->screen->w,0,visual->game->screen->h);
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

	if(solidbackground){
		visual->UseTexture("menuback.png");
		glColor4f(1.0f,1.0f,1.0f,1.0f);
		glBegin(GL_QUADS);
			glTexCoord2f(0.0f,0.0f);
			glVertex2f(0.0f,0.0f);
			glTexCoord2f(1.0f,0.0f);
			glVertex2f(viewportx,0.0f);
			glTexCoord2f(1.0f,1.0f);
			glVertex2f(viewportx,viewporty);
			glTexCoord2f(0.0f,1.0f);
			glVertex2f(0,viewporty);
		glEnd();
	}
	else{
		glDisable(GL_TEXTURE_2D);
		glColor4f(0.0f,0.0f,0.0f,0.5f);
		glBegin(GL_QUADS);
			glTexCoord2f(0.0f,0.0f);
			glVertex2f(0.0f,0.0f);
			glTexCoord2f(1.0f,0.0f);
			glVertex2f(viewportx,0.0f);
			glTexCoord2f(1.0f,1.0f);
			glVertex2f(viewportx,viewporty);
			glTexCoord2f(0.0f,1.0f);
			glVertex2f(0,viewporty);
		glEnd();
		glEnable(GL_TEXTURE_2D);
	}

	for(i=0;i<itemcount;i++){
		item[i].Draw(viewportx,viewporty);
	}

	glTranslatef(mouse.x,viewporty-mouse.y,0);
	glColor4f(1.0f,1.0f,1.0f,1.0f);
	visual->UseTexture("menucursor.png");
	
	glBegin(GL_QUADS);
			glTexCoord2f(0.0f,1.0f);
			glVertex3f(-16.0f,16.0f,0.0f);
			glTexCoord2f(0.0f,0.0f);
			glVertex3f(-16.0f,-16.0f,0.0f);
			glTexCoord2f(1.0f,0.0f);
			glVertex3f(16.0f,-16.0f,0.0f);
			glTexCoord2f(1.0f,1.0f);
			glVertex3f(16.0f,16.0f,0.0f);
	glEnd();
	
	glTranslatef(-mouse.x,-(viewporty-mouse.y),0);

	glPopMatrix();

	glEnable(GL_DEPTH_TEST);
	glEnable(GL_LIGHTING);

	int errornumber;
	while((errornumber=glGetError())!=GL_NO_ERROR){
		printf("Camera::Draw: OpenGL error: %s\n",visual->HandleGlError(errornumber));
	}

}

void Menu::HandleEvents()
{
	char single[2];
	single[1]=0;
	int dopush=0;
	SDL_Event tobepushed;
	int nothing;

	SDL_Event event;
	while(SDL_PollEvent(&event)){
		switch(event.type){
			case SDL_KEYDOWN:
				if(event.key.keysym.sym==SDLK_UP)
					Up();
				else if(event.key.keysym.sym==SDLK_DOWN)
					Down();
				else if(event.key.keysym.sym==SDLK_LEFT)
					item[selection].Left();
				else if(event.key.keysym.sym==SDLK_RIGHT)
					item[selection].Right();
				else if(( 
				(SDLK_a<=event.key.keysym.sym && event.key.keysym.sym<=SDLK_z) ||
				(SDLK_0<=event.key.keysym.sym && event.key.keysym.sym<=SDLK_9) ||
        event.key.keysym.sym==SDLK_SPACE || event.key.keysym.sym==SDLK_MINUS) &&
				item[selection].function==MENU_STRING &&
				strlen((char*)item[selection].target)<15
				){
					single[0]=(char)event.key.keysym.sym;
					if(SDLK_a<=event.key.keysym.sym && event.key.keysym.sym<=SDLK_z){
									if(event.key.keysym.mod&KMOD_SHIFT)
													single[0]-=32;
					}
					strcat((char*)item[selection].target,single);
				}
				else if(event.key.keysym.sym==SDLK_BACKSPACE && item[selection].function==MENU_STRING && strlen((char*)item[selection].target)>0)
					((char*)item[selection].target)[strlen((char*)item[selection].target)-1]=0;
				else if(event.key.keysym.sym==SDLK_RETURN){
					/*if(item[selection].function==MENU_QUIT||item[selection].function==MENU_QUITFULL||
					item[selection].function==MENU_CONTINUE || item[selection].function==MENU_SUB1||
					item[selection].function==MENU_SUB2 || item[selection].function==MENU_SUB3||
					item[selection].function==MENU_SUB4 || item[selection].function==MENU_SUB5||
					item[selection].function==MENU_SUB6){
						done=1;
					}*/
					if(item[selection].function==MENU_BOOL)
						*(int*)item[selection].target=!*(int*)item[selection].target;
					else
						done=1;
				}
				else{
					tobepushed=event;
					dopush=1;
				}
				break;
			case SDL_KEYUP:
				if(event.key.keysym.sym==SDLK_UP)
					nothing=1;
				else if(event.key.keysym.sym==SDLK_DOWN)
					nothing=1;
				else if(event.key.keysym.sym==SDLK_LEFT)
					nothing=1;
				else if(event.key.keysym.sym==SDLK_RIGHT)
					nothing=1;
				else if(( (SDLK_a<=event.key.keysym.sym && event.key.keysym.sym<=SDLK_z) ||
				(SDLK_0<=event.key.keysym.sym && event.key.keysym.sym<=SDLK_9) ||
        event.key.keysym.sym==SDLK_SPACE ||
				event.key.keysym.sym==SDLK_MINUS) &&
				item[selection].function==MENU_STRING)
					nothing=1;
				else if(event.key.keysym.sym==SDLK_BACKSPACE && item[selection].function==MENU_STRING)
					nothing=1;
				else if(event.key.keysym.sym==SDLK_RETURN){
				}
				else{
					tobepushed=event;
					dopush=1;
				}
				break;
			case SDL_MOUSEBUTTONDOWN:
				HandleClick(event.button.x,event.button.y);
				break;
			case SDL_MOUSEMOTION:
				HandleMotion(event.motion.x,event.motion.y);
				break;
			case SDL_QUIT:
				selection=itemcount-1; //yuck
				done=1;
				break;
			case SDL_VIDEOEXPOSE:
				break;
			default:
				break;
		}
	}

	//causing a mess
	/*if(dopush){//this out here because if we push events inside the while loop, it's endless
		SDL_PushEvent(&tobepushed);
	}*/
}

menufunc Menu::Happen()
{
	if(!font) return MENU_QUITFULL;

	while(!done){
		glClear(GL_COLOR_BUFFER_BIT);
		if(!solidbackground){
			LListItem<Camera>* item;
			item=visual->cameralist.head;
			while(item){
				//printf("Drawing camera of viewporty=%d\n",item->data.viewporty);
				item->data.Draw();
				item=item->next;
			}
		}
		Draw();
		HandleEvents();
		SDL_GL_SwapBuffers();
	}
	return item[selection].function;
}

void Menu::Select(int newselection)
{
	item[selection].selected=0;
	item[selection=newselection].selected=1;
}
