-- | Standard 'Turtle' graphics.
module LSystem.Turtle where

import Data.CG.Minus {- hcg-minus -}

-- | Turtle.
data Turtle = Turtle {ta :: Double -- ^ turning angle
                     ,tai :: Double -- ^ turning angle increment
                     ,loc :: Pt Double -- ^ location
                     ,hdg :: Double -- ^ heading
                     ,ll :: Double -- ^ line length
                     ,lls :: Double -- ^ line length scalar
                     ,stk :: [Turtle] -- ^ turtle stack
                    } -- lw = line width,lwi = line width increment,

-- | Right turn by 'ta'.
turnRight :: Turtle -> Turtle
turnRight t = t {hdg = hdg t + (ta t)}

-- | Left turn by 'ta'.
turnLeft :: Turtle -> Turtle
turnLeft t = t {hdg = hdg t - (ta t)}

-- | @180@ degree turn.
turnBack :: Turtle -> Turtle
turnBack t = t {hdg = hdg t + pi}

-- | Increment line length ('ll') by multiplying by line length scalar
-- ('lls').
incrLine :: Turtle -> Turtle
incrLine t = t {ll = ll t * lls t}

-- | Decrement line length ('ll') by dividing by line length scalar
-- ('lls').
decrLine :: Turtle -> Turtle
decrLine t = t {ll = ll t / lls t}

-- | Move 'loc' of 'Turtle' by 'll' on current 'hdg'.
forward :: Turtle -> Turtle
forward t =
    let shift (Pt x y) r d = Pt (x + r * cos d) (y + r * sin d)
    in t {loc = shift (loc t) (ll t) (hdg t)}

-- | Push 'Turtle' onto 'stk'.
push :: Turtle -> Turtle
push t = t {stk = t : stk t}

-- | Fetch 'Turtle' from 'stk'.
pop :: Turtle -> Turtle
pop t = head (stk t)

-- | Given state processing function /f/, a 'Turtle' and an initial
-- state, step 'Turtle' and state.
stepTurtle :: (t -> Pt R -> Pt R -> b) -> Turtle -> t -> (Turtle,b)
stepTurtle f t i =
    let p  = loc  t
        t' = forward t
        p' = loc  t'
        i' = f i p p'
    in (t',i')