/*
 * FILE: CURVE FRACTALS
 * ---------------------
 * This program draws a Curve Fractal which is a curved path of circles (spiraling inwards).
 * A level-0 curve draws nothing.  A level n curve draws a centered circle at the base point,
 * and then an n-1 curve of circles curving clockwise.
 */

#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);

// useful math constants
static const double SIN_60 = sqrt(3)*0.5;    //value of sin(60 degrees)

// display constants
static const int FRACTAL_DEPTH = 100;
static const int SCREEN_WIDTH = 500;
static const int SCREEN_HEIGHT = SCREEN_WIDTH;

/*
 * Draws a curved path of circles (spiraling clockwise).  A level-0 curve draws nothing.
 * A level n curve draws a centered circle at the base point, and then an n-1 curve
 * of circles starting at the point "length" away at "angle" degrees from the base,
 * with 80% of the original radius and length and 20 degrees less on the angle.
 */
void drawCurve(GWindow & w, int level, GPoint base, double radius, double length, double angle) {
    // Base case: the simplist possible instance of this problem (a level-0 curve draws nothing!)
    if (level == 0) {
        return;
    }

    // Draw the base circle
    drawCenteredCircle(w, base, radius);

    // Draw a level-1 curve at an angle from this circle
    GPoint newBase = getPolarLineEndpoint(base, length, angle);
    angle = angle - 20;
    radius = radius * 0.8;
    length = length * 0.8;
    drawCurve(w, level - 1, newBase, radius, length, angle);
}

/* PROVIDED HELPER FUNCTIONS */

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

/*
 * 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;
}

// 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);
}

int main() {
    GWindow w(SCREEN_WIDTH, SCREEN_HEIGHT);
    GPoint center(SCREEN_WIDTH / 2.0 - 100, SCREEN_HEIGHT / 2.0);
    drawCurve(w, FRACTAL_DEPTH, center, 50, 100, 70);
    return 0;
}

