#include "StdAfx.h"
#include "OlvTaskProcess.h"
#include "olivia_def.h"
#include <sstream>
#include <string>
#include "olv_task.h"

#define  MODULO "OlvTaskProcess"

std::string to_string(double& d)
{
	char dig[256];
	dig[0]=0;	
	return dig;
}

//*******************************************************************************************************
OlvTaskProcess::OlvTaskProcess(void)
{
	costes.clear();
	va_mal=FALSE;
	angs=NULL;
}
OlvTaskProcess::~OlvTaskProcess( void )
{
	costes.clear();
	if(angs)
	{
		for(int i=0;i<info.n;i++)
		{
			angs[i].libera();			
		}		
		free(angs);
		angs=NULL;
	}
	ia.clear();
	cost_amb.clear();
}
//*******************************************************************************************************
void OlvTaskProcess::preTask()
{
	//pilla informacion de socket necesaria
	//el tread no esta currando
	//presentacion-----------------------------------------
	int aux[2];
	aux[0]= PETICION_GENERAL_PRESENTA;
	aux[1]=ithr;
	if(!envia(aux,sizeof(aux)))
	{
		C_log::log(MODULO, "error al enviar presentacion");
		cancela();
		return;
	}
	int nb;
	void *data = recibe(&nb);
	if(nb < sizeof(int) || (*(int*)data)!=PETICION_GENERAL_OK)
	{
		C_log::log(MODULO, "error al recibir contestacion de presentacion");
		cancela();
		return;
	}
	data = recibe(&nb);
	if(nb<sizeof(InfoIniTask))
	{
		C_log::log(MODULO, "error al recibir contestacion de presentacion");
		cancela();
		return;
	}
	memcpy(&info,data,sizeof(InfoIniTask));
	//------------------------------------------------------
}
//*******************************************************************************************************
void OlvTaskProcess::inTask()
{
	//envia sigue vivo----------------------
	
	int aux = PETICION_GENERAL_OK;
	if(!envia(&aux,sizeof(aux)))
	{
		C_log::log(MODULO, "error al enviar Ok");
		cancela();
		return;
	}
	int nb;
	void *data = recibe(&nb);
	if(nb<sizeof(int))
	{
		C_log::log(MODULO, "error al recibir contestacion ok");
		cancela();
		return;
	}
	//mira contstacion------------------------
	switch(*(int*)data)
	{
	case(PETICION_GENERAL_OK):
		break;
	default://PETICION_GENERAL_NO
		C_log::log(MODULO, "Recibida peticion de cancelacion");
		cancela();
	}
	//envia log
	enviaLog();
}
void OlvTaskProcess::enviaLog()
{
	StrArray msgs;
	if(OlvApp.colaLog.dame(msgs))
	{
		char buf[1028];
		int *id =(int*) buf;
		char* msg = (char*)&id[1];
		*id = PETICION_GENERAL_DAME_LOG;
		for (int i = 0; i<msgs.n_i; i++)
		{
			strcpy(msg,msgs.get(i));
			
			if(!envia(&buf,(int)(sizeof(int)+strlen(msg)+1)))
			{
				C_log::log(MODULO, "error al enviar Log");
				cancela();
			}
		}
	}
}
//*******************************************************************************************************
void OlvTaskProcess::postTask()
{
	enviaLog();
	int aux[2];
	aux[0]= PETICION_GENERAL_FIN;
	if(va_mal)
	{
		aux[1]=PETICION_GENERAL_NO; //dependiendo del estado
	}
	else
	{
		aux[1]=PETICION_GENERAL_OK; //dependiendo del estado
		C_log::log(MODULO,"Task %ld, Enviando final feliz",ithr);

	}
	if(!envia(aux,sizeof(aux)))
	{
		C_log::log(MODULO, "Task %ld, Error al enviar terminado",ithr);
		cancela();
	}
	int nb;
	void *data = recibe(&nb);
	if(nb<sizeof(int)|| *(int*)data != PETICION_GENERAL_FIN)
	{
		C_log::log(MODULO, "Task %ld, Error al recibir fin",ithr);
	}
}
//*******************************************************************************************************
void OlvTaskProcess::run()
{
	//tarea a realizar 
	//lee archivos de costes, angulos e informacion asociada
	//si !usa_angs, angs=NULL;
	if(!lee_mats())
	{
		C_log::log(MODULO,"Task %ld,Error en lee_mats", ithr);

		va_mal=TRUE;
		goto sal;
	}

	if(!calcula_cost_ambThr())
	{
		C_log::log(MODULO,"Task %ld,Error en calcula_cost_amb_sub", ithr);

		va_mal=TRUE;
		goto sal;
	}

	//guarda mat de cost_amb
	if(!guarda_cost_amb())
	{
		C_log::log(MODULO,"Task %ld,Error en guarda_cost_amb", ithr);

		va_mal=TRUE;
		goto sal;
	}
sal:
	C_log::log(MODULO, "Task de tarea saliendo %ld %s",ithr, va_mal ? "Mal" : "Bien");

}
//*******************************************************************************************************
BOOL OlvTaskProcess::calcula_cost_ambThr()
{
	//inicializa archivo----------------------
	char p[MAX_PATH];
	BOOL mal=FALSE;

	sprintf_s(p,MAX_PATH,"%s\\%s",info.path_temp,NOMB_ARCH_DIJ_DEF);
	if(!arch_dj.inicia(p, TRUE,FALSE, info.n))
	{
		C_log::log(MODULO,"Task %ld,Error %ld no se ha podido crear ndj", ithr,GetLastError());
		mal  = TRUE;
		goto final;
	}
	//C_log::log(MODULO,"sizeof %ld %ld %ld %ld", sizeof(Head_dj_arch),sizeof(Djkt_nodo), sizeof(Djkt_ids_pdr), arch_dj.sizn);
	if(!arch_dj.inicia_inf_amb(&ia,info.namb,info.KK,info.id_instal, info.id_planta))
	{
		C_log::log(MODULO,"Task %ld,Error %ld no se ha podido crear info de ambitos", ithr,GetLastError());
		mal  = TRUE;
		goto final;

	}
	//pilla memoria necesaria para coste de ambitos--------------
	if(!cost_amb.inicia(info.namb,info.namb))
	{
		C_log::log(MODULO,"Task %ld,Error %ld no se ha podido iniciar cost_amb, sin memoria", ithr,GetLastError());

		//sin memoria
		mal  = TRUE;
		goto final;

	}
	for(int i = 0; i<info.namb; i++)
		for(int j = 0; j<info.namb; j++)
			cost_amb[i][j] = (float)MAYUSCULO;

	//////////////////////////////////////
	//lanza los threads
	mal=lanza_thr_calc();
	//////////////////////////////////////

	//termina de guardar
	if(!mal && !arch_dj.graba_dis(ithr))
	{
		C_log::log(MODULO,"Task %ld,Error %ld no se ha podido guardar la info de ambitos", ithr,GetLastError());
		mal  = TRUE;
	}

final:
	return !mal;
}
//*******************************************************************************************************
BOOL OlvTaskProcess::lanza_thr_calc()
{
	ThCalcCostes th[MAX_THREAD_LEE];
	int nth = min(info.nthr,MAX_THREAD_LEE);
	int ntsk=(int)ceil(info.namb*1./(info.ntsks));
	int n = (int)ceil(ntsk*1./(nth));
	int asig = 0;
	int i=0;
	for(i=0; i<nth && asig<info.namb; i++)
	{
		th[i].ithr = i;
		th[i].pclas = this;
		th[i].mal = FALSE;
		th[i].ini = i*n+ithr*ntsk;
		th[i].fin = min((i+1)*n+ithr*ntsk,info.namb);
		asig=th[i].fin;
		th[i].lanza();
	}
	BOOL mal=FALSE;
	for(int ic=0; ic<i; ic++)
	{
		th[ic].join();
		mal|=th[ic].mal;
	}
	return mal;
}
//*******************************************************************************************************
void ThCalcCostes::run()
{
	mal = FALSE;
	if(!pclas->calcula_cost_amb_sub(ini,fin,ithr))
		mal=TRUE;
}
//*******************************************************************************************************
BOOL OlvTaskProcess::calcula_cost_amb_sub(int amb_ini,int amb_fin, int ith)
{
	int na,i,k;
	int seg;
	Djkt_nodo *costes_nodos;
	BOOL mal=FALSE;
	
	//----------------------------------------
	////////////////
	int na_desp = amb_fin-amb_ini;	
	costes_nodos=NULL;
	////////////////
	FlagsArray visto_ang;//buffer de flags

	C_log::log(MODULO,"Subthr %ld, Ambs %04d a %04d, numero ambitos totales %ld", ith,amb_ini, amb_fin, info.namb);

	seg = GetTickCount();
	/////////////////////////////////////
	//Bucle por cada ámbito de los que le tocan a este thread
	/////////////////////////////////////
	//el coste de un ámbito a sí mismo es el de trabajar ese ámbito, 
	//que es el coste de ir de su conj inicial a la final
	//na=na_ini;	
	/////////////////////////////////////
	for(na=amb_ini;na<amb_fin && !pirate; na++)
	{		
		//En olv_limp->ias[i].ic_ini está almacenado el índice de la conjunción del nodo inicial del ámbito
		//y en olv_limp->ias[i].ic_fin el del final. Se puede acceder con i directamente al array ias porque
		//la info asociada está añadida por orden, primero los ámbitos		
		/////////////////////////////////////////////
		//calcula el coste máximo del ámbito na a todos los demás
		//los añade a la fila na de la matriz de costes
		//es coste máximo porque hace el máximo de:
		//inicio(na)->inicio(ni), inicio(na)->final(ni), final(na)->inicio(ni), final(na)->final(ni)
		/////////////////////////////////////////////
		//k==0, calcula las distancias del nodo inicial de ese ámbito a todas las demás conjunciones
		//k==1, calucla las distancias del nodo final	
		
		for(k=0;k<info.KK;k++)
		{	
			costes_nodos=NULL;
			if(!DijkstraUtiles::dijkstra_ang_inv_ok(costes, angs, info.n, 
				(1-k)*ia.get(na,0)+k*ia.get(na,1), 
				&costes_nodos, &visto_ang))
			{
				C_log::log(MODULO,"Subthr %ld,Error en dijkstra_ang_inv_ok", ith);

				mal=TRUE;
				break;
			}


			//recorre todos los demás ámbitos buscando el coste a ellos en el array de costes devuelto, y los almacena
			//almacena el coste a su nodo inicial y a su nodo final
			if(ia.getFlags(na) & OLV_LIMP_FLG_AMB_NO)
			{
				for (i=0; i<info.n; i++)
				{
					costes_nodos[i].dis=(float)MAYUSCULO;
					costes_nodos[i].id_padre=-1;
					costes_nodos[i].ids_ady.nady=0;
				}
			}
			else
			{
				for(i=0;i<info.namb;i++)
				{
					if(ia.getFlags(i) & OLV_LIMP_FLG_AMB_NO)
						continue;
					if(na==i)
					{
						//el coste de un ámbito a sí mismo es el de trabajar ese ámbito
						cost_amb[na][na]=costes[ia.get(na,0)][ia.get(na,1)];
						continue;
					}

					if(cost_amb[i][na]>costes_nodos[ia.get(i,0)].dis)
						cost_amb[i][na]=costes_nodos[ia.get(i,0)].dis;
					if(info.KK==OLV_AMB_LIN)
					{				
						if(cost_amb[i][na]>costes_nodos[ia.get(i,1)].dis)
							cost_amb[i][na]=costes_nodos[ia.get(i,1)].dis;							
					}
				}
			}	
			if(!arch_dj.add_b(costes_nodos, na, k, TRUE))
			{
				C_log::log(MODULO,"Subthr %ld,Error %ld no se ha podido guardar dj iref: %ld k: %ld", ith,
					GetLastError(),na,k);
			}
		}
		if(mal)
			break;
		//avisa de progreso
		if(((na-amb_ini)%20==0))
		{
			C_log::log(MODULO,"Subthr %ld, Rellenando matriz de dist entre ambs %ld de %ld", ith,
			(na-amb_ini+1),na_desp);
				
		}
	}

	if(mal || pirate)
	{
		C_log::log(MODULO,"Subthr %ld, Error en cálculo de matriz de distancias entre ámbitos", ith);

		return FALSE;
	}
	
	C_log::log(MODULO,"Subthr %ld, Fin Matriz de dist entre ambs, %.3f seg", ith, 1.0*(GetTickCount()-seg)/1000);

	return TRUE;
	
	/////////////////////////////////////
}
//*******************************************************************************************************
BOOL OlvTaskProcess::lee_mats()
{
	//lee archivos de costes, angulos e informacion asociada
	//si !usa_angs, angs=NULL;

	BOOL mal=FALSE;
	CoptiMemo oo(TRUE);
	C_log::log(MODULO,"Task %ld, Memo disp %I64d",ithr, oo.memo);
	int nvect=oo.calc_nvect_multi(info.n,info.nthr,sizeof(Djkt_elem_cola));
	if(nvect<0)
	{
		C_log::log(MODULO,"Task %ld, Error sin memoria al calcular nvect",ithr);
		goto va_mal;
	}
	C_log::log(MODULO,"Task %ld, Calculando con nvect %ld de %ld",ithr, nvect,info.n);
	//inicializa los arrays
	costes.inicializa(info.n,info.nthr,nvect);

	C_log::log(MODULO,"Task %ld, Lee matriz de costes",ithr);
	if(!costes.leeThread(info.path_cconj,info.ext,info.nthr,FALSE)) //el false es para forzar a que todos sean vect, que no los haga igual que los archivos
	{
		C_log::log(MODULO,"Task %ld, Error al leer matriz de costes: %s",ithr, info.path_cconj );
		goto va_mal;
	}

	C_log::log(MODULO,"Task %ld, Lee matriz de angulos",ithr);
	if(info.usa_angs)
	{
		angs = new Djkt_ang_ady[info.n]; 
		if(!angs)
		{
			C_log::log(MODULO,"Task %ld, Error lee_mat sin memoria para %ld Djkt_ang_ady",ithr, info.n);

			mal=TRUE;
		}
		for(int ic=0; ic<info.n && !mal; ic++)
		{
			if(!angs[ic].lee(ic,info.path_ang,info.ext))
			{
				C_log::log(MODULO,"Task %ld,Error en lee_mats", ithr);

				mal=TRUE;
			}
		}
		if(mal)
		{
			C_log::log(MODULO,"Task %ld, Error al leer matriz de angulos: %s",ithr, info.path_ang );
			goto va_mal;
		}
	}

	C_log::log(MODULO,"Task %ld, Lee informacion asociada",ithr);
	if(!ia.leeFile(info.file_iaso))
	{
		C_log::log(MODULO,"Proceso %ld, Error al leer matriz de info aso: %s",ithr, info.file_iaso );

		goto va_mal;
	}

	return TRUE;

va_mal:
	return FALSE;
}
//*******************************************************************************************************
BOOL OlvTaskProcess::guarda_cost_amb()
{
	C_log::log(MODULO,"Task %ld, Guardando costes entre ambitos",ithr);
	char path[MAX_PATH];
	
	sprintf_s(path,MAX_PATH,"%s%02d.%s",info.path_costamb,ithr,info.ext);

	if(!Cdir_manager::crea_dir(info.path_costamb)||!cost_amb.graba(path))
	{
		C_log::log(MODULO,"Task %ld, Error al guardar matriz de costes de ambitos: %s",ithr,path);

		return FALSE;

	}

	return TRUE;
}
//*******************************************************************************************************
void OlvTaskProcess::desconecta()
{
	OlvApp.isConnected = FALSE;
	TaskProcess::desconecta();
}
//*******************************************************************************************************

BOOL InfoIndiceEx::leeFile( char* path )
{
	Cb_file file;
	dat.borra();
	if(!file.abre(path,1,FALSE,TRUE))
	{
		C_log::log(MODULO,"Error en apertura de archivo InfoIndiceEx::leeFile: %s", path);

		return false;
	}
	if(!dat.leer(&file))
	{
		C_log::log(MODULO,"Error en lectura de archivo InfoIndiceEx::leeFile: %s", path);

		return false;
	}
	return TRUE;
}
//*******************************************************************************************************