#lang racket
(require gigls/unsafe)


;;; Procedure:
;;;    assign-color
;;; Parameters:
;;;    n, a real integer
;;; Purpose:
;;;    To assign a color to any value of n
;;; Produces:
;;;    Assigned-color, an irgb color
;;; Preconditions:
;;;    [no additional]
;;; Postconditions:
;;;    Assigned-color will have a nonzero value for only one
;;;      of the three irgb components.
;;;    an input of n will have an Assigned-color with the same
;;;      irgb component as an input of n + 3. For each 3x, where
;;;      x is a real integer, 17x will be added on to the same irgb
;;;      component that is in Assigned-color with an input of n. In 
;;;      other words, assign-color cycles the different color components
;;;      in threes. 
(define assign-color
  (lambda (n)
    (let ([m (+ (modulo n 3) 1)]
          [r (floor (/ n 45))]
          [q (floor (/ n 3))])
      (cond
        [(integer? (/ m 3))
         (irgb-new 0 0 (+ r (modulo (+ (* 17 q) 17) 256)))]
        ;If m is a multiple of 3, we will make a blue color
        [(integer? (/ m 2))
         (irgb-new 0 (+ r (modulo (+ (* 17 q) 17) 256)) 0)]
        ;If m is a multiple of 2, but not of 3, we will make a green color
        [else
         (irgb-new (+ r (modulo (+ (* 17 q) 17) 256)) 0 0)]))))
        ;If m is neither a multiple of 2 or 3, we will make a red color

;Tests used for assign-color

;> (irgb->rgb-list (assign-color 0))
;'(17 0 0)
;> (irgb->rgb-list (assign-color 1))
;'(0 17 0)
;> (irgb->rgb-list (assign-color 2))
;'(0 0 17)
;> (irgb->rgb-list (assign-color 20))
;'(0 0 119)
;> (irgb->rgb-list (assign-color 21))
;'(136 0 0)
;> (irgb->rgb-list (assign-color 44))
;'(0 0 255)
;> (irgb->rgb-list (assign-color 45))
;'(17 0 0)
;> (irgb->rgb-list (assign-color 90))
;'(17 0 0)
;> (irgb->rgb-list (assign-color 999))
;'(68 0 0)
;> (irgb->rgb-list (assign-color 1000))
;'(0 68 0)


;;; Procedure:
;;;    background-creator
;;; Parameters:
;;;    n, a real integer
;;;    width, a positive real integer
;;;    height, a poisitive real integer
;;; Purpose:
;;;    Produce a background that fades from a color determined by n to black. 
;;; Produces:
;;;    background, an image
;;; Preconditions:
;;;    [no additional]
;;; Postconditions:
;;;    The color on the left will be the color output by assign-color
;;;      for the input n.
;;;    The color on the right will be black.
;;;    The color will fade from the color output by assign-color to black
;;;    background will have a width of width and a height of height
(define background-creator
  (lambda (n width height)
    (image-compute
     (lambda (col row)
       (hsv->irgb (map - (irgb->hsv (assign-color n)) 
                       (list 0 0 (* col (/ (list-ref (irgb->hsv (assign-color n)) 2) width))))))
     width height)))

;Tests for background-creator

;> (background-creator 40 100 100)
;9
;> (image-show 9)
;9
;> (background-creator 41 100 100)
;10
;> (image-show 10)
;10
;> (background-creator 42 100 100)
;11

;;; Procedure:
;;;    circle-in-square!
;;; Parameters:
;;;    image, an image
;;;    left, a real integer
;;;    top, a real integer
;;;    width, a positive real integer
;;;    height, a poisitive real integer
;;;    color, a string representing a color
;;; Purpose:
;;;    To put a rectangle of a certain color in an image, with a ellipse within that rectangle, having a brighter shade of color than that of the rectangle.
;;; Produces:
;;;    shape, an image
;;; Preconditions
;;;    [no additional]
;;; Postconditions
;;;    The left side of the rectangle will be at the x coordinate defined by left. The x coordinate of the ellipse will be in the same place,
;;;      and the y coordinate of the left of the ellipse will be exactly between the lower left and upper left corner of the rectangle.
;;;    The top side of the rectangle will be at the y coordinate defined by top. The y coordinate of the ellipse will be in the same place,
;;;      and the x coordinate of the top of the ellipse will be exactly between the upper left and upper right corner of the rectangle.
;;;    Both the rectangle and the ellipse will have a width of width.
;;;    Both the rectangle and the ellipse will have a height of height.
;;;    Shape will be in image.
;;;    The rectangle will be the color defined by color, while the color of the ellipse will be the shade of color after irgb-lighter has been 
;;;      applied to color twice. 

(define ellipse-in-rectangle!
  (lambda (image left top width height color)
    (image-select-rectangle! image REPLACE left top width height)
    (context-set-fgcolor! color)
    (image-fill-selection! image)
    (image-select-ellipse! image REPLACE left top width height)
    (context-set-fgcolor! (irgb->color-name (irgb-lighter (irgb-lighter (color-name->irgb color)))))
    (image-fill-selection! image)
    (image-select-nothing! image)))
 
;;; Procedure:
;;;    image-series
;;; Parameters:
;;;    n, a real integer
;;;    width, a real positive integer
;;;    height, a real positive integer
;;; Purpose:
;;;    Create an image with a background and a shape in the foreground.
;;; Produces:
;;;    image, an image
;;; Preconditions:
;;;    n must be in the range of 0 to 44
;;; Postconditions:
;;;    The color of the rectangle will be complementary to that of the left portion of the background, as produced by irgb-complement.
;;;    The shape will be in the centered in the center of image.
;;;    The color of the ellipse will be two shades lighter than that of the rectangle, as produced by irgb-lighter. 
;;;    Each value of n from 0 to 44 produces a unique image. 

(define image-series
  (lambda (n width height)
    (let ([z (+ 1 (floor (/ n 45)))])
      (if (equal? z 1)
          (ellipse-in-rectangle! (background-creator n width height) (* (/ 1 5) width) (* (/ 1 5) height) (* (/ 3 5) (/ width z)) (* (/ 3 5) (/ height z)) (irgb->color-name (irgb-complement (assign-color n))))
          (error "image-series: takes inputs only from the range 0-44, given" n)))))
