#lang racket
(require gigls/unsafe)
;;; Procedure:
;;;   h-lines
;;; Parameters:
;;;   n-lines, an integer describing the number of lines
;;;   image, an image
;;;   voffset, an integer describing the vertical offset between the lines
;;;   row1, an integer corresponding to the starting row of each line
;;;   row2, an integer corresponding to the ending row of each line
;;; Purpose:
;;;   Draws n-lines amount of horizontal lines across the image.
;;; Produces:
;;;   img, a modified version of our original image
;;; Preconditions:
;;;   n-lines > 0
;;;   voffset < (image-height image)
;;;   row1 > 0
;;;   row2 > 0
;;;   image must be a predefined, valid image
;;; Postconditions:
;;;   produces img, a modified version of image.
;;;   img contains n-lines horizontal lines spaced vertically by voffset

(define h-lines
  (lambda (n-lines image voffset row1 row2)
    (when (> n-lines 1) ;evaluates the body of the expression when n-lines > 1
      (image-draw-line! image 0 row1 (image-width image) row2) ;draws the line
      (h-lines (- n-lines 1) image voffset (+ row1 voffset) (+ row2 voffset))))) ;recurses through the procedure while the condition is met

;;; Procedure:
;;;   v-lines
;;; Parameters:
;;;   n-lines, an integer describing the number of lines
;;;   image, an image
;;;   hoffset, an integer describing the horizontal offset between the lines
;;;   col1, an integer corresponding to the starting column of each line
;;;   col2, an integer corresponding to the ending column of each line
;;; Purpose:
;;;   Draws n-lines amount of vertical lines across the image.
;;; Produces:
;;;   img, a modified version of our original image
;;; Preconditions:
;;;   n-lines > 0
;;;   hoffset < (image-width image)
;;;   col1 > 0
;;;   col2 > 0
;;;   image must be a predefined, valid image
;;; Postconditions:
;;;   produces img, a modified version of image.
;;;   img contains n-lines horizontal lines spaced horizontally by hoffset

(define v-lines
  (lambda (n-lines image hoffset col1 col2)
    (when (> n-lines 1) ;draws lines when n-lines > 1
      (image-draw-line! image col1 0 col2 (image-height image)) ;draws the line
      (v-lines (- n-lines 1) image hoffset (+ col1 hoffset) (+ col2 hoffset))))) ;recurses through the procedure while the condition is met

;;; Procedure:
;;;   d-lines1
;;; Parameters:
;;;   n-lines, an integer describing the number of lines
;;;   image, an image
;;;   offset, an integer describing the offset between the lines
;;;   row1, an integer corresponding to the starting row of each line
;;;   col2, an integer corresponding to the ending column of each line
;;; Purpose:
;;;   Draws n-lines amount of vertical lines across the image.
;;; Produces:
;;;   img, a modified version of our original image
;;; Preconditions:
;;;   n-lines > 0
;;;   offset < (image-width image)
;;;   offset < (image-height image)
;;;   row1 > 0
;;;   row2 > 0
;;;   image must be a predefined, valid image
;;; Postconditions:
;;;   produces img, a modified version of image.
;;;   img contains n-lines diagonal lines spaced diagonally by offset.
;;;   d-lines1 produces horizontal-like lines but each rotated 45 degrees clockwise about its central horizontal axis.

(define d-lines1
  (lambda (n-lines image offset row1 col2 )
    (when (> n-lines 1) ;draws lines when n-lines > 1
        (image-draw-line! image 0 row1 col2 (image-width image)) ;draws the line
        (d-lines1 (- n-lines 1) image offset (- row1 offset)  (+ col2 offset))))) ;recurses through the procedure while the condition is met

