#include <fstream>
#include <math.h>
#include <time.h>
using namespace std;


// class for a complex number a + bi

class complexNumber{
	public:
	double v[2];
	complexNumber(){ v[0] = v[1] = v[2] = 0.; }
	complexNumber(double x, double y){ v[0] = x; v[1] = y; }
	~complexNumber(){}
	double magnitude2();	// return the square of the modulus
	complexNumber square();
};

double complexNumber::magnitude2() {
	return v[0]*v[0] + v[1]*v[1];
}

complexNumber complexNumber::square() {
	return complexNumber(v[0]*v[0] - v[1]*v[1], 2*v[0]*v[1]);
}

// define addition of two complex numbers
inline complexNumber operator+(const complexNumber& x, const complexNumber& y){
  return complexNumber(x.v[0]+y.v[0],x.v[1]+y.v[1]);
}
inline complexNumber operator*(const complexNumber& x, const complexNumber& y)
{
	return complexNumber(x.v[0]*y.v[0] - x.v[1]*y.v[1],
		x.v[0]*y.v[1] + x.v[1]*y.v[0]);
}

// trigonometric functions for complex numbers
inline complexNumber sin(complexNumber x) {
	return complexNumber(sin(x.v[0])*cosh(x.v[1]), 
		cos(x.v[0])*sinh(x.v[1]));
}


// given a complex number z and constant c, is z in the set or not?
bool isInSet(complexNumber z, const complexNumber& c, 
			 const int& maxIterations, const double& thresh) {
	double thresh2 = thresh*thresh;
	for (int i = 0; i < maxIterations; i++) {
	 z = z.square() + c;
	 //  if you don't want to use the quadratic, try the sin:
	 //z = c*sin(z);
	 if (z.magnitude2() > thresh2) {
		 return false;
	 }
	}
	return true;
}

int main(int argc, char** argv) {
	clock_t startClock = clock();

	printf("Starting complex Julia Set...\n");

	// image dimensions:
	int width  = 500;
	int height = 500;

	// area to scan:
	double minX = -1.5;
	double maxX =  1.5;
	double minY = -1.5;
	double maxY =  1.5;

	// value for constant c:
	complexNumber c(-0.123, 0.745);
	//complexNumber c(0, 1);

	// number of iterations and escape threshhold:
	int maxIterations = 20;
	double thresh = 1000.0;

	char* filename = "myFile.bmp";

	// array to hold pixel data:
	bool** pixels;
	pixels = new bool*[width];
	for (int i = 0; i < width; i++) {
		pixels[i] = new bool[height];
	}

	// scan each pixel to see if it is in the set or not
	printf("Scanning area: XX.X%%");
	for (int i = 0; i < width; i++) {
		printf("\b\b\b\b\b%04.1f%%", float(i)/float(width)*100.0);
		for (int j = 0; j < height; j++) {
			const double a = double(i)*(maxX-minX)/double(width) + minX;
			const double b = double(j)*(maxY-minY)/double(height) + minY;
			complexNumber z(a, b);
			pixels[i][j] = isInSet(z, c, maxIterations, thresh);
		}
	}
	printf("\b\b\b\b\bDone.\n\n");

	
	// write the result to a bitmap
	printf("Writing file...\n");
	ofstream myFile;
	myFile.open(filename, ios::out | ios::binary);
	// write BM
	char header[2] = {'B','M'};
	myFile.write(header, 2);

	// write file size
	unsigned int fileSize = width*height*3 + 54;
	myFile.write((char*)&fileSize, 4);

	// write reserved
	unsigned short reserved = 0;
	myFile.write((char*)&reserved, 2);
	myFile.write((char*)&reserved, 2);

	// write offset to bitmap data
	unsigned int offSet = 54;
	myFile.write((char*)&offSet, 4);

	// write header size
	unsigned int headerSize = 40;
	myFile.write((char*)&headerSize, 4);

	// write image size
	myFile.write((char*)&width, 4);
	myFile.write((char*)&height, 4);

	// planes
	unsigned short planes = 0;
	myFile.write((char*)&planes, 2);

	// bits per color
	unsigned short bitCount = 24;
	myFile.write((char*)&bitCount, 2);

	unsigned int compression = 0;
	myFile.write((char*)&compression, 4);
	unsigned int imageSize = 0;
	myFile.write((char*)&imageSize, 4);
	unsigned int ppmX = 0;
	myFile.write((char*)&ppmX, 4);
	unsigned int ppmY = 0;
	myFile.write((char*)&ppmY, 4);
	unsigned int colorsUsed = 0;
	myFile.write((char*)&colorsUsed, 4);
	unsigned int colorsImp = 0;
	myFile.write((char*)&colorsImp, 4);

	// write image information
	for (int j = 0; j < height; j++) {
		for (int i = 0; i < width; i++) {
			char rr, gg, bb;
			if (pixels[i][j]) {
				rr = char(0);
				gg = char(0);
				bb = char(0);
			}
			else {
				rr = char(255);
				gg = char(255);
				bb = char(255);
			}		
	 	    myFile.write(&bb, 1);
		    myFile.write(&gg, 1);
		    myFile.write(&rr, 1);
		}
	}
    myFile.close();

	double dif = (clock() - startClock) / double(CLOCKS_PER_SEC);
	printf("Wrote file '%s' in %.2lf seconds.\n\n", filename, dif);
}