{-
===================================================================
                 ______
                / TK  / ________  ________   _________
               /     / / ____  / / ____  /  / _____  /
              /     / / /   / / / /   /_/  / /    / /
             /     / / /   / / / /  ____  / /    / /
            /     / / /   / / / /  /_  / / /    / /
           /     / / /___/ / / /____/ / / /____/ /
          /     / /_______/ /________/ /________/
         /     /_________________________________|\
        /                                          \
       /_________________________________________  /
                                                 |/
by Philip Healy                                                V1.0
===================================================================
-}

module Logo (logo) where

import Tcl



logo :: GUI ()
logo =
     do initCanvas
        initConsole

initCanvas :: GUI ()
initCanvas =
     do top <- window' ".logo" []
	title top "Turtle Canvas"
        c <- canvas' ".logo.c" [background "white", 
                             height 400, 
                             width 400]
        tcl_ ["pack .logo.c"]

initConsole :: GUI ()
initConsole = 
     do tcl_ ["toplevel .logo.w"]
        tcl_ ["wm title .logo.w \"LOGO Command Line\""]
        tcl_ ["frame .logo.w.f1"]
        tcl_ ["frame .logo.w.f2"]
        e <- edit' ".logo.w.f1.t" [width 50, height 30]
        tcl_ [".logo.w.f1.t configure -font {courier 10 bold}"]
        tcl_ ["pack .logo.w.f1"]
        tcl_ ["pack .logo.w.f1.t"]
        tcl_ ["focus .logo.w"]
        tcl_ [".logo.w.f1.t tag configure redtext -foreground red"]
        tcl_ [".logo.w.f1.t insert end " ++ "\"" ++ banner ++ "\""]
        st <- newState (St ((2000,2000),270,True) (True,"black","white") 
                       ( [] ,True,False,""))
        bind e "<Return>" (console st)
        drawTurtle st True
        putPrompt st


console :: StateRef -> GUI ()
console st =
     do getInput >>= exec st
        putPrompt st


exec :: StateRef -> String -> GUI ()
exec st str =
     do St t p (procs,ok,getting,current) <- readState st
        if (getting)
         then addACommand st (parse str) current
         else exec' st str  

exec' :: StateRef -> String -> GUI ()
exec' st str =
     do undrawTurtle
        interp st (parse str)
        isVisible st >>= \b -> drawTurtle st b

getInput :: GUI String
getInput =
     do a <- tcl [".logo.w.f1.t get",
			"\"end -2 lines linestart +1 chars\"",
			"\"end -2 chars\""]
        return a

putPrompt :: StateRef -> GUI ()
putPrompt st =
     do St p t (procs,ok,getting,current) <- readState st
        if (not getting)
         then tcl_ [".logo.w.f1.t insert end >"]
         else tcl_ [".logo.w.f1.t insert end *"]



                

banner :: String
banner = foldr1 (++) [
  "==================================================\n",
  "           ______\n",
  "          / TK  / ________  ________   _________\n",
  "         /     / / ____  / / ____  /  / _____  /\n",
  "        /     / / /   / / / /   /_/  / /    / /\n",
  "       /     / / /   / / / /  ____  / /    / /\n",
  "      /     / / /   / / / /  /_  / / /    / /\n",
  "     /     / / /___/ / / /____/ / / /____/ /\n",
  "    /     / /_______/ /________/ /________/\n",
  "   /     /_________________________________|\\\\ \n",
  "  /                                          \\\\ \n",
  " /_________________________________________  /\n",
  "                                           |/\n",
  "==================================================\n"]



--------------------------------------------------------
--                      Types.hs                      --
--        type definitions and their interfaces       --
--------------------------------------------------------



type Arg        = String
type Command    = (String,[Arg])
type Procedure  = (String,[Arg],[Command])
type Procedures = [Procedure]
 
colours :: [String]
colours = ["black",
           "blue",
           "green",
           "orange",
           "purple",
           "red",
           "white",
           "yellow"]

isAColour :: String -> Bool
isAColour str = elem str colours

type Pencolour = String
type Bgcolour  = String
type Pendown   = Bool
type Pen       = (Pendown,Pencolour,Bgcolour)

type Pos     = (Int,Int)
type Angle   = Int
type Visible = Bool
type Turtle  = (Pos,Angle,Visible)

type OK      = Bool
type Getting = Bool
type Current = String
type Procs = (Procedures,OK,Getting,Current)

