#lang racket
(require gigls/unsafe)

;;; Procedure:
;;;   make-image
;;; Parameters:
;;;   width, a positive integer
;;;   height, a positive integer
;;;   n, an integer
;;; Purpose:
;;;   To create an interesting image
;;; Produces:
;;;   Nothing is returned. canvas, an image, is produced.
;;; Preconditions:
;;;   n must be between 0 and 999 inclusive.
;;;   In order for the turtle in the image to scale correctly, 
;;;     width must be equivalent to height. Everything else should scale
;;;     correctly as long as the parameters are correct.
;;; Postconditions:
;;;   canvas has a red rectangle that is 20% of the height of canvas
;;;     and 15% the width of canvas. This rectangle is at the bottom
;;;     right of the image.
;;;   There is a white wavy fence covering most of the image that is 20 links
;;;     wide and 27 links long.
;;;   There is a red link every (+ 110 (mod n 10)) number of links. This means
;;;     that some images may have several red links whereas others might not
;;;     have any visible red links.
;;;   The angle of the fence always increases first by (+ 10 (mod n 15))
;;;     until the angle is greater than 135. Then, the angle starts
;;;     decreasing by the same amount until the angle is less than 45.
;;;     At this point, the angle starts increasing again.
;;;   The top right corner of the fence is always at the coordinate:
;;;     ((+ (* .8 width)(* (/ n 1000) .2 width)) , 0)
;;;   The right side of the fence extends to the coordinate:
;;;     ((* (/ n 1000) .5 width), (image-height canvas))
;;;   There is a black ellipse cut out of the fence centered at
;;;     the midpoint of the midpoint of the top right corner of the fence
;;;     and the bottom right point of the fence and the coordinate (0, 0).
;;;   There is a red rectangle inside of the hole that looks like it is
;;;     going through the hole. It is the same dimensions as the rectangle 
;;;     in the bottom right corner of the screen.
;;; Problems:
;;;   Occasionally, the background color of the image will remain white
;;;     instead of switching to black. This can be fixed by rendering the 
;;;     image again.
;;; Props:
;;;   We learned how to use the procedure acos from the following url:
;;;     http://docs.racket-lang.org/reference/generic-numbers.html#%28
;;;     def._%28%28lib._racket/math..rkt%29._radians-~3edegrees%29%29

