#lang racket
(require gigls/unsafe)

;;; File:
;;;   side-effects-lab.rkt
;;; Authors:
;;;   Samuel A. Rebelsky
;;;   YOUR NAME HERE
;;; Summary:
;;;   A variety of procedures for playing with side effects, particularly
;;;   side effects related to textual-output and basic image operations.

; +----------------+--------------------------------------------------
; | Textual Output |
; +----------------+

;;; Procedure:
;;;   greet
;;; Parameters:
;;;   name, a symbol or strong
;;; Purpose:
;;;   Prints a friendly message.
;;; Produces:
;;;   [Nothing; called for the side effect.]
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   Some text has been printed.
(define greet
  (lambda (name)
    (display "Hello, ")
    (display name)
    (display ".  ")
    (display "It's nice to meet you.")
    (newline)))

; +-------------------------------+-----------------------------------
; | Exploring Order of Operations |
; +-------------------------------+

;;; Procedure:
;;;   yield
;;; Parameters:
;;;   val, a value
;;; Purpose:
;;;   Display a short message about val
;;; Produces:
;;;   val, the same value
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   A short message is displayed
(define yield
  (lambda (val)
    (display "  yields ")
    (display val)
    (newline)
    val))

(define add
  (lambda (x y)
    (display "add ") (display x) (display " and ") (display y) (newline)
    (yield (+ x y))))

(define subtract
  (lambda (x y)
    (display "subtract ") (display y) (display " from ") (display x) (newline)
    (yield (- x y))))

(define multiply
  (lambda (x y)
    (display "multiply ") (display x) (display " and ") (display y) (newline)
    (yield (* x y))))

(define divide
  (lambda (x y)
    (display "divide ") (display x) (display " by ") (display y) (newline)
    (yield (/ x y))))

(define negate
  (lambda (x)
    (display "negate ") (display x) (newline)
    (yield (- x))))

; +-----------------+-------------------------------------------------
; | Fun with Images |
; +-----------------+

;;; Procedure:
;;;   scare! (SCale And REnder)
;;; Parameters:
;;;   drawing, a drawing
;;;   image, an image
;;; Purpose:
;;;   scale the drawing to the size of the image and then render it
;;;   on the image
;;; Produces:
;;;   image, the updated image
;;; Preconditions:
;;;   drawing and image both have a positive width and height
;;; Postconditions:
;;;   An appropriately scaled version of drawing appears on image
(define scare!
  (lambda (drawing image)
    (drawing-render!
     (hscale-drawing (/ (image-width image) (drawing-width drawing))
      (vscale-drawing (/ (image-height image) (drawing-height drawing))
       drawing))
     image)))

;;; Procedure:
;;;   claim
;;; Parameters:
;;;   source, a string that names an existing image file
;;;   target, a string that names an image file
;;; Purpose:
;;;   Add a little "ownership" symbol to the image in source,
;;;   saving the result in target.
;;; Produces:
;;;   The name of the target file.
;;; Preconditions:
;;;   You have permission to access the source file (in the computer sense,
;;;     the legal sense, and the ethical sense).
;;;   You have permission to write the target file.
;;;   The target file does not yet exist.
;;; Postconditions:
;;;   target now exists.
;;;   target contains an image much like source.
;;;   target contains a small icon to distinguish itself from source.
(define claim
  (lambda (source target)
    (image-save (image-claim! (image-load source)) target)))

;;; Procedure:
;;;   image-claim!
;;; Parameters:
;;;   source, an image
;;; Purpose:
;;;   Add a little "ownership" symbol to source.
;;; Produces:
;;;   source, the same image, now modified
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   source now contains a small icon to distinguish itself from
;;;   the previous version.
(define image-claim!
  (lambda (source)
    (drawing-render!
     (hshift-drawing
      (- (image-width source) 5)
      (vshift-drawing
       (- (image-height source) 3)
       claim-icon))
     source)))

;;; Name:
;;;   claim-icon
;;; Type:
;;;   drawing
;;; Contents:
;;;   A little icon we use to "claim" images.
(define claim-icon
  (drawing-group
   (scale-drawing 50 (recolor-drawing "red" drawing-unit-circle))
   (scale-drawing 40 drawing-unit-circle)
   (scale-drawing 30 (recolor-drawing "red" drawing-unit-circle))
   (scale-drawing 25 drawing-unit-circle)))

; +----------------------------------------+--------------------------
; | Observing the Construction of Drawings |
; +----------------------------------------+

(define annotated-hscale-drawing
  (lambda (scale drawing)
    (display "Scaling ")
    (display drawing)
    (display " horizontally by ")
    (display scale)
    (yield (hscale-drawing scale drawing))))

(define annotated-vscale-drawing
  (lambda (scale drawing)
    (vscale-drawing scale drawing)))

(define annotated-scale-drawing
  (lambda (scale drawing)
    (scale-drawing scale-drawing)))

(define annotated-hshift-drawing
  (lambda (offset drawing)
    (hshift-drawing offset drawing)))

(define annotated-vshift-drawing
  (lambda (offset drawing)
    (vshift-drawing offset drawing)))

(define annotated-recolor-drawing
  (lambda (color drawing)
    (recolor-drawing color drawing)))

; +-----------------+-------------------------------------------------
; | Sample Drawings |
; +-----------------+

;;; Value:
;;;   red-square
;;; Type:
;;;   drawing
;;; Description:
;;;   A moderate sized red square, suitable for rendering
(define red-square
  (vshift-drawing 
   50
   (hshift-drawing 
    40
    (scale-drawing 
     30
     (recolor-drawing 
      "red"
      drawing-unit-square)))))

;;; Value:
;;;   blue-circle
;;; Type:
;;;   drawing
;;; Description:
;;;   A moderate sized blue circle, suitable for rendering
(define blue-circle
  (vshift-drawing 
   50
   (hshift-drawing 
    40
    (scale-drawing 
     30
     (recolor-drawing 
      "blue"
      drawing-unit-circle)))))

;;; Procedure:
;;;   black-rectangle
;;; Type:
;;;   drawing
;;; Description:
;;;   A moderate size black rectangle, suitable for rendering
(define black-rectangle
  (vshift-drawing 
   40
   (hshift-drawing 
    50
    (hscale-drawing 
     40
     (vscale-drawing
      20
      drawing-unit-square)))))
