/*********************/
/*** TileSet Stuph ***/
/*********************/

#include	"stdafx.h"
#include	<Vector3.h>
#include	<gl\gl.h>
#include	<gl\glu.h>
#include	"GLEnabledView.h"
#include	<Vector>

#include	<GFName.hpp>

#include	"Core.h"
#include	"TileSet.h"
#include	"GinTex.h"
#include	"utils.h"

#include	"MapEdit.h"
#include	"MapEditDoc.h"
#include	"MapEditView.h"
#include	"MainFrm.h"
#include	"GUITileBank.h"

/*****************************************************************************/
/*** TileBank ****************************************************************/
/*****************************************************************************/

const float	TileBrowserGap=0.2f;
const float	TileBrowserX0=0-TileBrowserGap/2;
const float	TileBrowserX1=1+TileBrowserGap/2;
const float	TileBrowserY0=0-TileBrowserGap/2;
const float	TileBrowserY1=1+TileBrowserGap/2;

/*****************************************************************************/
CTileBank::CTileBank() : CElemBank(16,16,true,false)
{
		for (int i=0; i<MaxBrush; i++) Brush[i].Delete();
		ActiveBrush=0;
		SelStart=-1;
}

/*****************************************************************************/
CTileBank::~CTileBank()
{
}

/*****************************************************************************/
void	CTileBank::Load(CFile *File,int Version)
{
		if (Version<=4)
		{
			File->Read(&LayerCam,sizeof(Vector3));
			File->Read(&CurrentSet,sizeof(int));
			File->Read(&ActiveBrush,sizeof(int));
			Brush[0].Load(File,Version);
			Brush[1].Load(File,Version);
		}
		else
		{
			File->Read(&LayerCam,sizeof(Vector3));
			File->Read(&ActiveBrush,sizeof(int));
			Brush[0].Load(File,Version);
			Brush[1].Load(File,Version);
		}

		CElemBank::Load(File,Version);
}

/*****************************************************************************/
void	CTileBank::Save(CFile *File)
{
		File->Write(&LayerCam,sizeof(Vector3));
		File->Write(&ActiveBrush,sizeof(int));
		Brush[0].Save(File);
		Brush[1].Save(File);

		CElemBank::Save(File);
}

/*****************************************************************************/
void	CTileBank::DeleteCurrent()
{
int		ListSize=GetSetCount();
// Remap Brushes
		for (int i=0; i<MaxBrush; i++) 
		{
			Brush[i].RemoveSet(CurrentSet);
		}
		for (int Set=CurrentSet; Set<ListSize; Set++)
		{
			for (int i=0; i<MaxBrush; i++) 
			{
				Brush[i].RemapSet(Set,Set);
			}
		}
		SetList.erase(CurrentSet);
		if (CurrentSet) CurrentSet--;
}

/*****************************************************************************/
void	CTileBank::Render(CCore *Core,Vector3 &CamPos,bool Is3d)
{
		if (!GetSetCount()) return;
CElemSet	&ThisSet=SetList[CurrentSet];
int			ListSize=ThisSet.GetCount();
int			BrowserWidth=ThisSet.GetBrowserWidth();
int			TileID=0;
sMapElem	ThisElem;
int			SelFlag;
float		Scale=CamPos.z/(float)BrowserWidth/2.0;

		ThisElem.Flags=0;
		ThisElem.Set=CurrentSet;
		
		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();

		while(TileID!=ListSize)
		{
			CPoint	Pos=GetElemPos(TileID,BrowserWidth);
			float	XPos=(float)Pos.x*(1+TileBrowserGap);
			float	YPos=(float)Pos.y*(1+TileBrowserGap);

			glLoadIdentity();
			glScalef(Scale,Scale,Scale);
			glTranslatef(-CamPos.x+XPos,CamPos.y-YPos,0);

			glColor3f(1,1,1);

			RenderElem(CurrentSet,TileID,0,Is3d);

// Selection
			ThisElem.Tile=TileID;
			SelFlag=0;

			if (Brush[0].DoesContainTile(ThisElem)) SelFlag|=1;
			if (Brush[1].DoesContainTile(ThisElem)) SelFlag|=2;

			if (SelFlag)
			{
				glBegin(GL_QUADS); 
				switch(SelFlag)
				{
					case 1: // L
						glColor4f(1,0,0,0.5);
						BuildGLQuad(TileBrowserX0,TileBrowserX1,TileBrowserY0,TileBrowserY1,0.01f);
						break;
					case 2: // R
						glColor4f(0,0,1,0.5);
						BuildGLQuad(TileBrowserX0,TileBrowserX1,TileBrowserY0,TileBrowserY1,0.01f);
						break;
					case 3: // LR
						glColor4f(1,0,0,0.5);
						BuildGLQuad(TileBrowserX0,0.5,TileBrowserY0,TileBrowserY1,0.01f);
						glColor4f(0,0,1,0.5);
						BuildGLQuad(0.5,TileBrowserX1,TileBrowserY0,TileBrowserY1,0.01f);
						break;
				}
	
				glEnd();
			}

			TileID++;
		}
		glPopMatrix();
	
}

