// References to Mono's Gtk# library for MonoDevelop on Linux
#r "/usr/lib/cli/atk-sharp-2.0/atk-sharp.dll"
#r "/usr/lib/cli/glib-sharp-2.0/glib-sharp.dll"
#r "/usr/lib/cli/gdk-sharp-2.0/gdk-sharp.dll"
#r "/usr/lib/cli/gtk-sharp-2.0/gtk-sharp.dll"
// References to Mono's Gtk# library for Xamarin Studio on Mac
//#I "/Library/Frameworks/Mono.framework/Versions/3.10.0/lib/mono/gtk-sharp-2.0"
//#r "gdk-sharp.dll"
//#r "gtk-sharp.dll"
// References to Mono's Gtk# library for Xamarin Studio on Windows
//#I "C:/Program Files (x86)/GtkSharp/2.12/lib/gtk-sharp-2.0"
//#r "gdk-sharp.dll"
//#r "gtk-sharp.dll"

open Gtk
open System

/// Abstract Syntax Tree
module AST =
   type distance = int
   type degrees = int
   type count = int
   type command =
      | Forward of distance
      | Left of degrees
      | Right of degrees
      | Repeat of count * command list

open AST

// Turtle Type
type Turtle = { X:float; Y:float; A:int }

let width, height = 500, 500

let execute commands drawLine =
   let turtle = { X=float width/2.0; Y=float height/2.0; A = -90 }
   let rec perform turtle = function
      | Forward n ->
         let r = float turtle.A * Math.PI / 180.0
         let dx, dy = float n * cos r, float n * sin r
         let x, y =  turtle.X, turtle.Y
         let x',y' = x + dx, y + dy
         drawLine (x,y) (x',y')
         { turtle with X = x'; Y = y' }
      | Left n -> { turtle with A=turtle.A + n }
      | Right n -> { turtle with A=turtle.A - n }
      | Repeat(n,commands) ->
         let rec repeat turtle = function
            | 0 -> turtle
            | n -> repeat (performAll turtle commands) (n-1)
         repeat turtle n
   and performAll = List.fold perform
   performAll turtle commands |> ignore

let show commands =
   let window = new Window("Turtle")
   window.SetDefaultSize(width, height)
   window.DeleteEvent.Add(fun e -> window.Hide(); Application.Quit(); e.RetVal <- true)
   let drawing = new Gtk.DrawingArea()
   drawing.ExposeEvent.Add( fun x ->
       let gc = drawing.Style.BaseGC(StateType.Normal)
       let allocColor (r,g,b) =
          let col = ref (Gdk.Color(r,g,b))
          let _ = gc.Colormap.AllocColor(col, true, true)
          !col
       gc.Foreground <- allocColor (255uy,0uy,0uy)
       let drawLine (x1,y1) (x2,y2) =
            drawing.GdkWindow.DrawLine(gc, int x1, int y1, int x2, int y2) 
       execute commands drawLine
       )
   window.Add(drawing)
   window.ShowAll()
   window.Show()

let invoke action =   
    Application.Init()
    Application.Invoke(fun _ _ -> action())
    Application.Run()

let commands = [for i in 1..1000 do yield! [Forward 6; Right(i*7)]]
invoke (fun () -> show commands)