(local pxl8 (require :pxl8))
(local menu (require :mod.menu))
(local music (require :mod.music))
(local first_person3d (require :mod.first_person3d))

(var time 0)
(var active-demo :logo)
(var particles nil)
(var fire-init? false)
(var rain-init? false)
(var snow-init? false)
(var first_person3d-init? false)
(var use-famicube-palette? false)

(var logo-x 256)
(var logo-y 148)
(var logo-dx 100)
(var logo-dy 80)
(var logo-sprite nil)
(var transition nil)
(var transition-pending nil)

(fn switch-demo [new-demo]
  (when (and (not= active-demo new-demo) (not transition))
    (set transition-pending new-demo)
    (set transition (pxl8.create_transition :pixelate 0.5))
    (transition:set_color 0xFF000000)
    (transition:start)))

(global init (fn []
  (pxl8.load_palette "res/sprites/pxl8_logo.ase")
  (set logo-sprite (pxl8.load_sprite "res/sprites/pxl8_logo.ase"))
  (set particles (pxl8.create_particles 1000))
  (music.init)))

(global update (fn [dt]
  (when (pxl8.key_pressed "escape")
    (menu.toggle)
    (when (= active-demo :first_person3d)
      (pxl8.set_relative_mouse_mode (not (menu.is-paused)))))

  (when (not (menu.is-paused))
    (set time (+ time dt))

    (when transition
      (transition:update dt)
      (when (transition:is_complete)
        (when transition-pending
          (when (and (= active-demo :first_person3d) (not= transition-pending :first_person3d))
            (pxl8.set_relative_mouse_mode false))
          (when (and (not= active-demo :first_person3d) (= transition-pending :first_person3d))
            (pxl8.set_relative_mouse_mode true))
          (set active-demo transition-pending)
          (set transition-pending nil)
          (when (= active-demo :fire) (set fire-init? false))
          (when (= active-demo :rain) (set rain-init? false))
          (when (= active-demo :snow) (set snow-init? false))
          (when (= active-demo :first_person3d) (set first_person3d-init? false)))
        (transition:destroy)
        (set transition nil)))

    (when (pxl8.key_pressed "1") (switch-demo :logo))
    (when (pxl8.key_pressed "2") (switch-demo :plasma))
    (when (pxl8.key_pressed "3") (switch-demo :tunnel))
    (when (pxl8.key_pressed "4") (switch-demo :raster))
    (when (pxl8.key_pressed "5") (switch-demo :fire))
    (when (pxl8.key_pressed "6") (switch-demo :rain))
    (when (pxl8.key_pressed "7") (switch-demo :snow))
    (when (pxl8.key_pressed "8") (switch-demo :first_person3d))
    (when (pxl8.key_pressed "=")
      (set use-famicube-palette? (not use-famicube-palette?))
      (local palette-path (if use-famicube-palette? "res/palettes/famicube.ase" "res/sprites/pxl8_logo.ase"))
      (pxl8.load_palette palette-path))

    (music.update dt)

    (case active-demo
      :logo (do
              (set logo-x (+ logo-x (* logo-dx dt)))
              (set logo-y (+ logo-y (* logo-dy dt)))
              (when (< logo-x 0)
                (set logo-x 0)
                (set logo-dx (math.abs logo-dx)))
              (when (> logo-x 512)
                (set logo-x 512)
                (set logo-dx (- (math.abs logo-dx))))
              (when (< logo-y 0)
                (set logo-y 0)
                (set logo-dy (math.abs logo-dy)))
              (when (> logo-y 296)
                (set logo-y 296)
                (set logo-dy (- (math.abs logo-dy)))))
      :first_person3d (do
                        (when (not first_person3d-init?)
                          (first_person3d.init)
                          (set first_person3d-init? true))
                        (first_person3d.update dt)))

    (when particles
      (particles:update dt)))

  (when (menu.is-paused)
    (menu.update))))

(global frame (fn []
  (case active-demo
    :logo (do
            (pxl8.clear 0)
            (when logo-sprite
              (pxl8.sprite logo-sprite logo-x logo-y 128 64 (< logo-dx 0) (< logo-dy 0))))

    :plasma (do
              (pxl8.clear 0)
              (pxl8.text "Plasma (TODO: Fennel impl)" 200 170 1))

    :tunnel (do
              (pxl8.clear 0)
              (pxl8.text "Tunnel (TODO: Fennel impl)" 200 170 1))

    :raster (do
              (pxl8.clear 0)
              (pxl8.text "Raster Bars (TODO: Fennel impl)" 180 170 1))

    :fire (do
            (pxl8.clear 0)
            (when particles
              (when (not fire-init?)
                (particles:clear)
                (particles:set_position 320 360)
                (particles:set_spread 320 0)
                (particles:set_gravity 0 -80)
                (particles:set_drag 0.98)
                (particles:set_turbulence 60)
                (particles:set_spawn_rate 200)
                (particles:set_colors 1 9)
                (particles:set_life 2.0 5.0)
                (particles:set_velocity -30 30 -120 -60)
                (set fire-init? true))
              (particles:render)))

    :rain (do
            (pxl8.clear 0)
            (when particles
              (when (not rain-init?)
                (particles:clear)
                (particles:set_position 320 -10)
                (particles:set_spread 340 0)
                (particles:set_gravity 30 80)
                (particles:set_drag 1.0)
                (particles:set_turbulence 5)
                (particles:set_spawn_rate 500)
                (particles:set_colors 20 22)
                (particles:set_life 2.0 3.0)
                (particles:set_velocity -20 20 400 600)
                (set rain-init? true))
              (particles:render)))

    :snow (do
            (pxl8.clear 0)
            (when particles
              (when (not snow-init?)
                (particles:clear)
                (particles:set_position 320 -10)
                (particles:set_spread 340 0)
                (particles:set_gravity 0 25)
                (particles:set_drag 1.0)
                (particles:set_turbulence 100)
                (particles:set_spawn_rate 100)
                (particles:set_life 8.0 12.0)
                (particles:set_colors 10 15)
                (particles:set_velocity -50 50 30 50)
                (set snow-init? true))
              (particles:render)))

    :first_person3d (first_person3d.frame)


    _ (pxl8.clear 0))

  (when transition
    (transition:render))

  (when (menu.is-paused)
    (menu.draw))))
