module Dodge.LevelGen.DoorPane
    ( linearPane
    , mkDoubleDoor
    , mkSingleDoor
    ) where
import Dodge.Data
import Dodge.LevelGen.MoveDoor
import Picture
import qualified DoubleStack as DS
import Geometry.Vector
import Geometry.Data

import Data.Bifunctor

-- | A door pane that moves linearly between open and closed positions using a
-- boolean trigger.
linearPane 
    :: Color 
    -> Bool             -- ^ Pathable flag
    -> (World -> Bool)  -- ^ Opening condition
    -> Float            -- ^ speed
    -> Int              -- ^ Wall id
    -> (Point2,Point2)  -- ^ Closed position
    -> (Point2,Point2)  -- ^ Open position
    -> Wall
linearPane c isPathable cond speed n closedPos openPos = Door
    { _wlLine = closedPos
    , _wlID = n
    , _doorMech = dm
    , _wlColor = c
    , _wlSeen = False
    , _wlIsSeeThrough = False
    , _doorPathable = isPathable
    , _drPositions = DS.singleton closedPos
    }
  where 
    dm = doorMechan n (zoneps closedPos) openDoor closeDoor cond 
    openDoor  = moveDoorToward speed openPos
    closeDoor = moveDoorToward speed closedPos

rectanglePairs :: Float -> Point2 -> Point2 -> [(Point2,Point2)]
rectanglePairs wdth a b =
    [ (aup, ad)
    , (ad, bd)
    , (bd, bu)
    , (bu, aup)
    ]
  where
    aup = a +.+ norm
    ad = a -.- norm
    bu = b +.+ norm
    bd = b -.- norm
    norm = wdth *.* normalizeV ( vNormal (b -.- a))

mkSingleDoor :: Color -> Bool -> (World -> Bool) -> Point2 -> Point2 -> Float -> [Int] -> [Wall]
mkSingleDoor c isPathable cond hingep edgep speed is 
    = addSoundToDoor (head is) (fst $ head theDoor) (fst $ head shiftedDoor)
    $ zipWith3 (linearPane c isPathable cond speed)
        is
        theDoor
        shiftedDoor
  where 
    theDoor = rectanglePairs 9 hingep edgep
    shiftedDoor = map (bimap shiftLeft shiftLeft) theDoor
    shiftLeft  = (+.+ (hingep -.- edgep))

mkDoubleDoor :: Color -> Bool -> (World -> Bool) -> Point2 -> Point2 -> Float -> [Int] -> [Wall]
mkDoubleDoor c isPathable cond pl pr speed is 
    = addSoundToDoor (head is) (fst $ head leftDoor) (fst $ head shiftedDoor)
    $ zipWith3 (linearPane c isPathable cond speed)
        is
        (leftDoor ++ rightDoor)
        shiftedDoor
  where 
    shiftedDoor = map shiftLeft leftDoor ++ map shiftRight rightDoor
    leftDoor = 
        [ (pld +.+ perp,hwd)
        , (hwd,         hwu)
        , (hwu,         plu +.+ perp)
        , (plu +.+ perp,pld +.+ perp)
        ]
    rightDoor =
        [ (pru -.- perp,hwu)
        , (hwu,         hwd)
        , (hwd,         prd -.- perp)
        , (prd -.- perp,pru -.- perp)
        ]
    shiftRight = h (+.+ (0.5 *.* (pr -.- pl)))
    shiftLeft  = h (+.+ (0.5 *.* (pl -.- pr)))
    h func (x,y) = (func x,func y)
    norm = 9 *.* normalizeV ( vNormal (pr -.- pl))
    hw = 0.5 *.* (pl +.+ pr)
    perp = 5 *.* normalizeV (pl -.- pr)
    plu = pl +.+ norm
    pld = pl -.- norm
    pru = pr +.+ norm
    prd = pr -.- norm
    hwu = hw +.+ norm
    hwd = hw -.- norm
