#lang racket
(require gigls/unsafe)
;;; Procedure:
;;;   fibonacci-numbers
;;; Parameters:
;;;   n, a positive integer
;;; Purpose:
;;;   Computes a list containing all fibonacci numbers until the nth non-zero term in the list.
;;; Produces:
;;;  fibonacci-numbers-list, a list
;;; Preconditions:
;;;   fibonacci-numbers-helper is defined
;;;   cadr is defined.
;;; Postconditions:
;;;   For any three consecutive values in fibonacci-numbers-list a1 a2 and a3, (+ a1 a2) is a3.
;;;   That is, for any integer q greater than or equal to 1, (equal? (+ (list-ref fibonacci-numbers (- q 1)) ((list-ref fibonacci-numbers q))) (list-ref fibonacci-numbers (+ q 1)))
;;;  (equal? (+ (list-ref fibonacci-numbers (- q 1)) ((list-ref fibonacci-numbers q))) (list-ref fibonacci-numbers (+ q 1))) would return #t.

(define fibonacci-numbers
  (λ (n)
    (fibonacci-numbers-helper n null)))
(define fibonacci-numbers-helper
  (λ (n lst)
    (cond [(> n 1) (cons 
                    (+ (car (fibonacci-numbers-helper (- n 1) lst))
                       (cadr (fibonacci-numbers-helper (- n 1) lst)))
                    (fibonacci-numbers-helper (- n 1) lst))]
          [(equal? n 1) (list 1 0)]
          [else (list 0)])))

;  These procedures, and their following helpers, I derived from the reading "Turtle Graphics," by Jerod Weinman.
;;; Procedure:
;;;   turtle-quarter-circle-cw!
;;; Parameters:
;;;   rad, a positive integer
;;;   turtle, a turtle
;;; Purpose:
;;;   Creates a clockwise quarter-section of a circle of radius rad.
;;; Produces:
;;; [None, called for side-effect]
;;; Preconditions:
;;;   turtle is defined
;;;   The image upon which turtle resides is open and is defined.
;;;   repeat is defined.
;;; Postconditions:
;;;   Image produced upon the image upon which turtle resides is the quarter-section of a circle that is desired.

(define turtle-quarter-circle-cw!
  (λ (rad turtle)
    (repeat 45 turtle-quarter-circle-helper-cw! rad turtle)))


(define turtle-quarter-circle-helper-cw!
  (λ (rad turtle)
    (turtle-forward! turtle (/ (/ (* 2 rad pi) 4) 45))
    (turtle-turn! turtle 2)))

;;; Procedure:
;;;   turtle-quarter-circle-cw!
;;; Parameters:
;;;   rad, a positive integer
;;;   turtle, a turtle
;;; Purpose:
;;;   Creates a counter-clockwise quarter-section of a circle of radius rad.
;;; Produces:
;;; [None, called for side-effect]
;;; Preconditions:
;;;   turtle is defined
;;;   The image upon which turtle resides is open and is defined.
;;;   repeat is defined.
;;; Postconditions:
;;;   Image produced upon the image upon which turtle resides is the quarter-section of a circle that is desired.

(define turtle-quarter-circle-ccw!
  (λ (rad turtle)
    (repeat 45 turtle-quarter-circle-helper-ccw! rad turtle)))


(define turtle-quarter-circle-helper-ccw!
  (λ (rad turtle)
    (turtle-forward! turtle (/ (/ (* 2 rad pi) 4) 45))
    (turtle-turn! turtle -2)))
;This procedure was created with the assistance of the tutor Alex Greenberg and Professor Jerod Weinman.

;;; Procedure:
;;;   weird-quart-ccwn!
;;; Parameters:
;;;   rad, a positive integer
;;;   n, a positive integer
;;;   turtle, a turtle
;;; Purpose:
;;;   Creates a fractal quarter circle made up of n quarter circles.
;;; Produces:
;;; [None, called for side-effect]
;;; Preconditions:
;;;   turtle is defined
;;;   The image upon which turtle resides is open and is defined.
;;;   even? and odd? are defined
;;;   turtle-quarter-circle-cw! and turtle-quarter-circle-ccw! are defined.
;;;  turtle-turn! is defined.
;;; Postconditions:
;;;   Image is as desired, such that the radius of the figure is rad, and the radius of each of the smaller quarter circles creating the figure is (/ rad n).
;;;   Each quarter circle is in the opposite direction of the subsequent and prior quarter circle, except the end quarter circles, which are in the opposite direction
;;;   of the quarter circle "touching" them.
;;;   The final direction of turtle is the same as if (turtle-quarter-circle-ccw! rad turtle) were called.

