/*
Copyright (C) 1997-2001 Id Software, Inc.

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.

*/

//
// win_mouse.c -- standard windows mouse driver
//

#include "win_local.h"

// mouse variables
static cvar_t	*win_xpfix;

static int			mouse_oldbuttonstate;
static POINT		current_pos;

static qboolean	mouseactive;	// qfalse when not focus app

static qboolean	restore_spi;
static qboolean	mouseinitialized;
static int		originalmouseparms[3];
static int		newmouseparms[3] = { 0, 0, 1 }, newMouseParmsXP[3] = { 0, 0, 0 };
static qboolean	mouseparmsvalid;

static int		window_center_x, window_center_y;
static RECT		window_rect;

/*
===========
Win_AcquireMouse

Called when the window gains focus or changes in some way
===========
*/
static void Win_AcquireMouse( void ) {
	RECT screen;

	if( mouseparmsvalid )
		restore_spi = SystemParametersInfo( SPI_SETMOUSE, 0, win_xpfix->integer ? newMouseParmsXP : newmouseparms, 0 );

	if( GetSystemMetrics( SM_CMONITORS ) > 1 ) {
		/* use virtual screen dimensions */
		screen.left = GetSystemMetrics( SM_XVIRTUALSCREEN );
		screen.top = GetSystemMetrics( SM_YVIRTUALSCREEN );
		screen.right = screen.left + GetSystemMetrics( SM_CXVIRTUALSCREEN );
		screen.bottom = screen.top + GetSystemMetrics( SM_CYVIRTUALSCREEN );
	} else {
		/* use primary monitor dimensions */
		screen.left = 0;
		screen.top = 0;
		screen.right = GetSystemMetrics( SM_CXSCREEN );
		screen.bottom = GetSystemMetrics( SM_CYSCREEN );
	}

	GetWindowRect( hWndMain, &window_rect );
	if( window_rect.left < screen.left )
		window_rect.left = screen.left;
	if( window_rect.top < screen.top )
		window_rect.top = screen.top;
	if( window_rect.right > screen.right - 1 )
		window_rect.right = screen.right - 1;
	if( window_rect.bottom > screen.bottom - 1 )
		window_rect.bottom = screen.bottom - 1;

	window_center_x = ( window_rect.right + window_rect.left ) / 2;
	window_center_y = ( window_rect.top + window_rect.bottom ) / 2;

	SetCursorPos( window_center_x, window_center_y );

	SetCapture( hWndMain );
	ClipCursor( &window_rect );
	while( ShowCursor( FALSE ) >= 0 )
		;
}


/*
===========
Win_DeAcquireMouse

Called when the window loses focus
===========
*/
static void Win_DeAcquireMouse( void ) {
	if( restore_spi )
		SystemParametersInfo( SPI_SETMOUSE, 0, originalmouseparms, 0 );

	ClipCursor( NULL );
	ReleaseCapture();
	while( ShowCursor ( TRUE ) < 0 )
		;
}

/*
===========
Win_XPFix_OnChange
===========
*/
static void Win_XPFix_OnChange( cvar_t *self, void *arg ) {
	if( !mouseactive ) {
		return;
	}

	Win_AcquireMouse();
}

/*
===========
Win_SendMouseButtonEvents

Called from the main window procedure
===========
*/
void Win_SendMouseButtonEvents( int mstate, DWORD time ) {
	int		i;

	if( !mouseinitialized ) {
		return;
	}

	if( !mouseactive ) {
		return;
	}

	if( mstate == mouse_oldbuttonstate ) {
		return;
	}

// perform button actions
	for( i = 0 ; i < MOUSE_BUTTONS; i++ ) {
		if( ( mstate & ( 1 << i ) ) && !( mouse_oldbuttonstate & ( 1 << i ) ) ) {
			Key_Event( K_MOUSE1 + i, qtrue, time );
		}

		if( !( mstate & ( 1 << i ) ) && ( mouse_oldbuttonstate & ( 1 << i ) ) ) {
			Key_Event( K_MOUSE1 + i, qfalse, time );
		}
	}	
		
	mouse_oldbuttonstate = mstate;
}


/*
===========
Win_SendMouseMoveEvents
===========
*/
void Win_SendMouseMoveEvents( void ) {
	int		dx, dy;

	if( !mouseinitialized ) {
		return;
	}

	if( !mouseactive ) {
		return;
	}

	// find mouse movement
	if( !GetCursorPos( &current_pos ) ) {
		return;
	}

	dx = current_pos.x - window_center_x;
	dy = current_pos.y - window_center_y;

	if( !dx && !dy ) {
		return;
	}

	// force the mouse to the center, so there's room to move
	SetCursorPos( window_center_x, window_center_y );

	CL_MouseEvent( dx, dy );

}

/*
===========
Win_ShutdownMouse
===========
*/
static void Win_ShutdownMouse( void ) {
	Win_DeAcquireMouse();
	mouseactive = qfalse;
	mouseinitialized = qfalse;
	mouse_oldbuttonstate = 0;
}

/*
===========
Win_StartupMouse
===========
*/
static qboolean Win_InitMouse( void ) {
	if( !win_initialized ) {
		return qfalse;
	}

	win_xpfix = Cvar_Get( "win_xpfix", "0", 0 );
	win_xpfix->changedFunc = Win_XPFix_OnChange;

	mouseinitialized = qtrue;
	mouseparmsvalid = SystemParametersInfo( SPI_GETMOUSE, 0, originalmouseparms, 0 );

	return qtrue;
}

/*
===========
Win_ActivateMouse

Called when the main window gains or loses focus.
The window may have been destroyed and recreated
between a deactivate and an activate.
===========
*/
static void Win_ActivateMouse( qboolean active ) {
	if( !mouseinitialized ) {
		return;
	}

	if( mouseactive == active ) {
		return;
	}

	if( active ) {
		Win_AcquireMouse();
	} else {
		Win_DeAcquireMouse();
	}

	mouseactive = active;

}

/*
===================
Win_ClearMouseStates
===================
*/
static void Win_ClearMouseStates( void ) {
	mouse_oldbuttonstate = 0;
}

/*
@@@@@@@@@@@@@@@@@@@
Win_FillInputAPI
@@@@@@@@@@@@@@@@@@@
*/
void Video_FillInputAPI( inputAPI_t *api ) {
	api->Init = Win_InitMouse;
	api->Shutdown = Win_ShutdownMouse;
	api->Activate = Win_ActivateMouse;
	api->Frame = Win_SendMouseMoveEvents;
	api->ClearStates = Win_ClearMouseStates;
}


