// MainFrm.cpp : implementation of the CMainFrame class
//

#include "precompiled.h"
#include "stdafx.h"

#define _IGNORE_WGL_H_
#include "ogl.h"
#include "lib/res/graphics/tex.h"
#include "lib/res/mem.h"
#include "lib/res/file/vfs.h"
#undef _IGNORE_WGL_H_

#include "MathUtil.h"
#include "ScEd.h"
#include "ScEdView.h"
#include "MiniMap.h"
#include "MapReader.h"
#include "MapWriter.h"

#include "UserConfig.h"

#include "Unit.h"
#include "UnitManager.h"
#include "ObjectManager.h"
#include "TextureManager.h"
#include "ModelDef.h"
#include "UIGlobals.h"
#include "MainFrm.h"
#include "OptionsPropSheet.h"
#include "LightSettingsDlg.h"
#include "MapSizeDlg.h"
#include "EditorData.h"
#include "ToolManager.h"
#include "CommandManager.h"

#include "AlterLightEnvCommand.h"

#include "LightEnv.h"
#include "Game.h"

#include "PaintTextureTool.h"
#include "PaintObjectTool.h"
#include "RaiseElevationTool.h"
#include "BrushShapeEditorTool.h"

#include "SelectObjectTool.h"
#include "simulation/Entity.h"

#include "Loader.h"

extern CLightEnv g_LightEnv;

bool g_TerrainModified = false;
	// HACK: normally defined in gui/MiniMap.cpp, but ScEd doesn't compile the GUI code

/////////////////////////////////////////////////////////////////////////////
// CMainFrame


IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	//{{AFX_MSG_MAP(CMainFrame)
	ON_WM_CREATE()
	ON_COMMAND(ID_TERRAIN_LOAD, OnTerrainLoad)
	ON_COMMAND(ID_LIGHTING_SETTINGS, OnLightingSettings)
	ON_COMMAND(ID_VIEW_SCREENSHOT, OnViewScreenshot)
	ON_COMMAND(IDR_TEXTURE_TOOLS, OnTextureTools)
	ON_COMMAND(ID_TOOLS_OPTIONS, OnToolsOptions)
	ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
	ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
	ON_COMMAND(ID_EDIT_REDO, OnEditRedo)
	ON_UPDATE_COMMAND_UI(ID_EDIT_REDO, OnUpdateEditRedo)
	ON_COMMAND(IDR_ELEVATION_TOOLS, OnElevationTools)
	ON_COMMAND(IDR_RESIZE_MAP, OnResizeMap)
	ON_COMMAND(ID_VIEW_TERRAIN_GRID, OnViewTerrainGrid)
	ON_UPDATE_COMMAND_UI(ID_VIEW_TERRAIN_GRID, OnUpdateViewTerrainGrid)
	ON_COMMAND(ID_VIEW_TERRAIN_SOLID, OnViewTerrainSolid)
	ON_UPDATE_COMMAND_UI(ID_VIEW_TERRAIN_SOLID, OnUpdateViewTerrainSolid)
	ON_COMMAND(ID_VIEW_TERRAIN_WIREFRAME, OnViewTerrainWireframe)
	ON_UPDATE_COMMAND_UI(ID_VIEW_TERRAIN_WIREFRAME, OnUpdateViewTerrainWireframe)
	ON_COMMAND(ID_VIEW_MODEL_GRID, OnViewModelGrid)
	ON_UPDATE_COMMAND_UI(ID_VIEW_MODEL_GRID, OnUpdateViewModelGrid)
	ON_COMMAND(ID_VIEW_MODEL_SOLID, OnViewModelSolid)
	ON_UPDATE_COMMAND_UI(ID_VIEW_MODEL_SOLID, OnUpdateViewModelSolid)
	ON_COMMAND(ID_VIEW_MODEL_WIREFRAME, OnViewModelWireframe)
	ON_UPDATE_COMMAND_UI(ID_VIEW_MODEL_WIREFRAME, OnUpdateViewModelWireframe)
	ON_COMMAND(ID_FILE_SAVEMAP, OnFileSaveMap)
	ON_COMMAND(ID_FILE_LOADMAP, OnFileLoadMap)
	ON_COMMAND(ID_VIEW_RENDERSTATS, OnViewRenderStats)
	ON_UPDATE_COMMAND_UI(ID_VIEW_RENDERSTATS, OnUpdateViewRenderStats)
	ON_MESSAGE(WM_MOUSEWHEEL,OnMouseWheel)
	ON_COMMAND(ID_TEST_GO, OnTestGo)
	ON_UPDATE_COMMAND_UI(ID_TEST_GO, OnUpdateTestGo)
	ON_COMMAND(ID_TEST_STOP, OnTestStop)
	ON_UPDATE_COMMAND_UI(ID_TEST_STOP, OnUpdateTestStop)
	ON_COMMAND(IDR_UNIT_TOOLS, OnUnitTools)
	ON_COMMAND(ID_RANDOM_MAP, OnRandomMap)
	//}}AFX_MSG_MAP
	ON_COMMAND(ID_PLAYER_PLAYER0, OnEntityPlayer0)
	ON_COMMAND(ID_PLAYER_PLAYER1, OnEntityPlayer1)
	ON_COMMAND(ID_PLAYER_PLAYER2, OnEntityPlayer2)
	ON_COMMAND(ID_PLAYER_PLAYER3, OnEntityPlayer3)
	ON_COMMAND(ID_PLAYER_PLAYER4, OnEntityPlayer4)
	ON_COMMAND(ID_PLAYER_PLAYER5, OnEntityPlayer5)
	ON_COMMAND(ID_PLAYER_PLAYER6, OnEntityPlayer6)
	ON_COMMAND(ID_PLAYER_PLAYER7, OnEntityPlayer7)
	ON_COMMAND(ID_PLAYER_PLAYER8, OnEntityPlayer8)