;;; Procedure:
;;;   d-lines2
;;; Parameters:
;;;   n-lines, an integer describing the number of lines
;;;   image, an image
;;;   offset, an integer describing the offset between the lines
;;;   row1, an integer corresponding to the starting row of each line
;;;   col2, an integer corresponding to the ending column of each line
;;; Purpose:
;;;   Draws n-lines amount of vertical lines across the image.
;;; Produces:
;;;   img, a modified version of our original image
;;; Preconditions:
;;;   n-lines > 0
;;;   offset < (image-width image)
;;;   offset < (image-height image)
;;;   row1 > 0
;;;   row2 > 0
;;;   image must be a predefined, valid image
;;; Postconditions:
;;;   produces img, a modified version of image.
;;;   img contains n-lines diagonal lines spaced diagonally by offset.
;;;   d-lines2 produces horizontal-like lines but each rotated 135 degrees clockwise about its central horizontal axis.

(define d-lines2
  (lambda (n-lines image offset row2 col1 )
    (when (> n-lines 1) ;draws lines when n-lines > 1
        (image-draw-line! image col1 (image-height image) (image-width image) row2) ;draws the line
        (d-lines2 (- n-lines 1) image offset (- row2 offset)  (- col1 offset))))) ;recurses through the procedure while the condition is met

;;;This procedure was taken from assignment 6
;;; Procedure:
;;;   rgb->hue-angle
;;; Parameters:
;;;   rgb, a set of rgb values
;;; Purpose:
;;;   obtains a hue angle corresponding to that set of rgb values
;;; Produces:
;;;;  hue, an integer between 0 and 360 that corresponds to that rgb values
;;; Preconditions:
;;;   [no additional]
;;; Postconditions:
;;;   hue, is an angle on the hue wheel that corresponds to that rgb value

(define rgb->hue-angle
  (lambda (rgb)
    (let* ([red (rgb-red rgb)]
           [green (rgb-green rgb)]
           [blue (rgb-blue rgb)]
           [chroma (- (max red green blue) (min red green blue))]
           [raw-hue (cond ((= 0 chroma) 0)
                          ((and (>= red green) (>= red blue)) (/ (- green blue) chroma ))
                          ((and (>= green red) (>= green blue)) (+ 2 (/ (- blue red) chroma )))
                          (else (+ 4 (/ (- red green) chroma ))))])
      (*(cond ((< raw-hue 0) (+ 6 raw-hue))
              (else raw-hue))
        60))))

;;;This procedure was taken from assignment 6        
;;; Procedure:
;;;   rgb-rotate hue
;;; Parameters:
;;;   color, an rgb color
;;;   angle, a real number
;;; Purpose:
;;;   rotates the hue of color by the corresponding angle
;;; Produces:
;;;;  mod-color, a modified rgb color
;;; Preconditions:
;;;   angle >= 0
;;;   color , an rgb color accepted by scheme
;;; Postconditions:
;;;   mod-color, a hued version of color

(define rgb-rotate-hue
  (lambda (color angle)
    (hsv->rgb
     (list
      (modulo (round (+ (rgb->hue-angle color) angle)) 360)
      (inexact->exact (rgb->saturation color))
      (inexact->exact (rgb->value color))))))

;;; Procedure:
;;;   grid
;;; Parameters:
;;;   n, non negative counting number
;;;   n-lines, an integer describing the number of lines
;;;   width, an integer describing the width of the image
;;;   height, an integer describing the height of the image
;;;   image, an image
;;;   color1, an rgb color
;;;   color2, an rgb color
;;;   color3, an rgb color
;;; Purpose:
;;;  Modifies image by creating a grid of horizontal vertical and diagonal lines
;;; Produces:
;;;;  img,an image
;;; Preconditions:
;;;   0 <= n <= 999
;;;   n-lines > 0  
;;; Postconditions:
;;;   img, modified image containing a grid of n-lines of horizonatal, vertical and diagonal lines.

