/*
	Twilight Prophecy 3D/Multimedia SDK
	A multi-platform development system for virtual reality and multimedia.

	Copyright (C) 1997-2001 by Twilight 3D Finland Oy Ltd.

	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

	Please read the file LICENSE.TXT for additional details.


	source:
		win32 mouse

	revision history:
		Jan/07/2000 - Thomas Mannfred Carlsson - initial revision
		Jan/24/2001 - Jukka Liimatta - renaissance build

	todo:
		- Mouse velocity/axis implemenation
		- Change behaviour to work "correctly" in windowed mode
*/
#include <prcore/prcore.hpp>
using namespace prcore;



//////////////////////////////////////////////////////
// statics                                         //
////////////////////////////////////////////////////

LRESULT CALLBACK mouseStaticHook(int ncode, WPARAM wparam, LPARAM lparam);

static int mouseFlags = 0;
static int mouseX = 0;
static int mouseY = 0;
static HHOOK mouseStaticHookId = 0;
static long mouseStaticInitCount = 0;


//////////////////////////////////////////////////////
// Mouse                                           //
////////////////////////////////////////////////////

Mouse::Mouse()
{
	mouseStaticInitCount++;

	if ( ( !mouseStaticHookId ) && ( mouseStaticInitCount <= 1 ) )
	{
		mouseStaticHookId = SetWindowsHookEx( WH_MOUSE,
			(HOOKPROC) mouseStaticHook, 0, GetCurrentThreadId() );

		if ( !mouseStaticHookId ) 
			return;
	}
}


Mouse::~Mouse()
{
	if ( mouseStaticInitCount > 0 ) mouseStaticInitCount--;

	if ( ( mouseStaticHookId ) && ( mouseStaticInitCount == 0 ) )
	{
		UnhookWindowsHookEx( mouseStaticHookId );
		mouseStaticHookId = 0;

		ClipCursor( NULL );	// restore when done
	}
}


void Mouse::SetArea(const Rect& rect)
{
	RECT clip = 
	{ 
		rect.x,
		rect.y,
		rect.x+rect.width-1,
		rect.y+rect.height-1
	};
	ClipCursor( &clip );
}


void Mouse::SetXY(int x, int y)
{
	SetCursorPos( x, y );
}


int Mouse::GetX()
{
	return mouseX;
}


int Mouse::GetY()
{
	return mouseY;
}


int Mouse::GetAxisCount() const
{
	return 0;
}


int Mouse::GetButtonCount() const
{
	return 3;
}


float Mouse::GetAxis(int index)
{
	return 0;
}


bool Mouse::GetButton(int index)
{
	switch ( index )
	{
		case MOUSE_LEFT:	return (mouseFlags & MOUSE_LEFT) != 0;
		case MOUSE_RIGHT:	return (mouseFlags & MOUSE_RIGHT) != 0;
		case MOUSE_MIDDLE:	return (mouseFlags & MOUSE_MIDDLE) != 0;
		default:			return false;
	}
}


LRESULT CALLBACK mouseStaticHook( int ncode, WPARAM wparam, LPARAM lparam )
{
	if ( ncode < 0 )
	{
		return (int) CallNextHookEx( mouseStaticHookId, ncode, wparam, lparam );
	}

	mouseX = ( (MOUSEHOOKSTRUCT *)lparam )->pt.x;
	mouseY = ( (MOUSEHOOKSTRUCT *)lparam )->pt.y;

	switch ( wparam )
	{
		case WM_LBUTTONDOWN:
		{
			mouseFlags |= MOUSE_LEFT;
			break;
		}
		case WM_LBUTTONUP:
		{
			mouseFlags &= ( 0x0ffffff - MOUSE_LEFT );
			break;
		}
		case WM_MBUTTONDOWN:
		{
			mouseFlags |= MOUSE_MIDDLE;
			break;
		}
		case WM_MBUTTONUP:
		{
			mouseFlags &= ( 0x0ffffff - MOUSE_MIDDLE );
			break;
		}
		case WM_RBUTTONDOWN:
		{
			mouseFlags |= MOUSE_RIGHT;
			break;
		}
		case WM_RBUTTONUP:
		{
			mouseFlags &= ( 0x0ffffff - MOUSE_RIGHT );
			break;
		}
	}

	return 1;
}
