module Dodge.Creature.Impulse.Movement where
import Dodge.Data
import Dodge.Creature.Statistics
import Geometry

--import Data.Maybe
--import qualified Data.IntMap.Strict as IM
import Control.Lens
{- | Creature attempts to moves under its own steam.
The idea is that this may or may not work, depending on the status of the creature. 
For now, though, this cannot fail. -}
crMvBy :: Point2   -- ^ Movement translation vector, will be made relative to creature direction
    -> Creature -> Creature
crMvBy p cr = crMvAbsolute (rotateV (_crDir cr) p) cr

crMvAbsolute
    :: Point2   -- ^ Movement translation vector
    -> Creature 
    -> Creature
crMvAbsolute p' cr = advanceStepCounter (magV p) cr
    & crPos %~ (+.+ p)
    & crMvDir .~ argV p
  where 
    p = strengthFactor (getCrStrength cr) *.* p'

strengthFactor :: Int -> Float
strengthFactor i
    | i > 9 = 1
    | i < 1 = 0
    | otherwise = 0.1 * fromIntegral i

crMvForward 
    :: Float    -- ^ Speed
    -> Creature 
    -> Creature
crMvForward speed = crMvBy (V2 speed 0)

advanceStepCounter
    :: Float    -- ^ Speed
    -> Creature 
    -> Creature
advanceStepCounter speed = crStance . carriage %~ f
  where 
    f car = case car of
        Standing -> f (Walking 0 RightForward)
        Walking i ff -> Walking (i + ceiling speed) ff
        _ -> car

creatureTurn :: Float -> Creature -> Creature
creatureTurn a = crDir +~ a

creatureTurnTo :: Point2 -> Creature -> Creature
creatureTurnTo p cr 
    | vToTarg == V2 0 0 = cr -- this should deal with the angleVV error
    | otherwise         = cr & crDir .~ dirToTarget
  where
    vToTarg = p -.- _crPos cr
    dirToTarget = argV vToTarg

-- the following is perhaps not ideal because it mixes normalizeAngle with
-- angleVV, but it seems to work
creatureTurnTowardDir 
    :: Float -- ^ Angle
    -> Float -- ^ Turn speed
    -> Creature
    -> Creature
creatureTurnTowardDir a turnSpeed cr 
    | normalizeAngle (abs (a - cdir)) <= turnSpeed
                = cr & crDir .~ dirToTarget
    | isLeftOfA (normalizeAngle dirToTarget) (normalizeAngle $ _crDir cr) 
                = cr & crDir +~ turnSpeed
    | otherwise = cr & crDir -~ turnSpeed
  where
    cdir = _crDir cr
    vToTarg = rotateV a (V2 1 0)
    dirToTarget = argV vToTarg

creatureTurnToward :: Point2 -> Float -> Creature -> Creature
creatureTurnToward p turnSpeed cr 
    | vToTarg == V2 0 0 = cr -- this should deal with the angleVV error
    | errorAngleVV 3 vToTarg (unitVectorAtAngle (_crDir cr)) <= turnSpeed
                                        = cr & crDir .~ dirToTarget
    | isLeftOfA (normalizeAngle dirToTarget) (normalizeAngle $ _crDir cr) = cr & crDir +~ turnSpeed
    | otherwise                         = cr & crDir -~ turnSpeed
  where
    vToTarg = p -.- _crPos cr
    dirToTarget = argV vToTarg

{- | Speed modifier of an item when not aiming. -}
equipSpeed :: Item -> Float
equipSpeed _ = 1
