///////////////////////////////////////////////////////////
//
//  IMPLEMENTATION
//
//  CONTEXT: Genesis3D lightweight framework
//  MODULE:	 abstract main window class
//  PREREQ:	 customized resource.h 
//  FILE:	 mainviewcontroller.cpp
//	AUTHOR:  Klaus Zerbe <klaus@zerbe.com>
//  ORIGIN:  http://klaus.zerbe.com
//  VERSION: 1.0
//  DATE:    3.2.1999
//  PURPOSE: Kapselung der Windows-Hauptfenster Verwaltung
//
///////////////////////////////////////////////////////////

#include <stdafx.h>
#include "resource.h"

// applikation handle
HINSTANCE CMainViewController::m_hInst= NULL;

// commandline passed to WinMain()
LPSTR CMainViewController::m_pCmdLine= NULL;

// window class name
TCHAR CMainViewController::m_szWindowClass[MAX_LOADSTRING];

// singleton main window instance
CMainViewController* CMainViewController::m_pCurrent;

// register main window class and store WinMain arguments
BOOL CMainViewController::Initialize(HINSTANCE hInst, LPSTR pCmdLine)
{
	WNDCLASSEX wcex;
	// store WinMain arguments
	m_hInst= hInst;
	m_pCmdLine= pCmdLine; 
	// get window class name from ressource file
	LoadString(m_hInst, IDS_APP_CLASS, m_szWindowClass, MAX_LOADSTRING);
	wcex.cbSize = sizeof(WNDCLASSEX); 
	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)MainWndProc; // set window function
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= m_hInst;
	// get application icon from ressource file
	wcex.hIcon			= LoadIcon(m_hInst, (LPCTSTR)IDI_APP);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= (LPCSTR)IDC_MAINMENU;
	wcex.lpszClassName	= m_szWindowClass;
	// get the Win95 taskbar icon from ressource file
	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
	// register class
	return RegisterClassEx(&wcex);
}

CMainViewController::CMainViewController()
{
	m_hWnd= NULL;
	m_bReady= false;  // block idle loop
	m_pCurrent= this;
}

// get singleton instance
CMainViewController* CMainViewController::GetCurrent() 
{ 
	return m_pCurrent; 
}

// create main window with width x height sized client area
bool CMainViewController::Create(int width, int height)
{
	RECT rc;
	// exit if no application handle or already created
	if (!m_hInst || m_hWnd) return FALSE;
	// set window rectangle
	rc.left= 0;
	rc.top= 0;
	rc.right= width;
	rc.bottom= height;
	// get window title out of ressource file
	LoadString(m_hInst, IDS_APP_TITLE, m_szTitle, MAX_LOADSTRING);
	// recalc window rectangle to get wanted client size
	AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, true);
	// create main window
	m_hWnd= CreateWindowEx(WS_EX_APPWINDOW, m_szWindowClass, m_szTitle,
		WS_OVERLAPPEDWINDOW, 0, 0, rc.right-rc.left, rc.bottom-rc.top, 
		NULL, NULL, m_hInst, this);
	if (!m_hWnd) return false;
	// connect window to its controlling instance
	SetWindowLong(m_hWnd,GWL_USERDATA,(LONG)this);
	// draw window and update client area
	ShowWindow(m_hWnd, SW_SHOW);
	UpdateWindow(m_hWnd);
	return true;
}

// main loop
int CMainViewController::Run()
{
	// get hotkeys
	m_hAccelTable = LoadAccelerators(m_hInst, (LPCTSTR)IDC_ACCEL);
	// process window  messages and idle loop
	while (DoEvent());
	// return exit code
	return m_msg.wParam;
}

// message/idle loop processing
// should be called during any idle time :)
bool CMainViewController::DoEvent()
{
	bool bGotMsg= false; 
	// windows message available? than process it
	while (PeekMessage(&m_msg, NULL, 0, 0, PM_REMOVE)) {
		bGotMsg= true;
		// got termination? stop loop
		if (m_msg.message == WM_QUIT) return false;
		// process message
		if(!TranslateAccelerator (m_msg.hwnd, m_hAccelTable, &m_msg)) {
			TranslateMessage(&m_msg);
			DispatchMessage(&m_msg);
		}
	}
	// if got windows message, dont do any idle processing
	// often there will be a sequence of related messages need to processed
	// with priority
	if (bGotMsg) return true;
	// time for idle looping
	// DoIdle should return false if no more cycles needed
	if (IsReady()) { while (DoIdle()); }
	return true;
}

// show about box
void CMainViewController::ShowInfo()
{
   DialogBox(m_hInst, (LPCTSTR)IDD_ABOUTBOX, m_hWnd, (DLGPROC)About); 
}


// main window function
long CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	
	CMainViewController *pView;
	if (msg==WM_CREATE) {
		// if window is about to be created, get instance pointer from CREATESTRUCT
		LPCREATESTRUCT lpcs= (CREATESTRUCT*)lParam;
		pView= (CMainViewController*)(lpcs->lpCreateParams);
	} else {
		// afterwards take it out of the window structure
		pView= (CMainViewController*)GetWindowLong(hWnd, GWL_USERDATA);
	}
	// let do real message handling the derived app class
	// most things just reached through here
	// the bool methods need to return true if they handled the message
	if (pView) {
		POINT pos;
		switch (msg) {
			case WM_CREATE:
				pView->OnCreate(hWnd);
				break;
			case WM_ACTIVATEAPP:
				if (pView->OnActivateApp(wParam)) return 0; 
				break;
			case WM_CLOSE:
				if (pView->OnClose()) return 0;
				// destroy window in any case now
				DestroyWindow(hWnd); 
				return 0;
			case WM_DESTROY:
				pView->OnDestroy();
				ShowCursor(TRUE);
				// stop application in any case now
				PostQuitMessage(0);
				return 0;
			case WM_PAINT:
				if (pView->OnPaint(hWnd)) return 0;
				break;
			case WM_KEYDOWN:
				if (pView->OnKeyDown(wParam)) return 0;
				break;
			case WM_KEYUP:
				if (pView->OnKeyUp(wParam)) return 0;
				break;
			case WM_LBUTTONDOWN:
				pos.x= LOWORD(lParam);
				pos.y= HIWORD(lParam);
				if (pView->OnButtonDown(btnLeft, pos)) return 0;
				break;
			case WM_LBUTTONUP:
				pos.x= LOWORD(lParam);
				pos.y= HIWORD(lParam);
				if(pView->OnButtonUp(btnLeft, pos)) return 0;
				break;
			case WM_RBUTTONDOWN:
				pos.x= LOWORD(lParam);
				pos.y= HIWORD(lParam);
				if (pView->OnButtonDown(btnRight, pos)) return 0;
				break;
			case WM_RBUTTONUP:
				pos.x= LOWORD(lParam);
				pos.y= HIWORD(lParam);
				if (pView->OnButtonUp(btnRight, pos)) return 0;
				break;
			case WM_COMMAND:
				if (!pView->OnCommand(LOWORD(wParam), HIWORD(wParam))) return 0;
				break;
			case WM_SETCURSOR:
				if (hWnd==(HWND)wParam) {
				 	if (pView->OnSetCursor()) return 0;
				}
				break;
		}
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

// about box callback function
LRESULT CALLBACK About( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
	switch( message ) {
		case WM_INITDIALOG:
			return TRUE;
		case WM_COMMAND:
			if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
				// close about box
				EndDialog(hDlg, LOWORD(wParam));
				return TRUE;
			}
			break;
	}
    return FALSE;
}