(define grid
  (lambda (n n-lines width height image color1 color2 color3)
    (let* ([line-width (/ width (- n-lines 1))]
           [twice-line-width (* line-width 2)])
      (context-set-brush! "2. Block 01" n-lines)
      (context-set-fgcolor! (rgb-rotate-hue color1 n)) ; set the foreground color to a hue rotated version of color1
      (cond
        ((and (>= n 0) (<= n 333)); tests for when n is between 0 and 333 inclusive
         (d-lines1 n-lines image twice-line-width (- width twice-line-width) twice-line-width)) ;draws diagonal lines using the dlines1 procedure on image if test is approved
        ((and (>= n 334) (<= n 667)); tests for when n is between 334 and 667 inclusive
         (d-lines2 n-lines image twice-line-width (- height line-width) (- (image-width image) line-width))) ;draws diagonal lines using the dlines2 procedure on image if test is approved
        ((and (>= n 668) (<= n 999)) ;tests for when n is between 668 and 999 inclusive
         (d-lines1 n-lines image twice-line-width (- width twice-line-width) twice-line-width) ;draws diagonal lines using the dlines1 procedure on image if test is approved
         (d-lines2 n-lines image twice-line-width (- height line-width) (- width line-width)))) ;draws diagonal lines using the dlines2 procedure on image if test is approved
      (context-set-fgcolor! (rgb-rotate-hue color2 n)) ; set the foreground color to a hue rotated version of color2
      (h-lines (+ n-lines 1) image line-width 0 0);draws horizontal lines on image using the h-lines procedure. Add 1 to n-lines to avoid case where n-line parameter is 0
      (context-set-brush! "2. Block 01" (/ n-lines 2))
      (context-set-fgcolor! (rgb-rotate-hue color3 n)) ;set the foreground color to a hue rotated version of color3. This changes the color for the subsequent lines to be drawn.
      (h-lines (+ n-lines 1) image line-width 0 0) ;draws horizontal lines on image using the h-lines procedure. Add 1 to n-lines to avoid case where n-line parameter is 0
      (v-lines (+ n-lines 1) image line-width 0 0)))) ;draws vertical lines on image using the h-lines procedure. Add 1 to n-lines to avoid case where n-line parameter is 0

;;; Procedure:
;;;   overlap-grid
;;; Parameters:
;;;   image, an image
;;;   n, non negative counting number
;;;   n-lines, an integer describing the number of lines
;;;   color1, an rgb color
;;;   color2, an rgb color
;;;   color3, an rgb color
;;;   width, an integer describing the width of the image
;;;   height, an integer describing the height of the image
;;; Purpose:
;;;  Modifies image by creating another grid, overlapping the previous grid
;;; Produces:
;;;;  img, an image
;;; Preconditions:
;;;   0 <= n <= 999
;;;   n-lines > 0  
;;; Postconditions:
;;;   img is a modified image containing a grid with an overlapped grid of n-lines of horizonatal, vertical and diagonal lines.

(define overlap-grid
  (lambda (image n n-lines color1 color2 color3 width height)
    (image-select-rectangle! image ADD 0 0 (/ width 2) (/ height 2))
    (image-select-rectangle! image ADD (/ width 2) (/ height 2) (/ width 2) (/ height 2))
    (grid n n-lines width height image (rgb-complement color1) (rgb-complement color2) (rgb-complement color3))
    (image-select-nothing! image)))

;;; Documentation for the project was taken from the eboards.
;;; Procedure:
;;;   image-series
;;; Parameters:
;;;   n, an integer
;;;   width, a positive integer
;;;   height, a positive integer
;;; Purpose:
;;;   Create an "interesting" image.
;;; Produces:
;;;   image, an image
;;; Preconditions:
;;;   0 <= n < 1000
;;; Postconditions:
;;;   (image-width image) = width
;;;   (image-height image) = height
;;;   For all m != n
;;;   (image-series m width height) is different than image

(define image-series
  (lambda (n width height)
    (let* ([n-lines (+ 3 (modulo n 22))] ;defines the n-lines
           [image (image-show (image-new width height))] ;defines image
           [color1 (rgb-new (+ (* (mod n 255) 10) 27) 0 0)] ;defines color1
           [color2 (rgb-new 0 (+ (* (mod n 255) 8) 43) 0)] ;defines color2
           [color3 (rgb-new 0 0 (+ (* (mod n 255) 9) 37))]) ;defines color3
      (context-set-brush!  "2. Block 02" 1)
      (grid n n-lines width height image color1 color2 color3)
      (overlap-grid image n n-lines color1 color2 color3 width height))))