#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <ctime>
#include <vector>


#define K_MAX 50
#define ITER_MAX 10000

using namespace std;

typedef struct{
	int val0, val1, val2;
}color;
typedef struct{
	int valor;
	int val0, val1, val2;
}pixel;
typedef struct{
	vector<color> pix;
	int valor;
}ventana;


void kmeans(int k, vector<ventana> data, vector<ventana>* clusters,int iter);


int main(int argc,char *argv[]){

	FILE * f_Entrenamiento;
	FILE * f_Destino;
	int kMAX;
	int iter;

	if(argc<=1){
		fopen_s(&f_Entrenamiento,"Entrenamiento.txt","r");
		if(f_Entrenamiento==NULL){
			printf("Error en el fichero Entrenamiento.txt\n");
			return -1;
		}
	}
	else{
		fopen_s(&f_Entrenamiento,argv[1],"r");
		if(f_Entrenamiento==NULL){
			printf("Error en el fichero de entrenamiento\n");
			return -1;
		}
	}

	if(argc<3)
		kMAX=K_MAX;
	else{ 
		kMAX=atoi(argv[2]);
		if(kMAX>90)kMAX=90;
	}
	if(argc<4)
		iter=ITER_MAX;
	else{ 
		iter=atoi(argv[3]);
	}

	vector<ventana> entrenamiento;
	char buffer[2000];
	char *p_buffer;
	color pix_aux;
	ventana vent_aux;
	int v,Npixels;

	fgets(buffer,2000,f_Entrenamiento);
	sscanf_s(buffer,"%d",&Npixels);

	//Leer entrenamiento
	while( fgets(buffer,2000,f_Entrenamiento) != NULL ){
		p_buffer=buffer;
		for( int i=0; i < Npixels; i++){

			sscanf_s(p_buffer,"%d %d %d ",&pix_aux.val0, &pix_aux.val1, &pix_aux.val2);
			vent_aux.pix.push_back(pix_aux);

			for(int j=0; j<3; j++){
				while(*p_buffer != ' ')
					p_buffer++;
				p_buffer++;
			}
			
		}
				
		sscanf_s(p_buffer,"%d",&vent_aux.valor);
		entrenamiento.push_back(vent_aux);
		vent_aux.pix.clear();
	}

	fclose(f_Entrenamiento);

	//separamos en mano y nomano
	vector<ventana> mano;
	vector<ventana> nomano;


	for (int i=0; i<entrenamiento.size(); i++){
		if(entrenamiento[i].valor)
			mano.push_back(entrenamiento[i]);
		else
			nomano.push_back(entrenamiento[i]);
	}

	
	vector<ventana> centroides_mano;
	vector<ventana> centroides_nomano;

	char name[]="K_Medias_00.txt";
	
	for(int k=10,n=1; k<=kMAX; k+=10, n++){
		name[9]=char(n+48);
		fopen_s(&f_Destino,name,"w");
		if(f_Destino==NULL){
			printf("Error en el fichero K_Medias\n");
			exit(0);
		}
	
		kmeans(k,mano,&centroides_mano,iter);
		kmeans(k,nomano,&centroides_nomano,iter);

		fprintf(f_Destino,"%d",Npixels);
		for(int i=0; i<k;i++){
			fprintf(f_Destino,"\n");
			for (int j = 0; j < Npixels; j++){
				fprintf(f_Destino,"%d %d %d ", centroides_mano[i].pix[j].val0, centroides_mano[i].pix[j].val1, centroides_mano[i].pix[j].val2);
			}
			fprintf(f_Destino,"1");
		}
		for(int i=0; i<k;i++){
			fprintf(f_Destino,"\n");
			for (int j = 0; j < Npixels; j++){
				fprintf(f_Destino,"%d %d %d ", centroides_nomano[i].pix[j].val0, centroides_nomano[i].pix[j].val1, centroides_nomano[i].pix[j].val2);
			}
			fprintf(f_Destino,"0");
		}

		centroides_mano.clear();
		centroides_nomano.clear();

		fclose(f_Destino);
	}
	return 0;


}


void kmeans(int k, vector<ventana> data, vector<ventana>* clusters,int iter) {
	double dist;

	vector<ventana> centroids;
	int Npixel=data[0].pix.size();
	srand((unsigned)time(0)); 
	int *num = new int[k];
	
	ventana n_cent;
	color col;
	for (int i = 0; i < Npixel; i++){
		n_cent.pix.push_back(col);
	}
	for (int i = 0; i < k; i++){
		centroids.push_back(n_cent);
	}

	static const double R = (double)k / (RAND_MAX+1.0);

	// inciando centroides
	for (int i = 0; i < data.size(); i++)
		data[i].valor = (int)(rand()*R);

	int	cont=0;
	while(cont<iter){
		cont++;
		for (int i = 0; i < k; i++){
			num[i]=0;
			for(int j=0; j < Npixel; j++){
				centroids[i].pix[j].val0 = 0;
				centroids[i].pix[j].val1 = 0;
				centroids[i].pix[j].val2 = 0;
			}
		}

		for(int i=0; i<data.size();i++){
			num[data[i].valor]++;
			for(int j=0; j < Npixel; j++){
				centroids[data[i].valor].pix[j].val0 += data[i].pix[j].val0;
				centroids[data[i].valor].pix[j].val1 += data[i].pix[j].val1;
				centroids[data[i].valor].pix[j].val2 += data[i].pix[j].val2;
			}
		}
		for (int i = 0; i < k; i++){
			if(num[i]!=0){
				for(int j=0; j < Npixel; j++){
					centroids[i].pix[j].val0 /= num[i];
					centroids[i].pix[j].val1 /= num[i];
					centroids[i].pix[j].val2 /= num[i];
				}
			}
			else{
				int r= (int)(rand()%data.size());
				for(int j=0; j < Npixel; j++){
					centroids[i].pix[j].val0 = data[r].pix[j].val0;
					centroids[i].pix[j].val1 = data[r].pix[j].val1;
					centroids[i].pix[j].val2 = data[r].pix[j].val2;
				}
			}
		}

			double max_dist;
			int mov=0;
			for(int i=0; i<data.size();i++){

				max_dist=9999999.0;
				int min_cluster=0;
				for( int n=0; n<k; n++){
					double dist=0.0;
					for(int j=0; j < Npixel; j++){
						dist=pow( double(centroids[n].pix[j].val0-data[i].pix[j].val0), int(2) ) + pow( double(centroids[n].pix[j].val1-data[i].pix[j].val1), 2 ) + pow( double(centroids[n].pix[j].val2-data[i].pix[j].val2), 2 );
					}
					//dist=sqrt(dist);
					if(dist<max_dist){
						max_dist=dist;
						min_cluster=n;
					}
				}

				if(data[i].valor==min_cluster) mov++;
				data[i].valor=min_cluster;

			}	

		if( mov == data.size() ) break;
	}

	(*clusters)=centroids;
}
