module Logo.Builtins.Turtle (turtleBuiltins) where

import Prelude hiding (tan)
import qualified Data.Map as M

import Control.Monad.Trans (lift)
import Diagrams.TwoD.Path.Turtle
import Diagrams.TwoD.Types (p2)
import Data.Colour (Colour)
import Data.Colour.Names

import Logo.Types

updateTurtle :: TurtleIO a  ->  LogoEvaluator a
updateTurtle = lift

fd, bk, rt, lt, home, setxy, seth, pu, pd, setpensize, setpencolor :: [LogoToken] -> LogoEvaluator LogoToken

turtleBuiltins :: M.Map String LogoFunctionDef
turtleBuiltins = M.fromList
  [ ("fd",          LogoFunctionDef 1 fd)
  , ("bk",          LogoFunctionDef 1 bk)
  , ("rt",          LogoFunctionDef 1 rt)
  , ("lt",          LogoFunctionDef 1 lt)
  , ("home",        LogoFunctionDef 0 home)
  , ("setxy",       LogoFunctionDef 2 setxy)
  , ("seth",        LogoFunctionDef 1 seth)
  , ("pu",          LogoFunctionDef 0 pu)
  , ("pd",          LogoFunctionDef 0 pd)
  , ("setpensize",  LogoFunctionDef 1 setpensize)
  , ("setpencolor", LogoFunctionDef 1 setpencolor)
  ]

fd (NumLiteral d : []) = do
  updateTurtle (forward d)
  return $ StrLiteral ""

fd args = error $ "Invalid arguments to fd" ++ show args

bk (NumLiteral d : []) = do
  updateTurtle (backward d)
  return $ StrLiteral ""

bk _ = error "Invalid arguments to fd"

rt (NumLiteral a : []) = do
  updateTurtle (right a)
  return $ StrLiteral ""

rt _ = error "Invalid arguments to rt"

lt (NumLiteral a : []) = do
  updateTurtle (left a)
  return $ StrLiteral ""

lt _ = error "Invalid arguments to lt"

home [] = do
  updateTurtle (setPos (p2 (0,0)))
  return $ StrLiteral ""

home _ = error "Invalid arguments to home"

setxy [NumLiteral x, NumLiteral y] = do
  updateTurtle (setPos (p2 (x,y)))
  return $ StrLiteral ""

setxy _ = error "Invalid arguments to setxy"

seth [NumLiteral n] = do
  updateTurtle (setHeading n)
  return $ StrLiteral ""

seth _ = error "Invalid arguments to seth"

pu [] = do
  updateTurtle penUp
  return $ StrLiteral ""

pu _ = error "Invalid arguments to pu"

pd [] = do
  updateTurtle penDown
  return $ StrLiteral ""

pd _ = error "Invalid arguments to pd"

setpensize [NumLiteral d] = do
  updateTurtle (setPenWidth d)
  return $ StrLiteral ""

setpensize _ = error  "Invalid arguments to setpensize"

setpencolor [NumLiteral d] = do
  updateTurtle (setPenColor (numToColor . round $ d))
  return $ StrLiteral ""
 where
  numToColor :: Int -> Colour Double
  numToColor 0  = black
  numToColor 1  = blue
  numToColor 2  = green
  numToColor 3  = cyan
  numToColor 4  = red
  numToColor 5  = magenta
  numToColor 6  = yellow
  numToColor 7  = white
  numToColor 8  = brown
  numToColor 9  = tan
  numToColor 10 = forestgreen
  numToColor 11 = aqua
  numToColor 12 = salmon
  numToColor 13 = purple
  numToColor 14 = orange
  numToColor 15 = grey
  numToColor _  = error "Color values greater than 15 are not supported"

setpencolor _ = error "Invalid arguments to setpencolor"