END_MESSAGE_MAP()

static UINT indicators[] =
{
	ID_SEPARATOR,           // status line indicator
	ID_INDICATOR_CAPS,
	ID_INDICATOR_NUM,
	ID_INDICATOR_SCRL,
};


/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction

CMainFrame::CMainFrame()
{
	// TODO: add member initialization code here
	
}

CMainFrame::~CMainFrame()
{
}

void CMainFrame::PostNcDestroy()
{
	CFrameWnd::PostNcDestroy();
}

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	
	if (!m_wndDlgBar.Create(this, IDR_MAINFRAME, 
		CBRS_ALIGN_TOP, AFX_IDW_DIALOGBAR))
	{
		TRACE0("Failed to create dialogbar\n");
		return -1;		// fail to create
	}
	m_wndDlgBar.SetWindowText("Toolbar");

	// create status bar
	if (!m_wndStatusBar.Create(this) ||
		!m_wndStatusBar.SetIndicators(indicators,
		  sizeof(indicators)/sizeof(UINT)))
	{
		TRACE0("Failed to create status bar\n");
		return -1;      // fail to create
	}


	// create texture tools bar
	if (!m_wndTexToolsBar.Create(this, IDD_DIALOGBAR_TEXTURETOOLS, 
		CBRS_ALIGN_LEFT | CBRS_GRIPPER, AFX_IDW_DIALOGBAR))
	{
		TRACE0("Failed to create dialogbar\n");
		return -1;		// fail to create
	}
	m_wndTexToolsBar.SetWindowText("TexTools");

	// create elevation tools bar
	if (!m_wndElevToolsBar.Create(this, IDD_DIALOGBAR_ELEVATIONTOOLS, 
		CBRS_ALIGN_LEFT | CBRS_GRIPPER, AFX_IDW_DIALOGBAR))
	{
		TRACE0("Failed to create dialogbar\n");
		return -1;		// fail to create
	}
	m_wndElevToolsBar.SetWindowText("ElevTools");

	// create unit tools bar
	if (!m_wndUnitToolsBar.Create(this, IDD_DIALOGBAR_UNITTOOLS, 
		CBRS_ALIGN_LEFT | CBRS_GRIPPER, AFX_IDW_DIALOGBAR))
	{
		TRACE0("Failed to create dialogbar\n");
		return -1;		// fail to create
	}
	m_wndUnitToolsBar.SetWindowText("UnitTools");

	// create unit properties bar
	if (!m_wndUnitPropsBar.Create(this, IDD_DIALOGBAR_UNITPROPERTIES, 
		CBRS_ALIGN_LEFT | CBRS_GRIPPER, AFX_IDW_DIALOGBAR))
	{
		TRACE0("Failed to create dialogbar\n");
		return -1;		// fail to create
	}
	m_wndUnitPropsBar.SetWindowText("UnitProperties");

	// create brush shape editor bar
	if (!m_wndBrushShapeEditorBar.Create(this, IDD_DIALOGBAR_BRUSHSHAPEEDITOR, 
		CBRS_ALIGN_LEFT | CBRS_GRIPPER, AFX_IDW_DIALOGBAR))
	{
		TRACE0("Failed to create dialogbar\n");
		return -1;		// fail to create
	}
	m_wndTexToolsBar.SetWindowText("BrushEditor");

	// enable docking on main frame
	EnableDocking(CBRS_ALIGN_TOP | CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT | CBRS_ALIGN_BOTTOM);
	
