///////////////////////////////////////////////////////////
//
//  IMPLEMENTATION
//
//  CONTEXT: Genesis3D lightweight framework
//  MODULE:	 main application class
//  PREREQ:	 mainviewcontroller.h, genewrap.h, resource.h, effects.h
//  FILE:	 GeneWalker.cpp
//	AUTHOR:  Klaus Zerbe <klaus@zerbe.com>
//  ORIGIN:  http://klaus.zerbe.com
//  VERSION: 1.0
//  DATE:    3.2.1999
//  PURPOSE: main program
//
///////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h" 
#include "effects.h" // light effects

// concrete main application class
//
class CGeneWalker : public CMainViewController {
public:
	CGeneWalker() : CMainViewController() { m_pEngine= NULL; }
	// set engine wrapper reference
	void SetEngine(CEngineWrapper *pEngine) { m_pEngine= pEngine; }
	// handle frame rate menu option
	bool GetFramerateOption();
	bool ToggleFramerateOption();
	//
	// implement required windows messages
	//
	// menu commands
	bool OnCommand(WORD wId, WORD wNotify);
	// keyboard processing
	bool OnKeyDown(DWORD dwKeyCode);
	bool OnKeyUp(DWORD dwKeyCode);
	// mouse processing
	bool OnButtonDown(MouseButton butt, POINT pos);
	bool OnButtonUp(MouseButton butt, POINT pos);
	// cursor setting
	bool OnSetCursor();
	// idle loop activity
	BOOL DoIdle();
private:
	CEngineWrapper *m_pEngine; // Genesis3D- Engine-Wrapper
};

// check menu option for frame rate display
bool CGeneWalker::GetFramerateOption()
{
	HMENU hMenu= GetMenu(GetHandle());
	if (!hMenu) return false;
	return (GetMenuState(hMenu, IDM_FRAMERATE, MF_BYCOMMAND)==MF_CHECKED);
}

// toggle frame rate menu option
bool CGeneWalker::ToggleFramerateOption()
{
	HMENU hMenu= GetMenu(GetHandle());
	if (!hMenu) return false;
	bool b= !GetFramerateOption();
	CheckMenuItem(hMenu, IDM_FRAMERATE, MF_BYCOMMAND|(b? MF_CHECKED:MF_UNCHECKED));
	return b;
}

// handle menu commands
bool CGeneWalker::OnCommand(WORD wId, WORD wNotify)
{
	switch(wId) {
		case IDM_ABOUT:
			// show about box
			ShowInfo();
		   	return true;
		case IDM_EXIT:
			// terminate program
		   	DestroyWindow(GetHandle());
		   	return true;
		case IDM_FRAMERATE:
			// toggle frame rate menu option
			if (m_pEngine) m_pEngine->SetFramerateCount(ToggleFramerateOption());
			return true;
	}
	return false;
}

// keyboard processing
bool CGeneWalker::OnKeyDown(DWORD dwKeyCode)
{
	// just map down keys to the related navigation function
	switch (dwKeyCode) {
		case VK_LEFT: 
			m_pEngine->SetMouseMode(left);
			break;
		case VK_RIGHT: 
			m_pEngine->SetMouseMode(right);
			break;
		case VK_UP:  
			m_pEngine->SetMouseMode(fore);
			break;
		case VK_DOWN:  
			m_pEngine->SetMouseMode(back);
			break;
		case VK_PRIOR: 
			m_pEngine->SetMouseMode(lookup);
			break;
		case VK_NEXT:  
			m_pEngine->SetMouseMode(lookdown);
			break;
		case VK_HOME:  
			m_pEngine->SetMouseMode(lookStraight);
			break;
	}
	return true;
}

bool CGeneWalker::OnKeyUp(DWORD dwKeyCode)
{
	// if key released, stop navigation function
	m_pEngine->SetMouseMode(off);
	return true;
}

bool CGeneWalker::OnButtonDown(MouseButton butt, POINT pos)
{
	int idc;
	// use left mouse button to enable navigation function
	// which depends on "zone" where mouse cursor is
	if (butt == btnLeft)
		m_pEngine->SetMouseMode(m_pEngine->GetMouseMode(&idc));
	return true;
}

bool CGeneWalker::OnButtonUp(MouseButton butt, POINT pos)
{
	// if mouse button released stop navigation function
	if (butt == btnLeft)
		m_pEngine->SetMouseMode(off);
	return true;
}

bool CGeneWalker::OnSetCursor()
{
	// let engine wrapper position the cursor
	// and choose cursor icon
	m_pEngine->SetCursor();
	return true;
}

// idle processing
BOOL CGeneWalker::DoIdle()
{
	// render next frame
	// (that will not be rendered really, if called to fast)
	if (m_pEngine) m_pEngine->RenderFrame();
	// nothing else to do here
	return FALSE;
}

// windows program start
int APIENTRY WinMain(HINSTANCE hInstance,  HINSTANCE hPrevInstance,
					 LPSTR lpCmdLine, int nCmdShow )
{
	const char 
		szWhiteSpace[]= "\t ", // commandline argument separators
		szMemErr[]= "out of memory";
	CEngineWrapper *pGenesis= NULL;
//	char *pVFile=NULL, *pLevel= NULL, 
	char szLevel[20];
	char *pVFile= "..\\art";
	char *pLevel= "test1.bsp";
	try {
		CGeneWalker app;
		// register window class and store WinMain arguments global
		CMainViewController::Initialize(hInstance, lpCmdLine);
		// separate commandline arguments
/*		pVFile= strtok(lpCmdLine, szWhiteSpace);
		if (pVFile) pLevel= strtok(NULL, szWhiteSpace);
		if (!(pVFile && pLevel)) 
			throw "call: GeneWalker <file> <level>";
		// special argument handling for using GeneWalker as viewer for GEDIT
		if (strcmp(pVFile, "-map") == 0) {
			pVFile= "..\\art"; sprintf(szLevel, "%s.bsp", pLevel);
		} else*/ strcpy(szLevel, pLevel);
		// create window
		if (!app.Create(640, 480)) throw "can't create window";
		// create engine wrapper, passing viewcontroller
		pGenesis= new CEngineWrapper(&app);
		if (!pGenesis) throw szMemErr;
		// load level
		pGenesis->Startup(pVFile, szLevel);
		// create all entities for world
//		new CCorona(pGenesis); // corona lights
//		new CDynamicLight(pGenesis); // dynamic lights
//		new CElectricBolt(pGenesis); // lightnings
		new CArtefact(pGenesis); // polygon models
		new CMusic(pGenesis); // midi music
		new CDoor(pGenesis); // doors
		// pass engine wrapper to app
		app.SetEngine(pGenesis);
		// enable/disable frame rate counter
		pGenesis->SetFramerateCount(app.GetFramerateOption());
		// enable rendering
		app.SetReady(true);
		// start main loop
		int result= app.Run();
		// shutdown engine wrapper
		delete pGenesis;
		return result;
	}
	// if something went wrong...
	catch (char *pMsg) {
		// shutdown engine wrapper
		if (pGenesis) delete pGenesis;
		// display error message
		MessageBox(NULL, pMsg, "ERROR", MB_ICONWARNING|MB_OK);
		return -1;
	}
	// any unhandled errors (eg. protection violations)
	catch (...) {
		// display error message
		MessageBox(NULL, "reason unknown", "STRANGE ERROR", MB_ICONWARNING|MB_OK);
	}
}