data State = St Turtle Pen Procs

type StateRef = GUIRef State



--------------------------------------------------------
--                     Parser.hs                      --
--               The Logo command parser              --
--------------------------------------------------------



-- Parse function - converts a string to a command
parse :: String -> Command
parse s = parse' (toWords s)

parse' :: [String] -> Command
parse' []    = ("",[])
parse' (h:t) = (h,t)
           
-- Splits a string into a list of words
toWords :: String -> [String]
toWords [] = []
toWords s  = (getWord s) : toWords (dropSpace (dropWord s))

-- Gets the next word from a string
getWord :: String -> String
getWord []    = []
getWord (h:t)
  | elem h whitespace = []
  | otherwise         = h : getWord t

-- Removes whitespaces from around a word
dropSpace :: String -> String
dropSpace [] = []
dropSpace (h:t)
  | elem h whitespace = dropSpace t
  | otherwise         = (h:t)

-- Drops the first word from a string
dropWord :: String -> String
dropWord []    = []
dropWord (h:t) 
  | elem h whitespace = (h:t)
  | otherwise         = dropWord t

-- Whitespace definition
whitespace :: [Char]
whitespace = ['\n','\t',' ']




--------------------------------------------------------
--                                                    --
--                      Error.hs                      --
--                Prints Error Messages               --
--                                                    --
--------------------------------------------------------



err :: StateRef -> String -> GUI ()
err st str = 
     do tcl_ [".logo.w.f1.t insert end \""
               ++ str 
               ++ "\n\" redtext"]
        St t p (procs,ok,g,c) <- readState st
        writeState st (St t p (procs,False,g,c))



--------------------------------------------------------
--                                                    --
--                     Expr.hs                        --
--             Mathematical Expressions               --
--                                                    --
--------------------------------------------------------



-- Stub
isAnExpr :: [Arg] -> Bool
isAnExpr args = True


evalAnyExprs :: [Arg] -> [Arg]
evalAnyExprs []    = []
evalAnyExprs [a]   = [a]
evalAnyExprs [a,b] = [a,b]
evalAnyExprs (a:b:c:args)
  | isAnOperator b = (evalExpr [a,b,c]) : evalAnyExprs args
  | otherwise      = evalAnyExprs (b:c:args)

evalExpr :: [String] -> String
evalExpr [arg] = arg
evalExpr args  =
	evalExpr (applyOp "-" (applyOp "+" (applyOp "/" (applyOp "*" args))))

applyOp :: String -> [String] -> [String]
applyOp op []    = []
applyOp op [arg] = [arg]
applyOp op (a:b:c:args)
  | b == op   = (doOperation a b c) : applyOp op args
  | otherwise = a:b:c: (applyOp op args)

doOperation :: String -> String -> String -> String
doOperation a op b
  | op == "+" = plus     a b
  | op == "-" = minus    a b
  | op == "*" = multiply a b
  | op == "/" = divide   a b

operators :: [String]
operators = ["+","-","*","/"]

isAnOperator :: String -> Bool
isAnOperator str = elem str operators

plus :: String -> String -> String
plus a b = show ((parse_int a) + (parse_int b))

minus :: String -> String -> String
minus a b = show ((parse_int a) - (parse_int b))

multiply :: String -> String -> String
multiply a b = show ((parse_int a) * (parse_int b))

divide :: String -> String -> String
-- divide _ "0" = 
--     do tempState <- newState
--        err tempState "Division by 0"

divide a  b  = show (div (parse_int a) (parse_int b))



--------------------------------------------------------
--                   Commands.hs                      --
--                The Logo commands                   --
--------------------------------------------------------


--------------------------------------------------------
--               drawTurtle, undrawTurtle             --
--------------------------------------------------------
drawTurtle :: StateRef -> Bool -> GUI ()
drawTurtle st False = return ()
drawTurtle st b =
     do St ((x1,y1),angle,visible) (pd,pc,bg) procs <- readState st
        let x2 = getNewx x1 70 (angle - 120)
        let y2 = getNewy y1 70 (angle - 120)              
        let x3 = getNewx x1 100 angle
        let y3 = getNewy y1 100 angle
        let x4 = getNewx x1 70 (angle + 120)
        let y4 = getNewy y1 70 (angle + 120) 
        tcl_ [".logo.c create line ",
              show (fromGridded x1), show (fromGridded y1),
              show (fromGridded x2), show (fromGridded y2),
              show (fromGridded x3), show (fromGridded y3),
              show (fromGridded x4), show (fromGridded y4),
              show (fromGridded x1), show (fromGridded y1),
              " -tag turtletag"] 