/*****************************************************************************/
void	CTileBank::RenderCursor(CCore *Core,Vector3 &CamPos,bool Is3d)
{
		if (!GetSetCount()) return;
CElemSet	&ThisSet=SetList[CurrentSet];
int			ListSize=ThisSet.GetCount();
int			BrowserWidth=ThisSet.GetBrowserWidth();
CPoint		Start,End;
int			MaxTile=ListSize;
float		Scale=CamPos.z/(float)BrowserWidth/2.0;

		if (CursorPos<-1 || CursorPos>ListSize) return;		
		if (!ListSize) return;


		if (SelStart==-1)
		{
			Start=GetElemPos(CursorPos,BrowserWidth);
			End=Start;
		}
		else
		{

			CPoint	S=IDToPoint(SelStart-1,BrowserWidth);
			CPoint	E=IDToPoint(CursorPos-1,BrowserWidth);
			
			Start=CPoint(	min(S.x,E.x), min(S.y,E.y));
			End=CPoint(		max(S.x,E.x), max(S.y,E.y));
			if (PointToID(End,BrowserWidth)>=MaxTile) return;		// Invalid selection
		}

		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();

		for (int Y=Start.y; Y<=End.y; Y++)
		{
			for (int X=Start.x; X<=End.x; X++)
			{
				float	XPos=(float)X*(1+TileBrowserGap);
				float	YPos=(float)Y*(1+TileBrowserGap);

				glLoadIdentity();
				glScalef(Scale,Scale,Scale);
				glTranslatef(-CamPos.x+XPos,CamPos.y-YPos,0);

	
				glBegin(GL_QUADS); 
				glColor4f(1,1,0,0.5);
				BuildGLQuad(TileBrowserX0,TileBrowserX1,TileBrowserY0,TileBrowserY1,0);
				glEnd();

			}
		}
		glPopMatrix();

}

/*****************************************************************************/
bool	CTileBank::LButtonControl(CCore *Core,UINT nFlags, CPoint &CursorPos,bool DownFlag)
{
		if (nFlags & MK_RBUTTON)
		{
			SelectCancel();
			return(false);
		}
		Select(LBrush,DownFlag);

		return(true);	
}

/*****************************************************************************/
bool	CTileBank::RButtonControl(CCore *Core,UINT nFlags, CPoint &CursorPos,bool DownFlag)
{
		if (nFlags & MK_LBUTTON)
		{
			SelectCancel();
			return(false);
		}

		Select(RBrush,DownFlag);

		return(false);	
}

/*****************************************************************************/
bool	CTileBank::MouseMove(CCore *Core,UINT nFlags, CPoint &CursorPos)
{
	return(false);
}

/*****************************************************************************/
bool	CTileBank::Command(int CmdMsg,CCore *Core,int Param0,int Param1)
{
		switch(CmdMsg)
		{
		case CmdMsg_SubViewLoad:
			LoadNewSet(Core);
			GUIUpdate(Core);
			break;
		case CmdMsg_SubViewDelete:
			DeleteSet(Core);
			GUIUpdate(Core);
			break;
		case CmdMsg_SubViewUpdate:
			ReloadAllSets();
			Core->GetTexCache().Purge();
			GUIUpdate(Core);
			break;
		case CmdMsg_SubViewSet:
			CurrentSet=GUIElemList.m_List.GetCurSel();
			GUIUpdate(Core);
			break;
		case CmdMsg_ActiveBrushLeft:
			ActiveBrush=LBrush;
			break;
		case CmdMsg_ActiveBrushRight:
			ActiveBrush=RBrush;
		default:
			TRACE3("TileBank-Unhandled Command %i (%i,%i)\n",CmdMsg,Param0,Param1);
		}
		return(true);
}

/*****************************************************************************/
/*** Gui *********************************************************************/
/*****************************************************************************/
void	CTileBank::GUIInit(CCore *Core)
{
		Core->GUIAdd(GUIElemList,IDD_ELEMLIST);
		Core->GUIAdd(GUITileBank,IDD_TILEBANK);
}