/*
	// initially dock everything
	m_wndTexToolsBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT);	
	DockControlBar(&m_wndTexToolsBar);
	m_wndElevToolsBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT);	
	DockControlBar(&m_wndElevToolsBar);
	m_wndUnitToolsBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT);	
	DockControlBar(&m_wndUnitToolsBar);
	m_wndUnitPropsBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT);	
	DockControlBar(&m_wndUnitPropsBar);
*/
	// and start up with all tools deselected
	DeselectTools();

	return 0;
}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	if( !CFrameWnd::PreCreateWindow(cs) )
		return FALSE;
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics

#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
	CFrameWnd::AssertValid();
}

void CMainFrame::Dump(CDumpContext& dc) const
{
	CFrameWnd::Dump(dc);
}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers


float rnd1()
{
	return float(rand())/float(RAND_MAX);
}


void CMainFrame::OnTerrainLoad() 
{
	const char* filter="Targa Files|*.tga|RAW files|*.raw||";
	CFileDialog dlg(TRUE,"tga",0,OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,filter,0);
	dlg.m_ofn.lpstrInitialDir=g_UserCfg.GetOptionString(CFG_TERRAINLOADDIR);

	if (dlg.DoModal()==IDOK) {
		const char* filename=dlg.m_ofn.lpstrFile;

		CStr dir(filename);
		dir=dir.Left(dlg.m_ofn.nFileOffset-1);
		g_UserCfg.SetOptionString(CFG_TERRAINLOADDIR,(const char*) dir);

		g_EditorData.LoadTerrain(filename);
	}
}



void CMainFrame::OnLightingSettings() 
{
	CLightSettingsDlg dlg;
	RGBColorToColorRef(g_LightEnv.m_SunColor,dlg.m_SunColor.m_Color);
	RGBColorToColorRef(g_LightEnv.m_TerrainAmbientColor,dlg.m_TerrainAmbientColor.m_Color);
	RGBColorToColorRef(g_LightEnv.m_UnitsAmbientColor,dlg.m_UnitsAmbientColor.m_Color);
	dlg.m_Elevation=int(RADTODEG(g_LightEnv.m_Elevation)+0.5f);
	dlg.m_Direction=int(RADTODEG(g_LightEnv.m_Rotation)+0.5f);

	if (dlg.DoModal()==IDOK) {
		// have we previously applied a lightenv?
		if (dlg.m_PreviousPreview) {
			// yes - undo it
			g_CmdMan.Undo();
		} 

		// build a lighting environment from the parameters
		CLightEnv env;
		env.m_Elevation=DEGTORAD(dlg.m_ElevationButton.m_Elevation);
		env.m_Rotation=DEGTORAD(dlg.m_DirectionButton.m_Direction);
		ColorRefToRGBColor(dlg.m_SunColor.m_Color,env.m_SunColor);
		ColorRefToRGBColor(dlg.m_TerrainAmbientColor.m_Color,env.m_TerrainAmbientColor);
		ColorRefToRGBColor(dlg.m_TerrainAmbientColor.m_Color,env.m_UnitsAmbientColor);

		// create and execute an AlterLightEnv command
		CAlterLightEnvCommand* cmd=new CAlterLightEnvCommand(env);
		g_CmdMan.Execute(cmd);
	} else {
		if (dlg.m_PreviousPreview) {
			// undo the change
			g_CmdMan.Undo();
		}
	}

	AfxGetMainWnd()->Invalidate();
	AfxGetMainWnd()->UpdateWindow();
}

