;#lang scheme/base
;(require fluxus-016/drflux)
(require scheme/class "logic.ss" "view.ss" "controller.ss" "client.ss" "jabberer.ss" "list-utils.ss")

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; p l a n t   e y e s   
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; notes:
;
; * keeping with a view/logic separation, although this is quite different to 
;   the hexagon game. the main advantages:
;     - just a divide and conquer strategy for staying sane 
;     - able to debug the logic without the view, or vice versa
;     - the logic can be ticked at a lower frequency - or even different 
;       parts at different rates, whereas the view needs ticking every frame
;
; * need to try to keep all the intensive 'every thing vs every thing' checking 
;   in the logic side, where it can be done over many frames (i'm thinking the
;   lags involved with things like nutrients getting absorbed may not matter 
;   too much in this game)
;
; * using a message passing system to formalise the passing of information on 
;   the logic side. this makes it possible to have objects sending messages
;   at any point, and have them automatically collected up and dispatched to 
;   the view
;
; * these messages are also converted to xmpp messages and sent out over the 
;   network
;
; * line segments are computed in the logic side, and can be represented any
;   way by the view - maybe the players plant will be geometry and everyone
;   elses will be ribbons (stoopid LOD)
;
; * in the same way, the line segments can be created in any way by the logic 
;   side - eg. lsystem, or different methods per plant (or per twig even)

(define-struct player-info (jid pass tex pos col))

(define gui-game-mode%
  (class object%
    (field
     (players (list
               (make-player-info "plant0000001@fo.am" "plant0000001" 
                                 "textures/plant0000001.png" (vector 11.682296752929688 -27.272457122802734 -2.8969409465789795) (vector 0.5 1 0.5))
               (make-player-info "plant0000002@fo.am" "plant0000002" 
                                 "textures/plant0000002.png" (vector 22.92951774597168 -24.62310218811035 -4.961982727050781) (vector 0.5 1 0))
               (make-player-info "plant0000003@fo.am" "plant0000003" 
                                 "textures/plant0000003.png" (vector 11.626119613647461 -24.734521865844727 -25.146560668945312) (vector 0 1 0.5))
               (make-player-info "plant0000004@fo.am" "plant0000004" 
                                 "textures/plant0000004.png"  (vector -18.757593154907227 -10.819361686706543 37.17854690551758)(vector 0.75 1 0.5))
               (make-player-info "plant0000005@fo.am" "plant0000005" 
                                 "textures/plant0000005.png"  (vector -10.964780807495117 -20.065677642822266 23.76084327697754) (vector 0.5 1 0.75))
               ))
     (seeds '())
     (clicked -1))
    
    (define/public (get-player-info) 
      (list-ref players clicked))
        
    (define/public (setup)
      (let ((c 0))
      (set! seeds (map
                   (lambda (pi)
                     (with-state
                      (translate (vmul (vector (sin (* 2 3.141 (/ c (length players))))
                                               (cos (* 2 3.141 (/ c (length players)))) 0) 4))
                      ;(texture (load-texture (player-info-tex pi)))
                      (colour (player-info-col pi))
                      (set! c (+ c 1))
                      ;(shader "shaders/toon.vert.glsl" "shaders/toon.frag.glsl")
                      (load-primitive "meshes/seed.obj")))
                   players))))
                     
    (define/public (update t d)
      (for-each 
       (lambda (seed)
         (with-primitive seed
                         (rotate (vector 0 1 0))))
       seeds)
      (cond 
        ((mouse-button 1)
         (let ((o (mouse-over)))
           (cond
             (o
              (set! clicked (which-element o seeds 0))
              (when clicked
                (for-each 
                 (lambda (seed)
                   (destroy seed))
                 seeds))
              (if clicked #t #f))
             (else 
              #f))))
        (else
         #f)))
    
    (super-new)))


(define main-game-mode%
  (class object%
    (field
     (gl (make-object game-logic%))
     (gv (make-object game-view%))
     (c (make-object controller% gv))
     (cl #f)
     (tick-time 0)
     (player #f)
     (logic-tick 0.5)) ; time between logic updates

    (define/public (setup pi)
      (set! cl (make-object client% (player-info-jid pi) (player-info-pass pi)))
      (set! player (make-object plant-logic% 
                     (player-info-jid pi) 
                     (player-info-pos pi)                     
                     (player-info-col pi)
                     (player-info-tex pi)))
      (send c set-player-plant player)
      (send gl add-player player)
      (send c setup)
      (send gv setup)
      (send gl setup)
      (send cl setup))

    (define/public (update t d)
      (when (< tick-time t)    
        
        
        (let ((messages (send gl update)))
          ; pass the messages to the network client 
          (send gv update t d (send cl update messages gl))) ; and the game view
        
        (set! tick-time (+ t logic-tick)))
      
      (send gv update t d '())
      (send c update))
    
    (super-new)))

(clear)
(clear-shader-cache)

(define mode 'gui)
(define gui (make-object gui-game-mode%))
(define game (make-object main-game-mode%))
(send gui setup)

(define (animate)  
  (cond 
    ((eq? mode 'gui) 
     (when (send gui update (flxtime) (delta))
       (send game setup (send gui get-player-info))
       (set! mode 'game)))
    ((eq? mode 'game) 
     (send game update (flxtime) (delta)))))
    
(every-frame (animate))
