//
//  main.cpp
//  TriGame

#include <iostream>
#include <iomanip>
#include "console.h"
#include "gwindow.h"
#include "gobjects.h"
#include "random.h"
#include "simpio.h"

using namespace std;

const double HEIGHT = 500;
const double WIDTH = 500;

GPoint halfWay(GPoint p1, GPoint p2);
void barnsleysFern(GWindow *gw, int point_sz);
GPoint nextBarnsley(GPoint g);
void triangle(GWindow *gw, int point_sz);

int main() {
    GWindow *gw = new GWindow(HEIGHT, WIDTH);

    int choice = getInteger("Please choose: (1) Triangle, (2) Barnsley's: ");

    int point_sz = getInteger("Please enter a point size (1 is smallest): ",
                              "Please enter an integer");

    switch(choice) {
        case 1: triangle(gw,point_sz);
                break;
        case 2: barnsleysFern(gw,point_sz);
                break;
    }

    return 0;
}

void triangle(GWindow *gw, int point_sz) {
    GPoint topLeft = GPoint(0, 0);
    GPoint topRight = GPoint(WIDTH-point_sz-1, 0);
    GPoint bottomMiddle = GPoint(WIDTH/2, HEIGHT-point_sz-1);

    gw->setColor("Green");
    gw->fillOval(topLeft.getX(),topLeft.getY(),point_sz,point_sz);
    gw->fillOval(topRight.getX(),topRight.getY(),point_sz,point_sz);
    gw->fillOval(bottomMiddle.getX(),bottomMiddle.getY(),point_sz,point_sz);

    GPoint currPoint = GPoint(randomReal(0, WIDTH-1),randomReal(0, HEIGHT-1));
    gw->setColor("Red");
    gw->fillOval(currPoint.getX(),currPoint.getY(),point_sz,point_sz);

    gw->setColor("Black");

    string response = "";
    getLine("Initial point (red) has been placed. Enter for next point.");
    while (1) {
        int next = randomInteger(0, 2);
        switch(next) {
        case 0:
            currPoint = halfWay(currPoint,topLeft);
            break;
        case 1:
            currPoint = halfWay(currPoint,topRight);
            break;
        case 2:
            currPoint = halfWay(currPoint,bottomMiddle);
            break;
        }
        gw->fillOval(currPoint.getX(),currPoint.getY(),point_sz,point_sz);
        if (response == "") {
            response = getLine("Enter for next point, any string for continuous.");
        } else {
            pause(2);
        }
    }
}

GPoint halfWay(GPoint p1, GPoint p2) {
    // find the midpoint between two points
    double midX = (p1.getX() + p2.getX()) / 2.0;
    double midY = (p1.getY() + p2.getY()) / 2.0;
    return GPoint(midX, midY);
}

GPoint nextBarnsley(GPoint g) {
    double x = g.getX();
    double y = g.getY();
    double newX,newY;

    double rand_choice = randomReal(0,100);
    if (rand_choice < 1.0) { // 1% of the time
        newX = 0;
        newY = 0.16 * y;
    } else if (rand_choice < 86.0) { // 85% of the time
        newX =  0.85 * x + 0.04 * y;
        newY = -0.04 * x + 0.85 * y + 1.6;
    } else if (rand_choice < 93.0) { // 7% of the time
        newX = 0.20 * x - 0.26 * y;
        newY = 0.23 * x + 0.22 * y + 1.6;
    } else { // 7% of the time
        newX = -0.15 * x + 0.28 * y;
        newY =  0.26 * x + 0.24 * y + 0.44;
    }
    return GPoint(newX,newY);
}

void barnsleysFern(GWindow *gw, int point_sz) {
    GPoint nextPoint = GPoint(0.0, 0.0);

    gw->setColor("#009600");
    string response = "";

    for (int i=0; i < 100000; i++) {
        // draw the point, scaling and translating to middle of the screen
        double x = nextPoint.getX();
        double y = nextPoint.getY();

        // scale
        x = (x + 2.182)*(WIDTH - 1)/4.8378;
        y = (9.9983 - y)*(HEIGHT - 1)/9.9983;

        gw->fillOval(x,y,point_sz,point_sz);

        if (response == "") {
            response = getLine("Enter for next point, any string for continuous.");
        }
        nextPoint = nextBarnsley(nextPoint);
    }
}