undrawTurtle :: GUI ()
undrawTurtle =
     do tcl_ [".logo.c delete turtletag"]

isVisible :: StateRef -> GUI Bool
isVisible st =
     do St ((x1,y1),angle,visible) p procs <- readState st
        return visible

--------------------------------------------------------
--                forward, backward                   --
--------------------------------------------------------

forward :: StateRef -> [Arg] -> GUI ()
forward st []  = 
     do err st "Syntax Error"
forward st args
  | not (isAnExpr args)  = err st "Syntax Error"
  | otherwise            = forward' st ((parse_int (evalExpr args)) * 10)

forward' :: StateRef -> Int -> GUI ()
forward' st dis = 
     do St ((x1,y1),angle,visible) (pd,pc,bg) procs <- readState st
        let (x2,y2) = ((getNewx x1 dis angle),(getNewy y1 dis angle))
        line pd x1 y1 x2 y2 pc
        writeState st (St ((x2,y2),angle,visible) (pd,pc,bg) procs)


back :: StateRef -> [Arg] -> GUI ()
back st []  = 
     do err st "Syntax Error"
back st args
  | not (isAnExpr args)  = err st "Syntax Error"
  | otherwise            = back' st ((parse_int (evalExpr args)) * 10)

back' :: StateRef -> Int -> GUI ()
back' st dis = 
     do St ((x1,y1),angle,visible) (pd,pc,bg) procs <- readState st
        let (x2,y2) = ((getNewx x1 dis (angle - 180)),
                       (getNewy y1 dis (angle - 180)))
        line pd x1 y1 x2 y2 pc
        writeState st (St ((x2,y2),angle,visible) (pd,pc,bg) procs)


getNewx :: Int -> Int -> Int -> Int
getNewx oldx dis angle = round ((fromIntegral dis)*(cos (degToRad angle)) 
                                 + (fromIntegral oldx))

getNewy :: Int -> Int -> Int -> Int
getNewy oldy dis angle = round ((fromIntegral dis)*(sin (degToRad angle)) 
                                 + (fromIntegral oldy))

degToRad :: Int -> Float
degToRad a = (fromIntegral a) *  0.01745329251994

line :: Bool -> Int -> Int -> Int -> Int -> String -> GUI ()
line pd x1 y1 x2 y2 colour
  | (pd == True) = line' (fromGridded x1) (fromGridded y1) 
                         (fromGridded x2) (fromGridded y2) colour
  | otherwise = return () 

line' :: Int -> Int -> Int -> Int -> String -> GUI ()
line' x1 y1 x2 y2 colour =
     do tcl_ [".logo.c create line",
              show x1,
              show y1,
              show x2,
              show y2,
              "-fill", colour]

-- to convert from internal co-ordinates
-- to screen co-ordinates
fromGridded :: Int -> Int
fromGridded i = (round ((fromIntegral i)/10))

-- test if a string is numeric
-- if it isn't then parse_int will produce
-- unpredictable results
isInt :: String -> Bool
isInt str
  |(str == []) = False
  |otherwise   = isInt' str

isInt' :: String -> Bool
isInt' [] = True
isInt' (h:t)
  | ('0' <= h) && (h <= '9') = isInt' t
  | otherwise = False

--------------------------------------------------------
--                  Left & Right                      --
--------------------------------------------------------

left ::  StateRef -> [Arg] -> GUI ()
left st [] =
     do err st "Syntax Error"
left st (h:t)
  | (length t) /= 0      = err st "Syntax Error"
  | not (isInt h)        = err st "Syntax Error"
  | otherwise            = changeAngle st (-(parse_int h))

right ::  StateRef -> [Arg] -> GUI ()
right st [] =
     do err st "Syntax Error"
right st (h:t)
  | (length t) /= 0      = err st "Syntax Error"
  | not (isInt h)        = err st "Syntax Error"
  | otherwise            = changeAngle st (parse_int h)


changeAngle :: StateRef -> Angle -> GUI ()
changeAngle st a =
     do St (pos,angle,visible) p procs <- readState st
        let newAngle = roundAngle (angle + a)
        writeState st (St (pos,newAngle,visible) p procs)

