(define (new_light location color)
  (let
    ((light (make-vector 2)))
    ; TODO intern
    (vector-set! light _LIGHT_LOCATION location)
    (vector-set! light _LIGHT_COLOR color)
    (set! lights (cons light lights))
    light))

(define (get_light_color
  no_shadow
  light
  n_lights
  intersection_point shadow_intersection_point
  ray shadow_ray
  object_phong object_color object_normal)
  (if (= (shadow
           no_shadow
           intersection_point
           (vector-ref light _LIGHT_LOCATION) ; location
           shadow_intersection_point
           shadow_ray)
         1)
    (begin
      (vec_copy object_color light_color)
      (vec_scale
        (* (/ 1.0 n_lights)
          (vector-ref object_phong _PHONG_AMBIENT)) ; ambient
        light_color)) ; updates global light_color
    (begin
      (vec_copy (vector-ref light _LIGHT_LOCATION) light_location)
      (vec_sub intersection_point light_location light_direction)
      (normalize light_direction light_direction)
      (phong
        ray
        object_color
        object_phong
        object_normal
        light
        light_direction
        n_lights)))) ; updates global light_color

(define (get_color_of_all_lights
  lights
  intersection_point
  shadow_intersection_point
  no_shadow
  ray
  shadow_ray
  object_phong
  object_color
  object_normal)
  (vector-set! pixel_color _X 0.0)
  (vector-set! pixel_color _Y 0.0)
  (vector-set! pixel_color _Z 0.0)
  (if (null? lights) ; no lights assume ambient color of object
    (vec_copy object_color pixel_color)
    (let
      ((n_lights (length lights)))
      (let loop ()
        (if (not (null? lights))
          (let
            ((light (car lights)))
            (get_light_color
              no_shadow
              light
              n_lights
              intersection_point shadow_intersection_point
              ray shadow_ray
              object_phong object_color object_normal)
            (vec_add pixel_color light_color pixel_color)
            (set! lights (cdr lights))
            (loop))))))
  (clip_upper pixel_color))


(define (reflectance fraction ang)
  (let
    ((metal_fresnal 0.8))
    (* fraction
      (+ metal_fresnal (* (- 1.0 metal_fresnal) (- 1.0 (power ang 5)))))))

(define (reflect direction normal)
  (let
    ((scale (* 2.0 (dot direction normal))))
    (vec_copy normal temp)
    (vec_scale scale temp)
    (vec_sub direction temp temp)
    ; result in temp
))

(define (process_reflection
  recursion_level recursion_data
  location normal direction)
  (vec_copy normal (vector-ref recursion_data _RECURSION_NORMAL2))
  ; reverse direction of normal
  (vec_scale -1.0 (vector-ref recursion_data _RECURSION_NORMAL2))
  (reflect direction
    (vector-ref recursion_data _RECURSION_NORMAL2)) ; result in temp
  (vec_copy temp (vector-ref recursion_data _RECURSION_DIRECTION2))
  (vec_scale (* 20.0 epsilon) temp) ; get off surface reduces jitteriness
  (vec_add location temp (vector-ref recursion_data _RECURSION_LOCATION2))
  (update_ray
    (vector-ref recursion_data _RECURSION_RAY)
    (vector-ref recursion_data _RECURSION_LOCATION2)
    (vector-ref recursion_data _RECURSION_DIRECTION2))
  (update_intersection_object
    (vector-ref recursion_data _RECURSION_INTERSECTION_OBJECT))
  (ray_traverse_octree
    0 octree
    (vector-ref recursion_data _RECURSION_RAY)
    (vector-ref recursion_data _RECURSION_DIRECTION2)
    (vector-ref recursion_data _RECURSION_INTERSECTION_OBJECT))
  (get_pixel_color
    (+ recursion_level 1)
    (vector-ref recursions (+ recursion_level 1))
    (vector-ref
      (vector-ref recursion_data _RECURSION_INTERSECTION_OBJECT)
      _INTERSECTION_OBJECT_DISTANCE)
    (vector-ref
      (vector-ref recursion_data _RECURSION_INTERSECTION_OBJECT)
      _INTERSECTION_OBJECT_SCENE_OBJECT)
    (vector-ref
      (vector-ref recursion_data _RECURSION_INTERSECTION_OBJECT)
      _INTERSECTION_OBJECT_MIN_POINT)
    intersection_point
    (vector-ref recursion_data _RECURSION_RAY)
    (vector-ref recursion_data _RECURSION_SHADOW_RAY))
  (apply_fog ; updates fog_pixel_color
    (vector-ref
      (vector-ref recursion_data _RECURSION_INTERSECTION_OBJECT)
      _INTERSECTION_OBJECT_DISTANCE)
    pixel_color)
  (vec_copy
    fog_pixel_color
      (vector-ref recursion_data _RECURSION_REFLECTION_PIXEL_COLOR))
  ; return pixel color
  (vector-ref recursion_data _RECURSION_REFLECTION_PIXEL_COLOR))

