/*
 * FILE: CIRCLE FRACTALS
 * ---------------------
 * This program draws a Circle Fractal of a constant depth on the screen.
 * A Circle fractal of depth N is a circle of the specified size, containing
 * 6 depth N-1 Circle fractals within it.
 */

#include <math.h>
#include "gwindow.h"
#include "gobjects.h"
#include "point.h"

using namespace std;

void drawCenteredCircle(GWindow &w, GPoint center, double radius);
GPoint getPolarLineEndpoint(GPoint start, double length, double angleDegrees);

// display constants
static const int FRACTAL_DEPTH = 7;
static const int SCREEN_WIDTH = 600;
static const int SCREEN_HEIGHT = SCREEN_WIDTH;

/*
 * Draws a circle fractal by drawing a circle at the given center and radius, and
 * then 6 depth-1 circles within it.
 */
void drawRecursiveCircle(GWindow & w, int depth, GPoint center, double radius) {
    /* Base case: simplest possible instance of this problem - do nothing! */
    if (depth == 0) {
        return;
    }

    // Step 1: draw the large circle
    drawCenteredCircle(w, center, radius);

    // Step 2: draw the 6 smaller depth - 1 circles
    double length = 2.0 / 3 * radius;
    for(int i = 0; i < 6; i++) {
        GPoint childCenter = getPolarLineEndpoint(center, length, 60*i);
        drawRecursiveCircle(w, depth - 1, childCenter, radius / 3);
    }
}

/* PROVIDED HELPER FUNCTIONS */

// Converts the specified amount of degrees to radians.
double degreesToRadians(double degrees) {
    double radiansPerDegree = 2. * M_PI / 360;
    return degrees * radiansPerDegree;
}

// Draws a circle with the given radius centered around the given point.
void drawCenteredCircle(GWindow & w, GPoint center, double radius) {
    w.drawOval(center.getX() - radius, center.getY() - radius, 2 * radius, 2 * radius);
}

/*
 * Returns the endpoint of the line drawn from the given start point, of the given
 * length, and at the given angle (in degrees).
 */
GPoint getPolarLineEndpoint(GPoint start, double length, double angleDegrees) {
    double radians = degreesToRadians(angleDegrees);
    double dx = length * cos(radians);
    double dy = length * sin(radians);
    GPoint next(start.getX() + dx, start.getY() - dy);
    return next;
}

int main() {
    GWindow w(SCREEN_WIDTH, SCREEN_HEIGHT);
    GPoint center(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
    drawRecursiveCircle(w, FRACTAL_DEPTH, center, SCREEN_WIDTH/2);
    return 0;
}