roundAngle :: Angle -> Angle
roundAngle a
  | a >= 360   = roundAngle (a - 360)
  | a < 0      = roundAngle (a + 360)
  | otherwise  = a

--------------------------------------------------------
--                  penup & pendown                   --
--------------------------------------------------------

penup :: StateRef -> [Arg] -> GUI ()
penup st args
  | (length args) /= 0  = err st "Syntax Error"
  | otherwise =
     do St t (pd,pc,bg) procs <- readState st
        writeState st (St t (False,pc,bg) procs)

pendown :: StateRef -> [Arg] -> GUI ()
pendown st args
  | (length args) /= 0  = err st "Syntax Error"
  | otherwise =
     do St t (pd,pc,bg) procs <- readState st
        writeState st (St t (True,pc,bg) procs)

--------------------------------------------------------
--              showturtle,hideturtle                 --
--------------------------------------------------------

showturtle :: StateRef -> [Arg] -> GUI ()
showturtle st args
  | (length args) /= 0  = err st "Syntax Error"
  | otherwise =
     do St (pos,angle,visible) p procs <- readState st
        writeState st (St (pos,angle,True) p procs)

hideturtle :: StateRef -> [Arg] -> GUI ()
hideturtle st args
  | (length args) /= 0  = err st "Syntax Error"
  | otherwise =
     do St (pos,angle,visible) p procs <- readState st
        writeState st (St (pos,angle,False) p procs)


--------------------------------------------------------
--                    pencolour                       --
--------------------------------------------------------

pencolour ::  StateRef -> [Arg] -> GUI ()
pencolour st [] =
     do err st "Syntax Error"
pencolour st (h:t)
  | (length t) /= 0   = err st "Syntax Error"
  | not (isAColour h) = err st "Syntax Error"
  | otherwise = 
     do St t (pd,pc,bg) procs <- readState st
        writeState st (St t (pd,h,bg) procs)

--------------------------------------------------------
--                       home                         --
--------------------------------------------------------

home :: StateRef -> [Arg] -> GUI ()
home st args
  | (length args) /= 0  = err st "Syntax Error"
  | otherwise =
     do St (pos,angle,visible) pen procs <- readState st
        writeState st (St ((2000,2000),270,visible) pen procs)

--------------------------------------------------------
--                    clearscreen                     --
--------------------------------------------------------

clearscreen :: StateRef -> [Arg] -> GUI ()
clearscreen st args
  | (length args) /= 0  = err st "Syntax Error"
  | otherwise =
     do tcl_ [".logo.c delete all"]

--------------------------------------------------------
--                       exit                         --
--------------------------------------------------------

exit :: StateRef -> [Arg] -> GUI ()
exit st args
  | (length args) /= 0  = err st "Syntax Error"
  | otherwise =
     do tcl_ ["destroy .logo"]



-------------------------------------------------------
--                    Interp.hs                      --
--                Command Interpreter                --
-------------------------------------------------------