void CMainFrame::OnViewScreenshot() 
{
	CScEdView* view=(CScEdView*) GetActiveView();
	view->OnScreenShot();
}



void CMainFrame::OnTextureTools() 
{
	g_EditorData.SetMode(CEditorData::SCENARIO_EDIT);

	// swizzle around control bar visibility
	DisableCtrlBars();
	ShowControlBar(&m_wndTexToolsBar,TRUE,FALSE);
	((CButton*) m_wndDlgBar.GetDlgItem(IDC_BUTTON_TEXTURETOOLS))->SetState(TRUE);

	// set active tool
	g_ToolMan.SetActiveTool(CPaintTextureTool::GetTool());
}

void CMainFrame::OnElevationTools() 
{
	g_EditorData.SetMode(CEditorData::SCENARIO_EDIT);

	// swizzle around control bar visibility
	DisableCtrlBars();
	ShowControlBar(&m_wndElevToolsBar,TRUE,FALSE);
	((CButton*) m_wndDlgBar.GetDlgItem(IDC_BUTTON_ELEVATIONTOOLS))->SetState(TRUE);
	
	// notify window being shown so controls for correct mode (raise/smooth) are drawn,
	// and correct tool is setup
	m_wndElevToolsBar.OnShow();
}

void CMainFrame::OnUnitTools() 
{
	g_EditorData.SetMode(CEditorData::SCENARIO_EDIT);

	// swizzle around control bar visibility
	DisableCtrlBars();
	ShowControlBar(&m_wndUnitToolsBar,TRUE,FALSE);
	((CButton*) m_wndDlgBar.GetDlgItem(IDC_BUTTON_MODELTOOLS))->SetState(TRUE);

	// set modeactive tool
	if (m_wndUnitToolsBar.m_Mode==CUnitToolsDlgBar::SELECT_MODE) {
		m_wndUnitToolsBar.SetSelectMode();
	} else {
		m_wndUnitToolsBar.SetAddUnitMode();
	}

	// ensure we're in the right editing mode
	g_EditorData.SetMode(CEditorData::SCENARIO_EDIT);
}

void CMainFrame::DisableCtrlBars()
{
	ShowControlBar(&m_wndTexToolsBar,FALSE,FALSE);
	ShowControlBar(&m_wndElevToolsBar,FALSE,FALSE);
	ShowControlBar(&m_wndUnitToolsBar,FALSE,FALSE);
	ShowControlBar(&m_wndUnitPropsBar,FALSE,FALSE);
	ShowControlBar(&m_wndBrushShapeEditorBar,FALSE,FALSE);

	// switch off corresponding short cut buttons
	DisableToolbarButtons();
}

void CMainFrame::DisableToolbarButtons()
{
	((CButton*) m_wndDlgBar.GetDlgItem(IDC_BUTTON_SELECT))->SetState(FALSE);
	((CButton*) m_wndDlgBar.GetDlgItem(IDC_BUTTON_TEXTURETOOLS))->SetState(FALSE);
	((CButton*) m_wndDlgBar.GetDlgItem(IDC_BUTTON_ELEVATIONTOOLS))->SetState(FALSE);
	((CButton*) m_wndDlgBar.GetDlgItem(IDC_BUTTON_MODELTOOLS))->SetState(FALSE);
}

void CMainFrame::DeselectTools()
{
	// switch off all control bars
	DisableCtrlBars();
	((CButton*) m_wndDlgBar.GetDlgItem(IDC_BUTTON_SELECT))->SetState(TRUE);
	
	// deselect active tool
	g_ToolMan.SetActiveTool(0);

	// ensure we're in the right editing mode
	g_EditorData.SetMode(CEditorData::SCENARIO_EDIT);
}

void CMainFrame::OnObjectProperties(CObjectEntry* obj) 
{
	// swizzle around control bar visibility
	DisableCtrlBars();
	ShowControlBar(&m_wndUnitPropsBar,TRUE,FALSE);

	m_wndUnitPropsBar.SetObject(obj);

	// set active tool
	g_ToolMan.SetActiveTool(0);

	// ensure we're in the right editing mode
	g_EditorData.SetMode(CEditorData::UNIT_EDIT);
}

