/**
 * File: draw-boxy-fractal.cpp
 * ---------------------------
 * drawBoxyFractal draws a collection of recursively layered squares
 * to form a fractal in two-dimensional space.
 *
 * (c) Jerry Cain
 * Edits and comments by Cynthia Lee (c) 2014
 *
 */

#include <cmath>
using namespace std;

#include "gwindow.h"
#include "simpio.h"

/* Constants */
static const int    WINDOWHEIGHT = 600;
static const int    WINDOWWIDTH = 800;
static const double STARTDIMENSION = 120;
static const double SCALE_FACTOR = 0.45;

/* Function Prototypes */
static void drawBoxyFractal(GWindow& window, double cx, double cy, double dimension, int order);
static void drawFilledBox(GWindow& window, double cx, double cy, double dimension,
                          const string& fill, const string& border);

/* 
 * main()
 *
 * - Sets up graphics window
 * - Prompts user for desired depth of drawing (choose 0 (zero) to QUIT)
 * - Initiates call to recursive fractal drawing
 */
int main() {
    setConsoleFont("Arial-18");
    GWindow window(WINDOWWIDTH, WINDOWHEIGHT);
    while (true){
        int order = getInteger("Depth to draw (0 to quit): ");
        if (order <= 0) break;
        window.clear();
        int centerX = WINDOWWIDTH/2;
        int centerY = WINDOWHEIGHT/2;
        drawBoxyFractal(window, centerX, centerY, STARTDIMENSION, order);
    }
    return 0;
}

/* 
 * drawBoxyFractal
 *
 * - window: the graphics window
 * - cx, cy: the coordinates of the desired center of the next square to draw
 * - dimension: the width of the square to draw
 * - order: count of how many more levels deep we should go in the recursion
 *
 * Class notes:
 * To generate fractals like the ones on the "real or photoshop?" slide, you can
 * test order and behave differently based on order. For example, to generate a
 * fractal that alternates between two different patterns on alternating order
 * levels, you can say "if (order%2 == 0) { do one thing } else { do something else }
*/
static void drawBoxyFractal(GWindow& window, double cx, double cy,
                            double dimension, int order) {

    if (order == 0) return;
    if (order % 2 == 0) drawFilledBox(window, cx, cy, dimension, "Gray", "Black");
    drawBoxyFractal(window, cx-dimension/2, cy-dimension/2, dimension*SCALE_FACTOR, order-1);
    drawBoxyFractal(window, cx+dimension/2, cy+dimension/2, dimension*SCALE_FACTOR, order-1);
    drawBoxyFractal(window, cx-dimension/2, cy+dimension/2, dimension*SCALE_FACTOR, order-1);
    drawBoxyFractal(window, cx+dimension/2, cy-dimension/2, dimension*SCALE_FACTOR, order-1);
    if (order % 2 != 0) drawFilledBox(window, cx, cy, dimension, "Gray", "Black");
}


/* 
 * drawFilledBox
 *
 * - window: the graphics window
 * - cx, cy: the coordinates of the desired *center* of the next square to draw
 * - dimension: the width of the square to draw
 * - fill: color of the box's fill
 * - border: color of the box's border
 *
 * Class notes:
 * You don't need to worry about this one. You can think of it as effectively part of the
 * graphics library. It just draws a filled rectangle at the specified coordinates/size.
 */
static void drawFilledBox(GWindow& window, double cx, double cy, double dimension,
                          const string& fill, const string& border) {
    GRectangle bounds(cx - dimension/2, cy - dimension/2, dimension, dimension);
    window.setColor(fill);
    window.fillRect(bounds);
    window.setColor(border);
    window.drawRect(bounds);
}
