#include <iostream>
#include "../../vector/Vec3f.hxx"
#include <stdlib.h>
#include <time.h>
#include <fstream>
#include <vector>

// Box Muller transform
float box_muller() {
	float u = (float)rand() / RAND_MAX;
	float v = (float)rand() / RAND_MAX;

	float N = sqrt(-2*log(u)) * cos(2*3.1415*v);
	//float M = sqrt(-2*log(u)) * sin(2*3.1415*v);

	return N;
}

//fractal geometry based on diamond square alogrithm
int main() {
	//parameter
	int iterations     = 7;
	float threshold    = 20.0f;
	float smoothness   = 2.0f;
	float edge_a       = 100.0f; //first edge
	float edge_b       = 50.0f;  //second edge
	float ground_level = 0.0f;

	std::vector<Vec3f> corner1, corner2, corner3, corner4;
	std::vector< std::vector<int> > faces;

	corner1.push_back(Vec3f(0.0, 0.0, 0.0));
	corner2.push_back(Vec3f(edge_a, 0.0, 0.0));
	corner3.push_back(Vec3f(edge_a, edge_b, 0.0));
	corner4.push_back(Vec3f(0.0, edge_b, 0.0));

	std::ofstream outfile("fract.obj", std::ios::out);
	outfile << "mtllib fract.mtl" << std::endl;

	srand(time(NULL));

	std::vector<Vec3f> corner1_tmp, corner2_tmp, corner3_tmp, corner4_tmp;

	float pertubation = threshold;
	int counter = 1;

	for(int h = 0; h < iterations; ++h) {
		for (int i=0; i<int(corner1.size()); i++) {
			double randnum = ((rand()/(RAND_MAX+1.0)) * 2.0) - 1.0;
			
			Vec3f midpoint = (((corner1[i]+corner2[i])*0.5) 
					       + ((corner3[i]+corner4[i])*0.5))/2 
					       + Vec3f(0,0,pertubation*randnum);
			
			midpoint = midpoint + Vec3f(0,0,pertubation*randnum);

			Vec3f ab = (corner1[i]+corner2[i])*0.5;
			Vec3f bc = (corner2[i]+corner3[i])*0.5;
			Vec3f cd = (corner3[i]+corner4[i])*0.5;
			Vec3f da = (corner4[i]+corner1[i])*0.5;

			//new rectangles
			corner1_tmp.push_back(corner1[i]);
			corner2_tmp.push_back(ab);
			corner3_tmp.push_back(midpoint);
			corner4_tmp.push_back(da);

			corner1_tmp.push_back(ab);
			corner2_tmp.push_back(corner2[i]);
			corner3_tmp.push_back(bc);
			corner4_tmp.push_back(midpoint);

			corner1_tmp.push_back(midpoint);
			corner2_tmp.push_back(bc);
			corner3_tmp.push_back(corner3[i]);
			corner4_tmp.push_back(cd);

			corner1_tmp.push_back(da);
			corner2_tmp.push_back(midpoint);
			corner3_tmp.push_back(cd);
			corner4_tmp.push_back(corner4[i]);

			if(h == iterations-1  && midpoint.z() < ground_level)	{
				outfile << "v " << (float)corner1[i][0] 
				        << " " << (float)corner1[i][1] 
				        << " " << (float)corner1[i][2] 
				        << std::endl;       
				outfile << "v " << (float)ab[0] 
				        << " " << (float)ab[1] 
				        << " " << (float)ab[2] 
				        << std::endl;       
				outfile << "v " << (float)midpoint[0] 
				        << " " << (float)midpoint[1]
				        << " " << (float)midpoint[2]
				        << std::endl;       
				outfile << "v " << (float)da[0]
				        << " " << (float)da[1] 
				        << " " << (float)da[2]
				        << std::endl;       
				outfile << "v " << (float)corner2[i][0]
				        << " " << (float)corner2[i][1]
				        << " " << (float)corner2[i][2]
				        << std::endl;       
				outfile << "v " << (float)bc[0]
				        << " " << (float)bc[1]
				        << " " << (float)bc[2]
				        << std::endl;             
				outfile << "v " << (float)corner3[i][0] 
				        << " " << (float)corner3[i][1]
				        << " " << (float)corner3[i][2]
				        << std::endl;       
				outfile << "v " << (float)cd[0] 
				        << " " << (float)cd[1]
				        << " " << (float)cd[2]
				        << std::endl;                                           
				outfile << "v " << (float)corner4[i][0]
				        << " " << (float)corner4[i][1]
				        << " " << (float)corner4[i][2]
				        << std::endl;                   

				// using triangles
				outfile << "f " << (counter)
						<< " " << (counter+1)
						<< " " << (counter+2)
						<< std::endl;        
				outfile << "f " << (counter)
						<< " " << (counter+3)
						<< " " << (counter+2)
						<< std::endl;                  
				outfile << "f " << (counter+1)
						<< " " << (counter+4)
						<< " " << (counter+2)
						<< std::endl;        
				outfile << "f " << (counter+4)
						<< " " << (counter+5)
						<< " " << (counter+2)
						<< std::endl;                  
				outfile << "f " << (counter+5)
						<< " " << (counter+6)
						<< " " << (counter+2)
						<< std::endl;        
				outfile << "f " << (counter+6)
						<< " " << (counter+7)
						<< " " << (counter+2)
						<< std::endl;                  
				outfile << "f " << (counter+7)
						<< " " << (counter+8)
						<< " " << (counter+2)
						<< std::endl;        
				outfile << "f " << (counter+8)
						<< " " << (counter+3)
						<< " " << (counter+2)
						<< std::endl;               

/*
				// using rectangles
				outfile << "f " << (counter)
				        << " " << (counter+1)
				        << " " << (counter+2)
				        << " " << (counter+3)
				        << std::endl;        
				outfile << "f " << (counter+1) 
			            << " " << (counter+4) 
			            << " " << (counter+5) 
			            << " " << (counter+2) 
			            << std::endl;        
				outfile << "f " << (counter+5) 
						<< " " << (counter+6) 
						<< " " << (counter+7) 
						<< " " << (counter+2) 
						<< std::endl;        
				outfile << "f " << (counter+7) 
						<< " " << (counter+8) 
						<< " " << (counter+3) 
						<< " " << (counter+2) 
						<< std::endl;        
*/
				counter += 9;
			}  

		} 

		corner1.clear();
		corner2.clear();
		corner3.clear();
		corner4.clear();

		corner1=corner1_tmp;
		corner2=corner2_tmp;
		corner3=corner3_tmp;
		corner4=corner4_tmp;

		corner1_tmp.clear();
		corner2_tmp.clear();
		corner3_tmp.clear();    
		corner4_tmp.clear();

		pertubation /= smoothness;
	}

	outfile.close();

	return 0;
}