void CMainFrame::OnToolsOptions() 
{
	COptionsPropSheet dlg("Options",this,0);
	dlg.m_NavigatePage.m_ScrollSpeed=g_UserCfg.GetOptionInt(CFG_SCROLLSPEED);
	
	dlg.m_ShadowsPage.m_EnableShadows=g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS) ? TRUE : FALSE;

	COLORREF c;
	RGBAColorToColorRef(g_Renderer.GetOptionColor(CRenderer::OPT_SHADOWCOLOR),c);
	dlg.m_ShadowsPage.m_ShadowColor.m_Color=c;

	if (dlg.DoModal()==IDOK) {
		g_UserCfg.SetOptionInt(CFG_SCROLLSPEED,dlg.m_NavigatePage.m_ScrollSpeed);
		g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS,dlg.m_ShadowsPage.m_EnableShadows ? true : false);
		
		RGBAColor c;
		ColorRefToRGBAColor(dlg.m_ShadowsPage.m_ShadowColor.m_Color,0xff,c);
		g_Renderer.SetOptionColor(CRenderer::OPT_SHADOWCOLOR,c);
	}
}

void CMainFrame::OnEditUndo() 
{
	g_CmdMan.Undo();
}

void CMainFrame::OnUpdateEditUndo(CCmdUI* pCmdUI) 
{
	const char* cmdName=g_CmdMan.GetUndoName();
	if (!cmdName) {
		const char* undoText="&Undo";
		pCmdUI->SetText(undoText);
		pCmdUI->Enable(FALSE);
	} else {
		const char* undoText="&Undo                                    Ctrl+Z";
		char buf[64];
		strcpy(buf,undoText);
		size_t len=strlen(cmdName);
		if (len>32) len=32;
		buf[6]='\"';
		strncpy(buf+7,cmdName,len);
		buf[6+len+1]='\"';
		pCmdUI->SetText(buf);
		pCmdUI->Enable(TRUE);
	}
}

void CMainFrame::OnEditRedo() 
{
	g_CmdMan.Redo();
}

void CMainFrame::OnUpdateEditRedo(CCmdUI* pCmdUI) 
{
	const char* cmdName=g_CmdMan.GetRedoName();
	if (!cmdName) {
		const char* redoText="&Redo";
		pCmdUI->SetText(redoText);
		pCmdUI->Enable(FALSE);
	} else {
		const char* redoText="&Redo                                    Ctrl+Y";
		char buf[64];
		strcpy(buf,redoText);
		size_t len=strlen(cmdName);
		if (len>32) len=32;
		buf[6]='\"';
		strncpy(buf+7,cmdName,len);
		buf[6+len+1]='\"';
		pCmdUI->SetText(buf);
		pCmdUI->Enable(TRUE);
	}
}



void CMainFrame::OnResizeMap() 
{
	CMapSizeDlg dlg;
	if (dlg.DoModal()==IDOK) {
		// resize terrain to selected size
		g_Game->GetWorld()->GetTerrain()->Resize(dlg.m_MapSize);	

		// reinitialise minimap to cope with terrain of different size
		g_MiniMap.Initialise();
	}
}

void CMainFrame::OnViewModelGrid() 
{
	g_Renderer.SetModelRenderMode(EDGED_FACES);
}

void CMainFrame::OnUpdateViewModelGrid(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(g_Renderer.GetModelRenderMode()==EDGED_FACES);
}

void CMainFrame::OnViewModelSolid() 
{
	g_Renderer.SetModelRenderMode(SOLID);
}

void CMainFrame::OnUpdateViewModelSolid(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(g_Renderer.GetModelRenderMode()==SOLID);	
}

void CMainFrame::OnViewModelWireframe() 
{
	g_Renderer.SetModelRenderMode(WIREFRAME);
}

void CMainFrame::OnUpdateViewModelWireframe(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(g_Renderer.GetModelRenderMode()==WIREFRAME);
}

void CMainFrame::OnViewTerrainGrid() 
{
	g_Renderer.SetTerrainRenderMode(EDGED_FACES);
}

void CMainFrame::OnUpdateViewTerrainGrid(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(g_Renderer.GetTerrainRenderMode()==EDGED_FACES);
}

