{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE ScopedTypeVariables, RankNTypes #-}

module Graphics.Gloss.Internals.Interface.ViewPort.Motion
	(callback_viewPort_motion)
where
import Graphics.Gloss.Data.Vector
import Graphics.Gloss.Geometry.Angle
import Graphics.Gloss.Internals.Interface.ViewPort
import Graphics.Gloss.Internals.Interface.Callback
import Graphics.Gloss.Internals.Interface.Backend
import qualified Graphics.Gloss.Internals.Interface.ViewPort.ControlState	as VPC
import qualified Graphics.Rendering.OpenGL.GL					as GL
import Control.Monad	
import Data.IORef


-- | Callback to handle keyboard and mouse button events
--	for controlling the viewport.
callback_viewPort_motion 
	:: IORef ViewPort 	-- ^ ref to ViewPort state
	-> IORef VPC.State 	-- ^ ref to ViewPort Control state
	-> Callback

callback_viewPort_motion portRef controlRef 
 	= Motion (viewPort_motion portRef controlRef)

viewPort_motion
	:: IORef ViewPort
	-> IORef VPC.State
	-> MotionCallback
	
viewPort_motion
	portRef controlRef
	stateRef
	pos
 = do
--	putStr $ "motion pos = " ++ show pos ++ "\n"

	translateMark	<- controlRef `getsIORef` VPC.stateTranslateMark
	rotateMark	<- controlRef `getsIORef` VPC.stateRotateMark

	(case translateMark of
	 Nothing		-> return ()
	 Just (markX, markY)	
	  -> do
		motionTranslate
	  	  portRef controlRef
		  (fromIntegral markX, fromIntegral markY)
		  pos 
		postRedisplay stateRef)


	(case rotateMark of
	 Nothing		-> return ()
	 Just (markX, markY)
	  -> do
		motionRotate
	  	  portRef controlRef
		  (fromIntegral markX, fromIntegral markY)
		  pos 
		postRedisplay stateRef)


motionTranslate
	:: IORef ViewPort
        -> IORef VPC.State
        -> (GL.GLint, GL.GLint)
        -> (Int, Int)
	-> IO ()
 
motionTranslate 
	portRef controlRef
	(markX :: GL.GLint, markY :: GL.GLint)
	(posX, posY)
 = do
	(transX, transY)
		<- portRef `getsIORef` viewPortTranslate

	scale	<- portRef `getsIORef` viewPortScale
	r	<- portRef `getsIORef` viewPortRotate

	let dX		= fromIntegral $ markX - (fromIntegral posX)
	let dY		= fromIntegral $ markY - (fromIntegral posY)

	let offset	= (dX / scale, dY / scale)

	let (oX, oY)	= rotateV (degToRad r) offset

	portRef `modifyIORef` \s -> s 
		{ viewPortTranslate	
		   = 	( transX - oX
		 	, transY + oY) }
		
	controlRef `modifyIORef` \s -> s
		{ VPC.stateTranslateMark
		   =	Just (fromIntegral posX, fromIntegral posY) }


motionRotate
	:: IORef ViewPort
	-> IORef VPC.State
	-> (GL.GLint, GL.GLint)
	-> (Int, Int)
	-> IO ()

motionRotate 
	portRef controlRef
	(markX :: GL.GLint, _markY :: GL.GLint)
	(posX, posY)
 = do
 	rotate		<- portRef    `getsIORef` viewPortRotate
	rotateFactor	<- controlRef `getsIORef` VPC.stateRotateFactor
	
	portRef `modifyIORef` \s -> s 
		{ viewPortRotate
		   = 	rotate + rotateFactor * fromIntegral ((fromIntegral posX) - markX) }
		
	controlRef `modifyIORef` \s -> s
		{ VPC.stateRotateMark
		   = 	Just (fromIntegral posX, fromIntegral posY) }


getsIORef :: IORef a -> (a -> r) -> IO r
getsIORef ref fun
 = liftM fun $ readIORef ref