(define weird-quart-ccwn!
  (λ (rad fractal-num turtle)
    (cond
      ((even? fractal-num)
       (let kernel2 ((iter fractal-num)) 
         (cond
           ((<= iter 1)
            (turtle-quarter-circle-cw! (/ rad fractal-num) turtle))
           ((even? iter)
            (turtle-quarter-circle-ccw! (/ rad fractal-num) turtle)
            (kernel2 (- iter 1)))
           (else
            (turtle-quarter-circle-cw! (/ rad fractal-num) turtle)
            (kernel2 (- iter 1))))))   
      (else
       (let kernel ((iter fractal-num)) 
         (cond
           ((<= iter 1)
            (turtle-quarter-circle-ccw! (/ rad fractal-num) turtle))
           ((even? iter)
            (turtle-quarter-circle-cw! (/ rad fractal-num) turtle)
            (kernel (- iter 1)))
           (else
            (turtle-quarter-circle-ccw! (/ rad fractal-num) turtle)
            (kernel (- iter 1)))))))
    (when
        (even? fractal-num)
      (turtle-turn! turtle -90))))

;  Was advised by Alex Greenberg for this procedure.

;;; Procedure:
;;;   fibonacci-spirals-fract!
;;; Parameters:
;;;   n, a positive integer
;;;   width, a positive integer
;;;   height, a positive integer
;;;   base, a positive integer
;;;   direction, a positive integer
;;;   turtle, a turtle
;;; Purpose:
;;;   Creates a fibonacci spiral and a corresponding fractal fibonacci-spiral that begin and end at the same points and in the same direction,
;;;   the direction which they begin spiralling in corresponding to direction, where direction is an integer corresponding to the degrees from 0.
;;; Produces:
;;; [None, called for side-effect]
;;; Preconditions:
;;;   turtle is defined
;;;   The image upon which turtle resides is open and is defined.
;;;   mod is defined.
;;;   direction is inclusively between 0 and 359.
;;;   turtle-face!, turtle-teleport, and turtle-set-color are defined.
;;; Postconditions:
;;;   Image is as desired.

(define fibonacci-spirals-fract!
  (λ (n width height base direction turtle)
    (let* ((k (+ 5 (mod n 4))) (fractal-num (+ 1 (mod n base))) (scaling-factor (cond
                                                                     [(equal? k 5)
                                                                      21]
                                                                     [(equal? k 6)
                                                                      31]
                                                                     [(equal? k 7)
                                                                      50]
                                                                     [(equal? k 8)
                                                                      13]))
                                           (lst3 (reverse (fibonacci-numbers (+ 1 k)))) (lst4 (map (l-s * (/ (min width height) 
                                                    scaling-factor)) lst3)) (color (irgb (mod (round (* (mod n 33) n)) 255) (mod (round (* (mod n 28) n)) 255) (mod (round (* (mod n 31) n)) 255))))
      (turtle-set-color! turtle color)
      (turtle-teleport! turtle (/ width 2) (/ height 2))
      (turtle-face! turtle direction)
      (for-each (lambda (rad) 
                    (weird-quart-ccwn! rad 1 turtle)) lst4)
      (turtle-teleport! turtle (/ width 2) (/ height 2))
      (turtle-face! turtle direction)
        (for-each (lambda (rad) 
                    (weird-quart-ccwn! rad fractal-num turtle)) lst4))))

;;; Procedure:
;;;   ellipse-background!
;;; Parameters:
;;;   n, a positive integer
;;;   width, a positive integer
;;;   height, a positive integer
;;;   image, an image
;;; Purpose:
;;;   Creates an ellipse from a drawing that is of width width and height height.
;;; Produces:
;;; [None, called for side-effect]
;;; Preconditions:
;;;   image is defined.
;;;   let* is defined
;;;   mod is defined
;;; Postconditions:
;;;   The ellipse is as desired.

(define ellipse-background!
  (λ (n width height image)
    (let* ((color (irgb (mod (+ 128 (* (mod n 33) n)) 255) (mod (+ 128 (* (mod n 28) n)) 255) (mod (+ 128 (* (mod n 31) n)) 255))) (ellipse (hshift-drawing (/ width 2) (vshift-drawing (/ height 2) (hscale-drawing width (vscale-drawing height (recolor-drawing color drawing-unit-circle)))))))
    (drawing-render! ellipse image))))

;;; Procedure:
;;;   image-series
;;; Parameters:
;;;   n, a positive integer
;;;   width, a positive integer
;;;   height, a positive integer
;;;   image, an image
;;; Purpose:
;;;   Creates an image upon which fibonacci-spirals and fibonacci-fractal-spirals lie upon an ellipse background that fits the width and height.
;;; Produces:
;;; [None, called for side-effect]
;;; Preconditions:
;;;   let* is defined
;;;   turtle-set-brush! is defined
;;;   fibonacci-spirals-fract! is defined.
;;;   ellipse-background! is defined.
;;; Postconditions:
;;;   The desired image is created.

(define image-series
  (λ (n width height)
    (let* ((canvas (image-show (image-new width height))) (mertle (turtle-new canvas)))
  (turtle-set-brush! mertle "2. Hardness 100 (editable)" 1)
  (ellipse-background! n width height canvas)
  (fibonacci-spirals-fract! n width height 7 270 mertle)
  (fibonacci-spirals-fract! n width height 5 180 mertle)
  (fibonacci-spirals-fract! n width height 9 90 mertle)
  (fibonacci-spirals-fract! n width height 11 0 mertle))))