void CMainFrame::OnViewTerrainSolid() 
{
	g_Renderer.SetTerrainRenderMode(SOLID);
}

void CMainFrame::OnUpdateViewTerrainSolid(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(g_Renderer.GetTerrainRenderMode()==SOLID);	
}

void CMainFrame::OnViewTerrainWireframe() 
{
	g_Renderer.SetTerrainRenderMode(WIREFRAME);
}

void CMainFrame::OnUpdateViewTerrainWireframe(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(g_Renderer.GetTerrainRenderMode()==WIREFRAME);
}

void CMainFrame::OnFileSaveMap() 
{
	const char* filter="PMP Files|*.pmp||";
	CFileDialog savedlg(FALSE,"pmp","Untitled.pmp",OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR,filter,0);
	savedlg.m_ofn.lpstrInitialDir=g_UserCfg.GetOptionString(CFG_MAPSAVEDIR);
	if (savedlg.DoModal()==IDOK) {
		const char* savename=savedlg.m_ofn.lpstrFile;

		CStr dir(savename);
		dir=dir.Left(savedlg.m_ofn.nFileOffset-1);
		g_UserCfg.SetOptionString(CFG_MAPSAVEDIR,(const char*) dir);

		CMapWriter writer;
		try {
			writer.SaveMap(savename, g_Game->GetWorld()->GetTerrain(), &g_LightEnv, &g_UnitMan);

			CStr filetitle=savedlg.m_ofn.lpstrFileTitle;
			int index=filetitle.ReverseFind(CStr("."));
			CStr doctitle=(index==-1) ? filetitle : filetitle.GetSubstring(0,index);
			g_EditorData.SetScenarioName((const char*) doctitle);
			SetTitle();
		} catch (CFilePacker::CFileOpenError) {
			char buf[256];
			sprintf(buf,"Failed to open \"%s\" for writing",savename);
			MessageBox(buf,"Error",MB_OK);
		} catch (CFilePacker::CFileWriteError) {
			char buf[256];
			sprintf(buf,"Error trying to write to \"%s\"",savename);
			MessageBox(buf,"Error",MB_OK);
#ifdef NDEBUG
		} catch (...) {
			char buf[256];
			sprintf(buf,"Error saving file \"%s\"",savename);
			MessageBox(buf,"Error",MB_OK);
#endif
		}
	}
}

void CMainFrame::OnFileLoadMap() 
{
	g_EditorData.SetMode(CEditorData::SCENARIO_EDIT);

	const char* filter="PMP Files|*.pmp||";
	CFileDialog loaddlg(TRUE,"pmp",0,OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,filter,0);
	loaddlg.m_ofn.lpstrInitialDir=g_UserCfg.GetOptionString(CFG_MAPLOADDIR);

	if (loaddlg.DoModal()==IDOK) {
		const char* loadname=loaddlg.m_ofn.lpstrFile;

		CStr dir(loadname);
		dir=dir.Left(loaddlg.m_ofn.nFileOffset-1);
		g_UserCfg.SetOptionString(CFG_MAPLOADDIR,(const char*) dir);
		
		try {

			LDR_BeginRegistering();
			CMapReader* reader = new CMapReader(); // freed by the progressive loader
			reader->LoadMap(loadname, g_Game->GetWorld()->GetTerrain(), &g_UnitMan, &g_LightEnv);
			LDR_EndRegistering();
			LDR_NonprogressiveLoad();

			CStr filetitle=loaddlg.m_ofn.lpstrFileTitle;
			int index=filetitle.ReverseFind(CStr("."));
			CStr doctitle=(index==-1) ? filetitle : filetitle.GetSubstring(0,index);
			g_EditorData.SetScenarioName((const char*) doctitle);
			SetTitle();

			// reinitialise minimap 
			g_MiniMap.Initialise();
			// render everything force asset load
			g_EditorData.RenderNoCull();

			// start everything idling
			const std::vector<CUnit*>& units=g_UnitMan.GetUnits();
			for (uint i=0;i<units.size();++i) {
				units[i]->SetRandomAnimation("idle");
			}
		} catch (CFileUnpacker::CFileOpenError) {
			char buf[256];
			sprintf(buf,"Failed to open \"%s\" for reading",loadname);
			MessageBox(buf,"Error",MB_OK);
		} catch (CFileUnpacker::CFileReadError) {
			char buf[256];
			sprintf(buf,"Error trying to read from \"%s\"",loadname);
			MessageBox(buf,"Error",MB_OK);
		} catch (CFileUnpacker::CFileEOFError) {
			char buf[256];
			sprintf(buf,"Premature end of file error reading from \"%s\"",loadname);
			MessageBox(buf,"Error",MB_OK);
		} catch (CFileUnpacker::CFileVersionError) {
			char buf[256];
			sprintf(buf,"Error reading from \"%s\" - version mismatch",loadname);
			MessageBox(buf,"Error",MB_OK);
		} catch (CFileUnpacker::CFileTypeError) {
			char buf[256];
			sprintf(buf,"Error reading \"%s\" - doesn't seem to a PMP file",loadname);
			MessageBox(buf,"Error",MB_OK);
#ifdef NDEBUG
		} catch (...) {
			char buf[256];
			sprintf(buf,"Error loading file \"%s\"",loadname);
			MessageBox(buf,"Error",MB_OK);
#endif
		}
	}	
}

