#include<vector>
#include<math.h>
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
#include<fstream>
#include "data.h"

/*
 * Arbitrary data set
 */

//Constructor

Data::Data(){
	std::vector<std::vector<double>> T;
	std::string name = "Data_0";
	data_set = T;
	name_set = name;
}

Data::Data(const Data& other): data_set(other.data_set), name_set(other.name_set){}

Data::Data(std::string name): name_set(name){
	std::vector<std::vector<double>> T;
	data_set = T;
}

Data::Data(std::vector<std::vector<double>> T, std::string name): data_set(T), name_set(name){}

//Random generator

int partition(std::vector<std::vector<double>> &a,int start,int end){
	double pivot = a[end][0];
	int P_index = start;
	std::vector<double> tmp;
	for(int i=start;i<end;i++){
		if(a[i][0] <= pivot){
			tmp = a[i];
			a[i] = a[P_index];
			a[P_index] = tmp;
			P_index++;
		}
	}
	tmp = a[end];
	a[end] = a[P_index];
	a[P_index] = tmp;
	return P_index;
}

void Quicksort(std::vector<std::vector<double>> &a,int start,int end){
	if(start<end){
		int P_index=partition(a,start,end);
		Quicksort(a,start,P_index-1);
		Quicksort(a,P_index+1,end);
	}
}

void Data::randSet(int N){
	std::vector<std::vector<double>> T;
	double x=0,y=0;
	for(int i=0;i<N;i++){
		x = rand()/(RAND_MAX + 1.);
		y = rand()/(RAND_MAX + 1.);
		T.push_back({x,y});
	}
	data_set = T;
}

void Data::randSet(int N, double xa, double xb, double ya, double yb){
	std::vector<std::vector<double>> T;
	double t1=0,t2=0,x=0,y=0;
	for(int i=0;i<N;i++){
		t1 = rand()/(RAND_MAX + 1.);
		t2 = rand()/(RAND_MAX + 1.);
		x = xa*(1-t1)+xb*t1;
		y = ya*(1-t1)+yb*t2;
		T.push_back({x,y});
	}
	data_set = T;
}

void Data::randSet(int N, int d, double mu){
	double t=0,x=0,y=0,temp=0;
	std::vector<double> pol = {};
	FILE * param = fopen((name_set+".param.temp").c_str(), "w");
	for(int i=0;i<d+1;i++){
		t = rand()/(RAND_MAX + 1.);
		pol.push_back(10*(2*t-1));
		fprintf(param, "%lf \n", pol[i]);
	}
	std::vector<std::vector<double>> T = {};
	for(int i=0;i<N;i++){
		x = 10.*rand()/(RAND_MAX + 1.);
		y = 0;
		for(int j=0;j<d+1;j++){
			temp = y;
			y = temp + pol[j]*pow(x,j);
		}
		temp = y;
		y = temp + mu*(2*rand()/(RAND_MAX + 1.)-1);
		T.push_back({x,y});
	}
	Quicksort(T,0,T.size()-1);
	data_set = T;
}

//Modify and get data_set, name_set

void Data::add_value(std::vector<double> V){
	data_set.push_back(V);
}

void Data::setData(std::vector<std::vector<double>> T){
	data_set = T;
}

void Data::fromFile(std::string filepath){
	std::vector<std::vector<double>> T;
	std::fstream data(filepath, std::ios::in);
	double a=0.,b=0.;
	while(data >> a >> b)
		T.push_back({a,b});
	data.close();
	data_set = T;
}

std::vector<std::vector<double>> Data::getData() const {
	return data_set;
}

void Data::setName(std::string name){
	name_set = name;
}

std::string Data::getName() const {
	return name_set;
}

//Display methods

void Data::displayData(){
	std::vector<std::string> commandsForGnuplot = {"set title \""+name_set+"\"","set key bmargin","plot '"+name_set+".temp' w lp lc -1 title '"+name_set+"'"};
	FILE * temp = fopen((name_set+".temp").c_str(), "w");
	FILE * gnuplotPipe = popen ("gnuplot -persistent", "w");
	for (int i=0; i < data_set.size(); i++){
		fprintf(temp, "%lf %lf \n", data_set[i][0], data_set[i][1]);
	}
	for (std::string command : commandsForGnuplot){
		fprintf(gnuplotPipe,"%s \n", command.c_str());
	}
}

void Data::exportData(){
	FILE * fich = fopen((name_set+".data").c_str(), "w");
	for (int i=0; i < data_set.size(); i++){
		fprintf(fich, "%lf %lf \n", data_set[i][0], data_set[i][1]);
	}
}

//Get more informations

int Data::getCard() const {
	return data_set.size();
}

void Data::print() const {
	for(int i=0;i<data_set.size();i++)
		std::cout << data_set[i][0] << " " << data_set[i][1] << std::endl;
}
