// Lispyscript port of Hot Cocoa Lisp Mandelbrot example found here:
// https://github.com/olleicua/hcl-canvas-mandelbrot/blob/master/mandelbrot.hcl

(var canvas (first (document.getElementsByTagName "canvas")))
(var ctx (canvas.getContext "2d"))

(set canvas.height window.innerHeight)
(set canvas.width window.innerWidth)

//(function square (x) (* x x))
(macro square (x) (* ~x ~x))

(function mandelbrot (r i maxIter) {
 (var iter 0)
 (var zr r) (var zi i) // z = c
 (var zr_sq (square r)) (var zi_sq (square i)) // zi_sq and zr_sq
 (var loop 1) // max orbit size to check for
 (var lr 0) (var li 0) // orbit checker
 (while (! (|| (=== iter maxIter) (&& (=== lr zr) (=== li zi)) (<= 4 (+ zr_sq zi_sq))))
   ++iter
   (if (=== loop iter) {
     (set lr zr) 
     (set li zi) 
     (+= loop loop) // grow loop
   })
   (set zr_sq (square zr)) (set zi_sq (square zi)) // zi_sq and zr_sq
   (*= zi zr) (+= zi zi) (+= zi i) // zi = 2*zi*zr + ci
   (set zr (- zr_sq zi_sq)) (+= zr r)) // zr = zr_sq - zi_sq + cr
 (if? (|| (=== iter maxIter) (&& (=== lr zr) (=== li zi))) null iter)
})

(function color (n)
  (if? (nil? n) "rgb(0,0,0)" (do
      (set n (% (* 32 n) 768))
      (var rgb (cond
        (< n 256) [ (- 255 n) n 0 ]
        (< n 512) [ 0 (- 511 n) (- n 256) ]
        true [ (- n 512) 0 (- 767 n) ]))
      "rgb(${(get 0 rgb)},${(get 1 rgb)},${(get 2 rgb)})"
  )))

(var params { r: 0 i: 0 range: 4 maxIter: 30 })

(function half (x) (/ x 2))

(function draw ()
  (dotimes (r, canvas.width)
    (dotimes (i, canvas.height)
      (var calc
        (mandelbrot
          (+ (/ (* params.range r) canvas.width)
            (half (- params.range)) params.r)
          (+ (/ (* params.range i) canvas.height)
            (half (- params.range)) params.i)
          params.maxIter))
      (set ctx.fillStyle (color calc))
      (ctx.fillRect r i 1 1))))

(draw)

(document.addEventListener
  "keyup" (e) => (switch e.keyCode
      ; q
      81 {
        (*= params.range (/ 2 3))
        ++params.maxIter
        (draw)
        (break)
      }
      ; w
      87 {
        (-= params.i (/ params.range 3))
        (draw)
        (break)
      }
      ; e
      69 {
        (*= params.range (/ 3 2))
        --params.maxIter
        (draw)
        (break)
      }
      ; a
      65 {
        (-= params.r (/ params.range 3))
        (draw)
        (break)
      }
      ; s
      83 {
        (+= params.i (/ params.range 3))
        (draw)
        (break)
      }
      ; d
      68 {
        (+= params.r (/ params.range 3))
        (draw)
        (break)
      }))

