/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifdef _MSC_VER
#pragma warning (disable: 4786)
#endif

#define STRICT
#include <Windows.h>
#include <Windowsx.h>
#include <string>
#include <map>
#include <list>
#include <vector>
#include <boost/shared_ptr.hpp>
#include "WinOnly.h"
#include "WinBe.h"
#include "NativeView.h"
#include "NativeApplication.h"


using namespace winBe;


// constructor	
NativeView::NativeView (BView* view, NativeWindow* window)
{
	viewColor = RGB (255, 255, 255);
	hPen = ::CreatePen (PS_SOLID, 1, RGB (0, 0, 0));
	this->view = view;
	this->window = window;
}


// destructor
NativeView::~NativeView ()
{
	//winBe::debugMessage ("destructing NativeView");
	destroy ();
	DeletePen (hPen);
}


// createWindow
void NativeView::createWindow (const char* name, int left, int top, int right, int bottom, HWND hWndParent)
{
	hWnd = CreateWindow ("BView", name, WS_CHILD | WS_VISIBLE, left, top, right - left, bottom - top, hWndParent, NULL, NativeApplication::instance ().getHINSTANCE (), this);
}


void NativeView::destroy ()
{
	//if (::IsWindow (hWnd))
	//	::DestroyWindow (hWnd);

	NativeApplication::instance ().deleteView (view);
}


// onPaint
void NativeView::onPaint (RECT& updateRect, HDC hDC)
{
	this->hDC = hDC;
	if (::IsWindow (hWnd))
		callViewDraw (view, updateRect.left, updateRect.top, updateRect.right, updateRect.bottom);
}


// setBgColor
void NativeView::setBgColor (COLORREF color)
{
	viewColor = color;
}


// setPen
void NativeView::setPen (int width, COLORREF color)
{
	::DeletePen (hPen);
	hPen = ::CreatePen (PS_SOLID, width, color);
}


// getNativeView
NativeView* NativeView::getNativeView (HWND hWnd)
{
	return reinterpret_cast<NativeView*>(GetWindowLong (hWnd, 0));
}


// captureMouse
void NativeView::captureMouse ()
{
	SetCapture (hWnd);
}


// captureKeyboard
void NativeView::captureKeyboard ()
{
}


// onMouseDown
void NativeView::onMouseDown (int button, int x, int y, int modifiers)
{
	sendViewMouseDownMessage (view, button, x, y, modifiers);
}


// onMouseUp
void NativeView::onMouseUp (int button, int x, int y, int modifiers)
{
	winBe::sendViewMouseUpMessage (view, button, x, y, modifiers);
}


// onMouseMove
void NativeView::onMouseMove (int x, int y, int modifiers)
{
	winBe::sendViewMouseMovedMessage (view, x, y);
}

	
// onEraseBackground
void NativeView::onEraseBackground (HDC hDC)
{
	HBRUSH hBrush = CreateSolidBrush (viewColor);
	RECT rect;
	if (GetUpdateRect (hWnd, NULL, FALSE) == 0)
		GetClientRect (hWnd, &rect);
	else
		GetUpdateRect (hWnd, &rect, FALSE);
	FillRect (hDC, &rect, hBrush);
	DeleteBrush (hBrush);
}


// NativeViewWndProc
LRESULT CALLBACK winBe::NativeViewWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	LRESULT result = 0;
	bool processed = true;

	NativeView* view = NativeView::getNativeView (hWnd);

	switch (message) {

		case WM_CREATE:
		{
			CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
			SetWindowLong (hWnd, 0, reinterpret_cast<LONG>(cs->lpCreateParams));
			view = NativeView::getNativeView (hWnd);
			break;
		}

		case WM_ERASEBKGND:
			view->onEraseBackground (reinterpret_cast<HDC>(wParam));
			result = 1;
			break;

		case WM_LBUTTONDOWN:
			view->onMouseDown (1, LOWORD (lParam), HIWORD (lParam), wParam);
			break;

		case WM_LBUTTONUP:
			view->onMouseUp (1, LOWORD (lParam), HIWORD (lParam), wParam);
			break;

		case WM_MBUTTONDOWN:
			view->onMouseDown (2, LOWORD (lParam), HIWORD (lParam), wParam);
			break;

		case WM_MBUTTONUP:
			view->onMouseUp (2, LOWORD (lParam), HIWORD (lParam), wParam);
			break;

		case WM_MOUSEMOVE:
			view->onMouseMove (LOWORD (lParam), HIWORD (lParam), wParam);
			break;

		case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hDC = BeginPaint (hWnd, &ps);
			view->onPaint (ps.rcPaint, hDC);
			EndPaint (hWnd, &ps);
			break;
		}

		case WM_RBUTTONDOWN:
			view->onMouseDown (4, LOWORD (lParam), HIWORD (lParam), wParam);
			break;

		case WM_RBUTTONUP:
			view->onMouseUp (4, LOWORD (lParam), HIWORD (lParam), wParam);
			break;

		default:
			processed = false;
	}

	if (!processed)
		result = DefWindowProc (hWnd, message, wParam, lParam);

	return result;
}