/*****************************************************************************/
void	CTileBank::GUIKill(CCore *Core)
{
		Core->GUIRemove(GUIElemList,IDD_ELEMLIST);
		Core->GUIRemove(GUITileBank,IDD_TILEBANK);
}

/*****************************************************************************/
void	CTileBank::GUIUpdate(CCore *Core)
{
int			ListSize=GetSetCount();
bool		IsSubView=Core->IsSubView();

			if (GUIElemList.m_List)
			{
				GUIElemList.m_List.ResetContent();
				if (ListSize)
				{
					for (int i=0; i<ListSize; i++)
					{
						GUIElemList.m_List.AddString(GetSetName(i));
					}
					GUIElemList.m_List.SetCurSel(CurrentSet);
				}
				else
				{
					IsSubView=FALSE;
				}
				GUIElemList.m_List.EnableWindow(IsSubView);
			}

}

/*****************************************************************************/
void	CTileBank::GUIChanged(CCore *Core)
{
}

/*****************************************************************************/
/*** Functions ***************************************************************/
/*****************************************************************************/
bool	CTileBank::Select(int BrushID,bool DownFlag)
{
		if (DownFlag && SelStart==-1)
		{
			if (CursorPos<0) return(FALSE);
			SelStart=CursorPos;
			TRACE1("SEL Start %i\n",CursorPos);

			if (CursorPos==0)
			{
				SetBrush(GetBrush(BrushID));
				SelStart=-1;
				TRACE0("Selected Blank\n");

			}
		}
		else
		if (!DownFlag && SelStart!=-1)
		{
			if (CursorPos==-1) return(SelectCancel());
	
			SetBrush(GetBrush(BrushID));

			SelStart=-1;
			TRACE1("END SEL %i\n",CursorPos);
		}

		return(TRUE);
}

/*****************************************************************************/
void	CTileBank::SetBrush(CMap &ThisBrush)
{
int			BW=SetList[CurrentSet].GetBrowserWidth();
CPoint		S=IDToPoint(SelStart-1,BW);
CPoint		E=IDToPoint(CursorPos-1,BW);

int			Width=abs(E.x-S.x)+1;
int			Height=abs(E.y-S.y)+1;

sMapElem	ThisElem;
int			MaxTile=SetList[CurrentSet].GetCount();

//		if (PointToID(End,BW)>=MaxTile) SelectCancel();	// Invalid selection

		ThisElem.Set=CurrentSet;
		ThisElem.Flags=0;
			
		ThisBrush.Delete();
		ThisBrush.SetSize(Width,Height);

		for (int Y=0; Y<Height; Y++)
		{
			for (int X=0; X<Width; X++)
			{
				ThisElem.Tile=SelStart+X+(Y*BW);
				if (!IsValid(CurrentSet,ThisElem.Tile))
				{
					TRACE2("Not valid %i %i\n",CurrentSet,ThisElem.Tile);
					ThisElem.Tile=-1;
				}
				ThisBrush.Set(X,Y,ThisElem,true);
			}
		}
}

/*****************************************************************************/
bool	CTileBank::SelectCancel()
{
		SelStart=-1;
		TRACE0("Select Cancelled\n");
		return(TRUE);
}

/*****************************************************************************/
void	CTileBank::DeleteSet(CCore *Core)
{
		if (GUIElemList.m_List.GetCurSel()==-1) return;

		if (Core->Question("Delete Current Tile Bank\n\nAll used tiles in current set will be set to blank\nAre you sure?"))
			{
			int		SetCount=GetSetCount();
			int		i,ListSize=Core->GetLayerCount();

				for (i=0;i<ListSize;i++)
				{
					CLayerTile	*ThisLayer=(CLayerTile*)Core->GetLayer(i);
					if (ThisLayer->GetType()==LAYER_TYPE_TILE)
					{
					ThisLayer->RemoveSet(CurrentSet);
					}
				}
				DeleteCurrent();

				for (int Set=CurrentSet+1; Set<SetCount; Set++)
				{
		
					for (i=0;i<ListSize;i++)
					{
						CLayerTile	*ThisLayer=(CLayerTile*)Core->GetLayer(i);
						if (ThisLayer->GetType()==LAYER_TYPE_TILE)
						{
						ThisLayer->RemapSet(Set,Set-1);
						}
					}
				}
			}
		CurrentSet--;

		GUIUpdate(Core);
}