--{-# LANGUAGE TupleSections #-}
module Dodge.Room.Foreground where
import Picture
import Geometry
import Geometry.Vector3D
import Shape
import Quaternion

import Data.List
import Data.Maybe

highDiagonalMesh
    :: Point2 
    -> Point2 
    -> Float    -- ^ width
    -> Float    -- ^ vertical distance between lines
    -> Picture
highDiagonalMesh pa pb w d = setDepth (-0.2) $ pictures $
    map (flip thickLine 3 . tflat2) (diagonalLinesRect pb pa w d (3*pi/4))
    ++ 
    map (flip thickLine 3 . tflat2) (diagonalLinesRect pb pc (negate h) d (pi/4))
  where
    pc = pb +.+ w *.* normalizeV (vNormal (pb -.- pa))
    h = dist pa pb

diagonalLinesRect 
    :: Point2 
    -> Point2 
    -> Float    -- ^ width
    -> Float    -- ^ vertical distance between lines
    -> Float
    -> [(Point2,Point2)]
diagonalLinesRect pa pb w d ang = zip lhsPoints $ map findDiPoint lhsPoints
  where
    xVec = negate w *.* vNormal (normalizeV $ pb -.- pa)
    diVec = rotateV ang xVec
    pax = pa +.+ xVec
    pbx = pb +.+ xVec
    lhsPoints = divideLineExact d (pa -.- yN) (pb +.+ yN)
    findDiPoint p = head . sortOn (dist p) $ catMaybes 
        [intersectLineLine' p (p +.+ diVec) pax pbx
        ,intersectSegLine pa pax p (p +.+ diVec)
        ,intersectSegLine pb pbx p (p +.+ diVec)
        ]
    yN = d * 0.5 *.* normalizeV (pa -.- pb)

thinHighBar :: Float -> Point2 -> Point2 -> Shape
thinHighBar = highBar 3

thinHighBarLoop :: Float -> [Point2] -> Shape
thinHighBarLoop h = foldMap (uncurry $ thinHighBar h) . loopPairs

thinHighBarChain :: Float -> [Point2] -> Shape
thinHighBarChain h = foldMap (uncurry $ thinHighBar h) . chainPairs

thickHighBar :: Float -> Point2 -> Point2 -> Shape
thickHighBar = highBar 5

highBar :: Float -> Float -> Point2 -> Point2 -> Shape
highBar thickness h x y = translateSHz h $ colorSH orange $ upperPrismPoly thickness
    [x +.+ n, y +.+ n, y -.- n, x -.- n]
  where
    n = 0.5 * thickness *.* normalizeV (vNormal (y -.- x))

highPipe :: Float -> Point2 -> Point2 -> Shape
highPipe h x y = colorSH orange $ prismPoly
    (map (addZ (h + 5)) [x +.+ n2, y +.+ n2, y -.- n2, x -.- n2])
    (map (addZ h)       [x +.+ n, y +.+ n, y -.- n, x -.- n]    )
  where
    n2 = 1.25 *.* normalizeV (vNormal (y -.- x))
    n = 2.5 *.* normalizeV (vNormal (y -.- x))

girderZ 
    :: Float -- ^ height
    -> Float -- ^ distance between cross bars
    -> Float -- ^ width
    -> Point2 -> Point2 -> Shape
girderZ h d w x y = colorSH red $ mconcat $
    [ thinHighBar h xt yt
    , thinHighBar h xb yb
    ]
    <> zipWith (thinHighBar (h- 1)) ps qs
  where
    n = w *.* normalizeV (vNormal $ y -.- x)
    xb = x +.+ n
    yb = y +.+ n
    xt = x -.- n
    yt = y -.- n
    ps = divideLineExact d xb yb
    qs = tail $ divideLineExact d xt yt

girderV 
    :: Float -- ^ height
    -> Float -- ^ distance between cross bars
    -> Float -- ^ width
    -> Point2 -> Point2 -> Shape
girderV h d w x y = colorSH red $ mconcat $
    [ thinHighBar h xt yt
    , thinHighBar h xb yb
    ]
    <> zipWith (thinHighBar (h- 1)) ps qs
  where
    n = w *.* normalizeV (vNormal $ y -.- x)
    xb = x +.+ n
    yb = y +.+ n
    xt = x -.- n
    yt = y -.- n
    ps = evenDouble $ divideLineExact d xb yb
    qs = head qs' : evenDouble(tail qs')
      where
        qs' = divideLineExact d xt yt
    evenDouble (a:_:xs) = a:a:evenDouble xs
    evenDouble xs = xs

girderCol
    :: Color
    -> Float -- ^ height
    -> Float -- ^ distance between cross bars
    -> Float -- ^ width
    -> Point2 -> Point2 -> Shape
girderCol col h d w x y = colorSH col $ mconcat $
    [ thinHighBar h xt yt
    , thinHighBar h xb yb
    ]
    <> zipWith (thinHighBar (h- 1)) ps qs
  where
    n = w *.* normalizeV (vNormal $ y -.- x)
    xb = x +.+ n
    yb = y +.+ n
    xt = x -.- n
    yt = y -.- n
    ps = divideLineExact d xb yb
    qs = divideLineExact d xt yt

girder 
    :: Float -- ^ height
    -> Float -- ^ distance between cross bars
    -> Float -- ^ width
    -> Point2 -> Point2 -> Shape
girder = girderCol orange

robotArm :: Shape
robotArm = undefined

barPP :: Float -> Point3 -> Point3 -> Shape
barPP w a b 
    | a == b = mempty
    | otherwise = prismPoly
        (map ((+.+.+ a) . rotateToZ z1 . addZ 0) $ polyCirc 2 w)
        (map ((+.+.+ b) . rotateToZ z1 . addZ 0) $ polyCirc 2 w)
  where
    z1 = b -.-.- a

pipePP :: Float -> Point3 -> Point3 -> Shape
pipePP w a b = prismPoly
    (map ((+.+.+ a) . rotateToZ z1 . addZ 0) $ polyCirc 4 w)
    (map ((+.+.+ b) . rotateToZ z1 . addZ 0) $ polyCirc 4 w)
  where
    z1 = b -.-.- a
    
tankTopPipe :: Shape
tankTopPipe = colorSH orange $ 
    upperPrismPoly 31 (polyCirc 4 20)
    <> prismPoly 
        (map (addZ 41) $ polyCirc 4 5)
        (map (addZ 31) $ polyCirc 4 20)
--    <> pipePP 5 (V3 0 0 51) (V3 0 0 41)