(define make-image
  (lambda (width height n)
    (let* (;direction-of-change is a one-cell vector that holds 1 if the
           ;  angle of the fence is increasing and 0 if the angle is decreasing.
           [direction-of-change (vector 1)]
           ;angle-change-amount is the amount that each successive column 
           ;  of links changes its angle based on n.
           [angle-change-amount (+ 10 (mod n 15))]
           ;red-link is how often a red link appears in the fence. There is
           ;  a red link after every red-link number of links.
           [red-link (+ 110 (mod n 10))]
           ;red-counter counts to red-link.
           [red-counter (vector 0)]
           ;length is the size of one segment in a link. This is the same for
           ;  all links in the fence of one image.
           [length (* 20 height (/ 1 500))]
           [num-rows 27]
           [num-columns 20]
           ;All values starting with "x-" or "y-" represent the x coordinate
           ;  and the y coordinate of whatever follows. top is where the top
           ;  right edge of the fence is, bottom is where the bottom right
           ;  edge of the fence extends to, and hole is where the hole is.
           [x-top (+ (* .8 width)
                     (* (/ n 1000) .2 width))]
           [y-top 0]
           [x-bottom (* (/ n 1000) .5 width)]
           [y-bottom height]
           [x-hole (/ (/ (+ x-top x-bottom) 2) 2)]
           [y-hole (/ (/ (+ y-top y-bottom) 2) 2)]
           ;canvas is the image on which we draw everything. There is a red 
           ;  rectangle drawing in the bottom.
           [canvas (image-show
                    (drawing->image
                     (list 'drawing
                           'rectangle
                           (rgb-new 255 0 0)
                           ""
                           (- x-top (* .15 width))
                           (* .8 height) 
                           (* .15 width)
                           (* .2 height))
                     width height))]
           [jonathan (turtle-new canvas)])
      
      (letrec 
          ([radians->degrees
            (lambda (angle)
              (* angle 180 (/ 1 pi)))]
           
           ;Set the initial settings for the turtle.
           [initialize!
            (lambda ()
              (turtle-set-brush! jonathan "1. Pixel")
              (turtle-set-color! jonathan "white")
              (turtle-teleport! jonathan x-top y-top)
              ;Use inverse cosine and the dot product to turn the turtle
              ;  to face bottom. 
              (turtle-turn! jonathan 
                            (+ 90 (radians->degrees 
                                   (acos 
                                    (/ y-bottom 
                                       (sqrt 
                                        (+ (square y-bottom)
                                           (square 
                                            (- x-top x-bottom))))))))))]
           
           [increment-red-counter!
            (lambda ()
              (vector-set!
               red-counter 0 
               (increment (vector-ref red-counter 0))))]
           
           [get-red-counter
            (lambda ()
              (vector-ref red-counter 0))]
           
           ;make-link! makes one link in the fence.
           [make-link!
            (lambda (angle)
              (increment-red-counter!)
              ;Make a red link every red-link number of links.
              (when (= 0 (mod (get-red-counter) red-link))
                (turtle-set-color! jonathan "red"))
              (repeat 2 (lambda ()
                          (turtle-forward! jonathan length)
                          (turtle-turn! jonathan angle)
                          (turtle-forward! jonathan length)
                          (turtle-turn! jonathan (- 180 angle))))
              ;Set the turtle so that it is ready to draw the next link.
              (turtle-up! jonathan)
              (turtle-forward! jonathan length)
              (turtle-down! jonathan)
              (turtle-set-color! jonathan "white"))]
           
           ;turtle-reset! moves the turtle from the end of one column
           ;  to the start of the next column.
           [turtle-reset!
            (lambda (angle)
              (turtle-turn! jonathan 180)
              (turtle-up! jonathan)
              (turtle-forward! jonathan (* length num-rows))
              (turtle-turn! jonathan (+ 180 angle))
              (turtle-forward! jonathan length)
              (turtle-down! jonathan)
              (turtle-turn! jonathan (* -1 angle)))]
           
           ;increasing? returns true if the value of direction-of-change is 1.
           [increasing?
            (lambda ()
              (= (vector-ref direction-of-change 0) 1))]
           
           ;change-angle adds angle-change-amount to the previous angle if
           ;  increasing? and subtracts angle-change-amount to the previous
           ;  angle if not increasing?. This is what creates the waves in
           ;  the fence.
           [change-angle
            (lambda (angle)
              (when (< angle 45)
                (vector-set! direction-of-change 0 1))
              (when (> angle 135)
                (vector-set! direction-of-change 0 0))
              (if (increasing?)
                  (+ angle-change-amount angle)
                  (- angle angle-change-amount)))]
           
           [make-fence!
            (lambda (angle counter)
              ;This statement makes one column of links
              (repeat num-rows make-link! angle)
              (turtle-reset! angle)
              (when (< counter num-columns)
                (make-fence! (change-angle angle) (+ 1 counter))))]
           
           ;make-hole! creates black hole centered at (x-hole, y-hole).
           [make-hole!
            (lambda ()
              (image-select-ellipse! canvas 
                                     REPLACE 
                                     (- x-hole (* .1 width)) 
                                     (- y-hole (* .05 height)) 
                                     (* .2 width) 
                                     (* .1 height))
              (context-set-fgcolor! "black")
              (image-fill-selection! canvas)
              )]
           
           ;make-rectangle! creates a red rectangle that looks like
           ;  it is inside the hole.
           [make-rectangle!
            (lambda ()
              (image-select-ellipse! 
               canvas
               REPLACE
               (- x-hole (* .1 width))
               (- y-hole (* .05 height))
               (* .2 width)
               (* .1 height))
              (image-select-rectangle! 
               canvas
               INTERSECT
               (- x-hole (* .075 width))
               (- y-hole (* .05 height))
               (* .15 width)
               (* .1 height))
              (image-select-rectangle! 
               canvas
               ADD
               (- x-hole (* .075 width))
               (- y-hole (* .15 height))
               (* .15 width)
               (* .15 height))
              (context-set-fgcolor! "red")
              (image-fill-selection! canvas)
              )]
           );end letrec procedure definitions
        
        (context-set-bgcolor! "black")
        (initialize!)
        ;make-fence! creates the fence with a starting angle of 90 and
        ;  a counter value of 0.
        (make-fence! 90 0)
        (make-hole!)
        (make-rectangle!)
        (image-select-nothing! canvas)
        (context-update-displays!)))))