--{-# LANGUAGE TupleSections #-}
{- |
Drawing of creatures. 
Takes into account damage etc. -}
module Dodge.Creature.Picture
    ( basicCrPict
    , circLine
    , picAtCrPos
    , picAtCrPosNoRot
    ) where
import Dodge.Data
--import Dodge.Data.DamageType
--import Dodge.Base
--import Dodge.Creature.Stance.Data
import Dodge.Creature.Perception.Data
--import Dodge.Creature.State.Data
import Dodge.Creature.Stance.Data
--import Dodge.Creature.Memory.Data
import Dodge.Creature.Test
--import Dodge.Creature.AlertLevel.Data
--import Dodge.Picture.Layer
import Dodge.Item.Data
import Dodge.Clock
import Picture
import Geometry
import Shape
import ShapePicture
--import Geometry.Vector3D

import Control.Lens
import qualified Data.IntMap.Strict as IM
import qualified Data.Vector as V
basicCrPict 
    :: Color    -- ^ Creature color
    -> Creature 
    -> World
    -> SPic
basicCrPict col cr w = (,) (basicCrShape col cr) $ pictures $
    targetingPic ++
    [ creatureDisplayText w cr
    , tr . rotdir $ _spPicture $ drawEquipment cr
    ]
  where 
    targetingPic = IM.elems $ IM.mapMaybeWithKey f $ _crInv cr
    f invid it = fmap ((\g -> g invid it cr w) . snd) (it ^? itTargeting . _Just)
    tr = uncurryV translate (_crPos cr) 
    rotdir = rotate (_crDir cr)

basicCrShape 
    :: Color    -- ^ Creature color
    -> Creature 
    -> Shape
basicCrShape col cr = tr $ mconcat
    [ rotdir . _spShape $ drawEquipment cr
    , rotdir . dm . translateSHz 25 $ scalp cr
    , rotdir . dm $ upperBody col cr
    , dm . rotmdir $ feet cr
    ]
  where 
    dm = damageModSH cr
    tr = uncurryV translateSHf (_crPos cr)
    rotdir = rotateSH (_crDir cr)
    rotmdir = rotateSH (_crMvDir cr)
        . colorSH (greyN 0.3)

creatureDisplayText :: World -> Creature -> Picture
creatureDisplayText w cr 
    = setLayer 4 
    . setDepth 50 
    . translate x y 
    . color white 
    . rotate a 
    . scale theScale theScale 
    . text 
    $ clockCycle 50 (V.fromList [crDisplayAwake, crDisplayAlert]) w cr
  where
    campos = _cameraViewFrom w
    theScale = 0.15 / _cameraZoom w
    cpos = _crPos cr
    v = cpos -.- campos
    a = argV v - 0.5 * pi
    (V2 x y) = campos +.+ v +.+ _crRad cr *.* normalizeV v


crDisplayAlert :: Creature -> String
crDisplayAlert cr
    | isSuspicious = "?"
    | isCognizant  = "!"
    | otherwise    = "."
  where
    imAwarenesses = _crAwarenessLevel (_crPerception cr)
    isSuspicious = any f imAwarenesses && not (null imAwarenesses)
    isCognizant  = any g imAwarenesses && not (null imAwarenesses)
    f (Suspicious _) = True
    f _ = False
    g (Cognizant _) = True
    g _ = False

crDisplayAwake :: Creature -> String
crDisplayAwake cr = case _crAwakeLevel (_crPerception cr) of
    Comatose    -> "-"
    Asleep      -> "Z"
    Lethargic   -> "L"
    Vigilant    -> "V"
    Overstrung  -> "O"

--damageMod :: Creature -> Picture -> Picture
--damageMod cr pic = piercingMod $ bluntScale pic
--  where
--    cdir = _crDir cr
--    pastDams = _crPastDamage $ _crState cr
--    bluntDam :: Maybe Point2
--    bluntDam = find isBluntDam (concat pastDams) >>= (\dm -> (-.-) <$> dm ^? dmFrom <*> dm ^? dmTo)
--    bluntScale = case fmap argV bluntDam of
--        Just a -> rotate (a + cdir) . scale 0.8 1.2 . rotate (negate $ cdir + a)
--        _   -> id
--    isBluntDam Blunt{} = True
--    isBluntDam _ = False
--    piercingDam = find isPiercingDam (concat pastDams) >>= (\dm -> (-.-) <$> dm ^? dmFrom <*> dm ^? dmTo)
--    isPiercingDam Piercing{} = True
--    isPiercingDam _ = False
--    piercingMod = case fmap argV piercingDam of
--        Just a -> rotate (a + cdir) . scale 0.8 1.2 . rotate (negate $ cdir + a)
--        _   -> id
damageModSH :: Creature -> Shape -> Shape
damageModSH _ = id

feet :: Creature -> Shape
{-# INLINE feet #-}
feet cr = case cr ^? crStance . carriage of
    Just (Walking sa LeftForward)  -> mconcat
        [ translateSHf ( f sa)   off  aFoot
        , translateSHf (-f sa) (-off) aFoot
        ]
    Just (Walking sa RightForward) -> mconcat
        [ translateSHf (-f sa)   off  aFoot
        , translateSHf ( f sa) (-off) aFoot
        ]
    _ -> mconcat
        [ translateSHf 0   off  aFoot
        , translateSHf 0 (-off) aFoot
        ]
  where
    aFoot :: Shape
    aFoot = upperPrismPoly 10 $ polyCirc 3 4
    off = 5
    sLen = _strideLength $ _crStance cr
    f i = 6 * fromIntegral (sLen - i) / fromIntegral sLen

arms :: Creature -> Shape
{-# INLINE arms #-}
arms cr 
    | oneH cr = shoulderSH . translateSHf 11 (-3) . rotateSH (-0.5) $ scaleSH (V3 1 1.5 1) aHand
    | twists cr = shoulderSH . translateSHf 0 (0.5* crad) . rotateSH (-1) $ mconcat 
        [ translateSHf 12 4    aHand
        , translateSHf 4 (-10) aHand
        ]
    | otherwise = case cr ^? crStance . carriage of
        Just (Walking sa LeftForward)  -> waistSH $ translateSHf (-f sa) (-off) aHand
        Just (Walking sa RightForward) -> waistSH $ translateSHf (-f sa) off    aHand
        _ -> emptySH 
  where
    aHand :: Shape
    aHand = translateSHz (-4) . upperPrismPoly 4 $ polyCirc 3 4
    crad = _crRad cr
    off = 8
    sLen = _strideLength $ _crStance cr
    f i = negate 2 + negate 6 * fromIntegral (sLen - i) / fromIntegral sLen

scalp :: Creature -> Shape
{-# INLINE scalp #-}
scalp cr
    | twists cr = translateSHf 0 (0.5*crad) . rotateSH (-1) $ translateSHf (negate 0.25 * crad) 0.25 fhead
    | oneH   cr = rotateSH 0.5 $ translateSHf (0.25 * crad) 0 fhead
    | otherwise = translateSHf (0.25 * crad) 0 fhead
  where
    fhead = colorSH (greyN 0.9) . upperPrismPoly 5 . polyCirc 3 $ crad * 0.5
    crad = _crRad cr

oneH :: Creature -> Bool
oneH cr = crIsAiming' cr && crIt ^? itAimStance == Just OneHand
  where
    crIt = _crInv cr IM.! _crInvSel cr

twists :: Creature -> Bool
twists cr = crIsAiming' cr && crIt ^? itAimStance == Just TwoHandTwist
  where
    crIt = _crInv cr IM.! _crInvSel cr

torso :: Creature -> Shape
{-# INLINE torso #-}
torso cr 
    | oneH cr   = rotateSH 0.5 $ mconcat
        [ translateSHf 0 3 . rotateSH (negate 0.2) $ aShoulder
        , translateSHf 0 (negate 3) . rotateSH 0.2 $ aShoulder
        ]
    | twists cr = translateSHf 0 (0.5* crad) . rotateSH (-1) $ mconcat
        [ rotateSH (negate 0.2) . translateSHf 2 3 . rotateSH (negate 0.4) $ aShoulder
        , rotateSH (negate 0.2) . translateSHf 0 (negate 3) . rotateSH 0.2 $ aShoulder
        ]
    | otherwise = mconcat
        [ translateSHf 0 3 . rotateSH (negate 0.2) $ aShoulder
        , translateSHf 0 (negate 3) . rotateSH 0.2 $ aShoulder
        ]
  where
    --aShoulder = translateSHz (-10) . scaleSH (V3 0.5 1 1) . upperPrismPoly 10 $ polyCirc 3 crad
    aShoulder = scaleSH (V3 crad crad 1) baseShoulder
    crad = _crRad cr

baseShoulder :: Shape
{-# INLINE baseShoulder #-}
baseShoulder = translateSHz (-10) . scaleSH (V3 0.5 1 1) . upperPrismPoly 10 $ polyCirc 3 1

upperBody :: Color -> Creature -> Shape
{-# INLINE upperBody #-}
upperBody col cr = colorSH (light4 col) $ mconcat
    [ arms cr
    , shoulderSH $ torso cr
    ]

shoulderSH :: Shape -> Shape
shoulderSH = translateSHz 20
waistSH :: Shape -> Shape
waistSH = translateSHz 10

light4 :: Color -> Color
light4 = light . light . light . light

--drawAwakeLevel
--    :: Creature
--    -> Picture
--drawAwakeLevel cr = case cr ^? crAttentionDir of
--    Just (AttentiveTo [0]) -> setPos . color red $ circleSolid 5
--    _        -> setPos . color blue $ circleSolid 5
--  where
--    setPos = translate 0 (_crRad cr)

drawEquipment 
    :: Creature 
    -> SPic
{-# INLINE drawEquipment #-}
drawEquipment cr = mconcat $ map f $ IM.toList (_crInv cr)
  where 
    f (i,it) = case it ^? itEquipPict of
        Just g -> g cr i
        _      -> emptyBlank

circLine :: Float -> Picture
circLine x = line [V2 0 0,V2 x 0]

picAtCrPos :: Picture -> Creature -> World -> SPic
--{-# INLINE picAtCrPos #-}
picAtCrPos thePic cr _ = (,) emptySH $ tranRot (_crPos cr) (_crDir cr) thePic

picAtCrPosNoRot :: Picture -> Creature -> World -> SPic
--{-# INLINE picAtCrPos #-}
picAtCrPosNoRot thePic cr _ = (,) emptySH $ uncurryV translate (_crPos cr) thePic