interp :: StateRef -> Command -> GUI ()
interp st (n,args) 
  | n == ""            = return ()
  | n == "back"        = back        st args
  | n == "bk"          = back        st args
  | n == "clearscreen" = clearscreen st args
  | n == "cs"          = clearscreen st args
  | n == "fd"          = forward     st args
  | n == "forward"     = forward     st args
  | n == "hideturtle"  = hideturtle  st args
  | n == "home"        = home        st args
  | n == "ht"          = hideturtle  st args
  | n == "left"        = left        st args
  | n == "lt"          = left        st args
  | n == "pd"          = pendown     st args
  | n == "pencolour"   = pencolour   st args
  | n == "pendown"     = pendown     st args
  | n == "penup"       = penup       st args
  | n == "pu"          = penup       st args
  | n == "quit"        = exit        st args
  | n == "repeat"      = startRepeat st args
  | n == "right"       = right       st args
  | n == "rt"          = right       st args
  | n == "showturtle"  = showturtle  st args
  | n == "st"          = showturtle  st args 
  | n == "to"          = addAProc    st (parse' args) 
  | otherwise          = 
     do isAProc st n 
          >>= \b -> if (b) 
                    then (execProc st (n,args))
                    else do (err st ("I don't know how to " ++ n))
                            

commandNames :: [String]
commandNames = ["back","bk","clearscreen","cs","fd","forward","hideturtle",
                "home","ht","left","lt","pd","pencolour","pendown","penup",
                "pu","quit","right","rt","showturtle","st"]

--------------------------------------------------------
--                                                    --
--                     Repeat                         --
-- This should be in the Commands module but because  --
--      HUGS doesn't allow modules to be imported     --
--          recursively it is stuck in here.          --
--                                                    --
--------------------------------------------------------

startRepeat :: StateRef -> [Arg] -> GUI ()
startRepeat st args
  | (isAnExpr (getUntilStartBrkt args)) && 
    (isBracketed (dropUntilStartBrkt args)) = startRepeat' st (parse_int (evalExpr (getUntilStartBrkt args))) (dropUntilStartBrkt args)

  | otherwise = err st "Syntax Error"


startRepeat' :: StateRef -> Int -> [Arg] -> GUI ()
startRepeat' st reps args
  | isBracketed args = repeatCommands st reps (dropBrackets args)
  | otherwise = err st "Syntax Error"

isBracketed :: [Arg] -> Bool
isBracketed [] = False
isBracketed args
  | (head args == "[") && (last args == "]") = True
  | otherwise = False

dropBrackets :: [Arg] -> [Arg]
dropBrackets [] = []
dropBrackets args = dropFirst (dropLast args) 

dropFirst :: [Arg] -> [Arg]
dropFirst []    = []
dropFirst (h:t) = t

dropLast :: [Arg] -> [Arg]
dropLast []   = []
dropLast args = take ((length args) - 1) args

repeatCommands :: StateRef -> Int -> [Arg] -> GUI ()
repeatCommands st reps args =
     do St t p (procs,ok,g,c) <- readState st
        repeatCommands' st reps (splitIntoCmds args procs)

repeatCommands' :: StateRef -> Int -> [Command] -> GUI ()
repeatCommands' st 0 cmds = do return ()
repeatCommands' st reps cmds =
     do execCommands st ("",[],cmds)
        repeatCommands' st (reps - 1) cmds

splitIntoCmds :: [Arg] -> [Procedure] -> [Command]
splitIntoCmds [] procs = []
splitIntoCmds args procs = 
  (extractNextCmd args procs) : splitIntoCmds (dropNextCmd args procs) procs

extractNextCmd :: [Arg] -> [Procedure] -> Command
extractNextCmd (h:t) procs 
  | h == "repeat" = (h,(getUntilEndBrkt t))
  | otherwise     = (h,(getUntilNextCmd t procs))

dropNextCmd :: [Arg] -> [Procedure] -> [Arg]
dropNextCmd (h:t) procs
  | h == "repeat" = dropUntilEndBrkt t
  | otherwise     = drop (length (getUntilNextCmd t procs)) t

isDefined :: String -> [Procedure] -> Bool
isDefined str procs = (isACommand str) || (isAProc' str procs)
 
getUntilNextCmd :: [Arg] -> [Procedure] -> [Arg] 
getUntilNextCmd [] procs = []
getUntilNextCmd (h:t) procs 
  | isDefined h procs = []
  | otherwise = h : getUntilNextCmd t procs

getUntilStartBrkt :: [Arg] -> [Arg]
getUntilStartBrkt [] = []
getUntilStartBrkt (h:t)
  | h == "["  = []
  | otherwise = h : getUntilStartBrkt t

dropUntilStartBrkt :: [Arg] -> [Arg]
dropUntilStartBrkt [] = []
dropUntilStartBrkt (h:t)
  | h == "["  = (h:t)
  | otherwise = dropUntilStartBrkt t


getUntilEndBrkt :: [Arg] -> [Arg]
getUntilEndBrkt [] = []
getUntilEndBrkt args
  | (last args) == "]"  = args
  | otherwise = getUntilEndBrkt (take ((length args) - 1) args)

dropUntilEndBrkt :: [Arg] -> [Arg]
dropUntilEndBrkt [] = []
dropUntilEndBrkt args
  | (last args) == "]"  = []
  | otherwise = dropUntilEndBrkt (take ((length args) - 1) args) ++ [(last args)]



isACommand :: String -> Bool
isACommand str = elem str commandNames

--------------------------------------------------------
--                                                    --
--                     Procedures                     --
--  This should be in a seperate module but because   --
--      HUGS doesn't allow modules to be imported     --
--          recursively it is stuck in here.          --
--                                                    --
--------------------------------------------------------

-- Test if a string is the name of a procedure
isAProc :: StateRef -> String -> GUI Bool
isAProc st str =
     do St turtle pen (procs,ok,g,c) <- readState st
        return (isAProc' str procs)


isAProc' :: String -> Procedures -> Bool
isAProc' str [] = False
isAProc' str ((n,vars,cmds):t)
  | n == str  = True
  | otherwise = isAProc' str t

-- Add a new procedure
addAProc :: StateRef -> Command -> GUI ()
addAProc st (n,args) =
     do St turtle pen (procs,ok,g,c) <- readState st
        writeState st (St turtle pen (((n,args,[]):procs),ok,True,n))


-- Add a command to a procedure

addACommand :: StateRef -> Command -> String -> GUI ()
addACommand st ("end",[]) _ =
     do St t p (procs,ok,getting,current) <- readState st
        writeState st (St t p (procs,ok,False,"")) 
addACommand st cmd name =  
     do St t p (procs,ok,g,c) <- readState st
        let updatedProcs = saveProc (addACommand' cmd (indexProc name procs)) procs
        writeState st (St t p (updatedProcs,ok,g,c))         

addACommand' :: Command -> Procedure -> Procedure
addACommand' new (name,vars,cmds) = (name,vars,(cmds ++ [new]))


saveProc :: Procedure -> Procedures -> Procedures
saveProc p [] = []
saveProc (name,args,cmds) ((n,a,c):t)
  | name == n = (name,args,cmds):(saveProc (name,args,cmds) t)
  | otherwise = (n,a,c):(saveProc (name,args,cmds) t)


-- Execute a procedure
execProc :: StateRef -> Command -> GUI ()
execProc st (n,args) =
     do St t p (procs,ok,g,c) <- readState st
        execProc' st (n,(evalAnyExprs args)) procs

execProc' :: StateRef -> Command -> Procedures -> GUI ()
execProc' st (name,args) procs
  | not (matchProc (name,args) procs) = 
     err st ("Arguments do not match for procedure " ++ name)
  | otherwise =
     do execCommands st (subInVars (indexProc name procs) args)

-- Execute the commands in a procedure
execCommands :: StateRef -> Procedure -> GUI ()
execCommands st (name,args,cmds) =
     do St t p (procs,ok,g,c) <- readState st
        writeState st (St t p (procs,True,g,c))
        execCommands' st cmds

execCommands' :: StateRef -> [Command] -> GUI ()
execCommands' st [] =
     do return ()
execCommands' st (h:cmds) =
     do St t p (procs,ok,g,c) <- readState st
        if (not ok)
          then return () 
          else do
                undrawTurtle
                interp st h
                isVisible st >>= \b -> drawTurtle st b
                tcl_ ["update"]
                execCommands' st cmds
        

-- Check to make sure arguments match
matchProc :: Command -> Procedures -> Bool
matchProc (name,args) [] = False
matchProc (name,args) ((n,vars,cmds):t)
  | (name == n) && ((length args) == (length vars))  = True
  | otherwise = matchProc (name,args) t


-- Index a procedure by name
indexProc :: String -> Procedures -> Procedure
indexProc str ((name,vars,cmds):t)
  | str == name = (name,vars,cmds)
  | otherwise   = indexProc str t


-- Substitute values for variables in a procedure
subInVars :: Procedure -> [Arg] -> Procedure
subInVars p [] = p
subInVars (name,(h:t),cmds) (str:args) = 
  subInVars (name,t,(replaceInCommands h str cmds)) args


-- Replace a search string in a list of commands
replaceInCommands :: String -> String -> [Command] -> [Command]
replaceInCommands var replacement [] = []
replaceInCommands var replacement (h:cmds) =
  (replaceInACommand var replacement h):
   replaceInCommands var replacement cmds

-- Replace a search string in a single command
replaceInACommand :: String -> String -> Command -> Command
replaceInACommand var replacement (n,[]) = (n,[])
replaceInACommand var replacement (n,args) =
  (n,(replaceInACommand' var replacement args))

replaceInACommand' :: String -> String -> [Arg] -> [Arg]
replaceInACommand' var replacement [] = []
replaceInACommand' var replacement (h:t)
  | var == h  = replacement:(replaceInACommand' var replacement t)
  | otherwise = h:(replaceInACommand' var replacement t)


-- 
-- parse_int
--

parse_int :: String -> Int
parse_int x = read x