(define (get_shader_color color intersection_point)
  (let
    ((len (vector-ref color _COLOR_LEN))
     (color_1 (vector-ref color _COLOR1))
     (color_2 (vector-ref color _COLOR2)))
    (if (= len 0.0)
      color_1
      ; else get color choice from checker pattern
      (if (= (remainder (+
        (inexact->exact (floor (/ (vector-ref intersection_point _X) len)))
        (inexact->exact (floor (/ (vector-ref intersection_point _Y) len)))
        (inexact->exact (floor (/ (vector-ref intersection_point _Z) len))))
        2) 0)
        color_2
        color_1))))

(define (get_pixel_color
  recursion_level
  recursion_data
  distance
  scene_object
  intersection_point
  shadow_intersection_point
  ray
  shadow_ray)
  (if (= distance infinite)
    (vec_copy background_color pixel_color)
    (let
      ((object_color
         (get_shader_color
           (vector-ref
             (vector-ref scene_object _SCENE_OBJECT_SHADER) _SHADER_COLOR)
           intersection_point))
       (object_phong
         (vector-ref
           (vector-ref scene_object _SCENE_OBJECT_SHADER) _SHADER_PHONG))
       (object_reflection
         (vector-ref
           (vector-ref scene_object _SCENE_OBJECT_SHADER) _SHADER_REFLECTION))
       (no_shadow
         (vector-ref
           (vector-ref scene_object _SCENE_OBJECT_SHADER) _SHADER_NO_SHADOW)))
      (get_normal scene_object intersection_point)
      (vec_copy normal (vector-ref recursion_data _RECURSION_NORMAL))
      ; TODO get color from decal
      (if (or (= object_reflection 0.0) (= recursion_level 95))
        ; no reflection or max number of reflections
        (get_color_of_all_lights
          lights
          intersection_point
          shadow_intersection_point
          no_shadow
          ray
          shadow_ray
          object_phong
          object_color
          (vector-ref recursion_data _RECURSION_NORMAL))
        ; else reflection
        (let
          ((reflection_pixel_color '()))
          (normalize (vector-ref ray _RAY_DIRECTION) temp)
          (let
            ((reflectance_factor
              (reflectance object_reflection
                (dot (vector-ref recursion_data _RECURSION_NORMAL) temp))))
            ; recursion intersection point
            (vec_copy intersection_point
              (vector-ref recursion_data _RECURSION_INTERSECTION_POINT))
            (set! reflection_pixel_color
              (process_reflection
                recursion_level
                recursion_data
                intersection_point
                (vector-ref recursion_data _RECURSION_NORMAL)
                (vector-ref ray _RAY_DIRECTION)))
            (vec_scale reflectance_factor reflection_pixel_color)
            (get_color_of_all_lights
              lights
              (vector-ref recursion_data _RECURSION_INTERSECTION_POINT)
              shadow_intersection_point
              no_shadow
              ray
              shadow_ray
              object_phong
              object_color
              (vector-ref recursion_data _RECURSION_NORMAL))
            (vec_add reflection_pixel_color pixel_color pixel_color)
            (clip_upper pixel_color)))))))
    ; updates pixel_color