void CMainFrame::SetTitle()
{
	// set document title
	if (GetActiveView()) {
		GetActiveView()->GetDocument()->SetTitle(g_EditorData.GetScenarioName());
	}
}

void CMainFrame::OnViewRenderStats() 
{
	CInfoBox& infobox=g_EditorData.GetInfoBox();
	infobox.SetVisible(!infobox.GetVisible());	
}

void CMainFrame::OnUpdateViewRenderStats(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(g_EditorData.GetInfoBox().GetVisible()==true);
}

void CMainFrame::OnToolsBrushShapeEditor() 
{
	DeselectTools();
	ShowControlBar(&m_wndBrushShapeEditorBar,TRUE,FALSE);

	// set active tool
	g_ToolMan.SetActiveTool(CBrushShapeEditorTool::GetTool());

	// ensure we're in the right editing mode
	g_EditorData.SetMode(CEditorData::SCENARIO_EDIT);
}

LRESULT CMainFrame::OnMouseWheel(WPARAM wParam,LPARAM lParam) 
{
	// Windows sucks: why the main frame is getting mouse wheel messages
	// when mouse move messages are still going to the view is beyond
	// my comprehension.  Just duplicate the work CScEdView does.
	int xPos = LOWORD(lParam); 
	int yPos = HIWORD(lParam); 
	SHORT fwKeys = LOWORD(wParam);
	SHORT zDelta = HIWORD(wParam);

	g_NaviCam.OnMouseWheelScroll(0,xPos,yPos,float(zDelta)/120.0f);

	return 0;
}

void CMainFrame::OnTestGo() 
{
	g_EditorData.SetMode(CEditorData::TEST_MODE);	
}

void CMainFrame::OnUpdateTestGo(CCmdUI* pCmdUI) 
{
	if (g_EditorData.GetMode()==CEditorData::TEST_MODE || g_EditorData.GetMode()!=CEditorData::SCENARIO_EDIT)
		pCmdUI->Enable(FALSE);
	else
		pCmdUI->Enable(TRUE);
}

void CMainFrame::OnTestStop() 
{
	g_EditorData.SetMode(CEditorData::SCENARIO_EDIT);
}

void CMainFrame::OnUpdateTestStop(CCmdUI* pCmdUI) 
{
	if (g_EditorData.GetMode()==CEditorData::TEST_MODE)
		pCmdUI->Enable(TRUE);
	else
		pCmdUI->Enable(FALSE);
}

static float getExactGroundLevel( float x, float y )
{
	// TODO MT: If OK with Rich, move to terrain core. Once this works, that is.

	x /= 4.0f;
	y /= 4.0f;

	int xi = (int)floor( x );
	int yi = (int)floor( y );
	float xf = x - (float)xi;
	float yf = y - (float)yi;

	CTerrain* terrain = g_Game->GetWorld()->GetTerrain();

	u16* heightmap = terrain->GetHeightMap();
	unsigned long mapsize = terrain->GetVerticesPerSide();

	float h00 = heightmap[yi*mapsize + xi];
	float h01 = heightmap[yi*mapsize + xi + mapsize];
	float h10 = heightmap[yi*mapsize + xi + 1];
	float h11 = heightmap[yi*mapsize + xi + mapsize + 1];

	/*
	if( xf < ( 1.0f - yf ) )
	{
		return( HEIGHT_SCALE * ( ( 1 - xf - yf ) * h00 + xf * h10 + yf * h01 ) );
	}
	else
		return( HEIGHT_SCALE * ( ( xf + yf - 1 ) * h11 + ( 1 - xf ) * h01 + ( 1 - yf ) * h10 ) );
	*/

	/*
	if( xf > yf ) 
	{
		return( HEIGHT_SCALE * ( ( 1 - xf ) * h00 + ( xf - yf ) * h10 + yf * h11 ) );
	}
	else
		return( HEIGHT_SCALE * ( ( 1 - yf ) * h00 + ( yf - xf ) * h01 + xf * h11 ) );
	*/

	return( HEIGHT_SCALE * ( ( 1 - yf ) * ( ( 1 - xf ) * h00 + xf * h10 ) + yf * ( ( 1 - xf ) * h01 + xf * h11 ) ) );

}

static CObjectEntry* GetRandomActorTemplate()
{
	return NULL;
//	if (g_ObjMan.m_ObjectTypes.size()==0) return 0;
//
//	CObjectEntry* found=0;
//	int checkloop=250;
//	do {
//		u32 type=rand()%(u32)g_ObjMan.m_ObjectTypes.size();
//		u32 actorsoftype=(u32)g_ObjMan.m_ObjectTypes[type].m_Objects.size();
//		if (actorsoftype>0) {
//			found=g_ObjMan.m_ObjectTypes[type].m_Objects[rand()%actorsoftype];
//			if (found && found->m_Model && found->m_Model->GetModelDef()->GetNumBones()>0) {
//			} else {
//				found=0;
//			}
//		}
//	} while (--checkloop && !found);
//	
//	return found;
}

void CMainFrame::OnRandomMap() 
{
	const u32 count=5000;	
	const u32 unitsPerDir=u32(sqrt(float(count)));	
	
	u32 i,j;
	u32 vsize=g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide()-1;

	for (i=0;i<unitsPerDir;i++) {
		for (j=0;j<unitsPerDir;j++) {
//			float x=CELL_SIZE*vsize*float(i+1)/float(unitsPerDir+1);
//			float z=CELL_SIZE*vsize*float(j+1)/float(unitsPerDir+1);
			float dx=float(rand())/float(RAND_MAX);
			float x=CELL_SIZE*vsize*dx;
			float dz=float(rand())/float(RAND_MAX);
			float z=CELL_SIZE*vsize*dz;
			float y=getExactGroundLevel(x,z);
			CObjectEntry* actortemplate=GetRandomActorTemplate();
			if (actortemplate && actortemplate->m_Model) {
				CUnit* unit=new CUnit(actortemplate,actortemplate->m_Model->Clone());
				g_UnitMan.AddUnit(unit);
				
				CMatrix3D trans;
				trans.SetIdentity();	
				trans.RotateY(2*PI*float(rand())/float(RAND_MAX));
				trans.Translate(x,y,z);
				unit->GetModel()->SetTransform(trans);
			}
		}
	}

/*
	CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
	for (i=0;i<vsize;i++) {
		for (j=0;j<vsize;j++) {
			CTextureEntry* tex=g_TexMan.GetRandomTexture();
			CMiniPatch* mp=terrain->GetTile(i,j);
			mp->Tex1=tex->GetHandle();
			mp->Tex1Priority=tex->GetType();
			mp->m_Parent->SetDirty(RENDERDATA_UPDATE_VERTICES | RENDERDATA_UPDATE_INDICES);
		}
	}
	g_MiniMap.Rebuild();
*/
}

#define P(n) void CMainFrame::OnEntityPlayer##n() { return OnEntityPlayerX(n); }
P(0); P(1); P(2); P(3); P(4); P(5); P(6); P(7); P(8);
#undef P

void CMainFrame::OnEntityPlayerX(int x)
{
	CEntity* entity = CSelectObjectTool::GetTool()->GetFirstEntity();
	if (entity)
		entity->SetPlayer(g_Game->GetPlayer(x));
}
