#include "stdafx.h"
#ifdef OLIVIA_COMPILA
//olivia
#include "olv_reco_thr.h"
#include "olv_thr.h"
#include "olv_limp.h"
#include "olv.h"
#include "olv_reco.h"
#include "olv_geom.h"
#include "olv_csv.h"
#include "olv_sens_ws.h"
#include "math.h"
#include <iostream>
#include <sstream>
#include <string>
//utiles
#include "b_file.h"
#include "Fdbf.h"
#include "ManagerDbfGdataTable.h"
using namespace std;
/**
*	@file olv_limp_thr.h
*	Archivo de implementaciones del thread de control de la utilidad de recogida de residuos del programa Olivia.
*/
Colv_reco_thr::Colv_reco_thr(Colv_reco *olv_reco) : Colv_limp_thr(olv_reco)
{
	this->olv_reco = olv_reco;
}

Colv_reco_thr::~Colv_reco_thr(void)
{
	//destruye los subthreads
	if(subthrs)
	{
		for(int i=0;i<n_subthr;i++)
		{
			if(subthrs[i])
				delete subthrs[i];
		}
		free(subthrs);
		subthrs=NULL;
	}	
	if(olv_limp->tramos)
		delete [] olv_limp->tramos;
}
//*************************************************************************************
void Colv_reco_thr::inicia_th()
{
	inicia(OLV_MILIS_COLA,&cola_proc,-1,"reco_thr");
	olvlog(LOG_TODO,"olv_limp_t","Thread de recogida reco_thr arrancado");	
	borra_temp_files();
	pirate=FALSE;
}
//*************************************************************************************
/**
 * Cola de procesos en la que itera el thr cuando es recogida. Override de limpieza, así que se implementan\n
 * solo los eventos que tienen sentido en recogida y son diferentes que en limpieza
 */
void Colv_reco_thr::cola_proc(int evento, OlvAsync_cola<Param_olv_limp_thr> *clase,Param_olv_limp_thr *e)
{
	BOOL bien=TRUE;
	BOOL hecho=FALSE;

	Colv_reco_thr *this_i=static_cast<Colv_reco_thr *>(clase);
	switch (evento)
	{
	case OLV_LIMP_EV_RELL_DAT:
		{
			hecho=TRUE;
			bien=this_i->rellena_datos();
			if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
			{
				if(this_i->olv_reco->info_sens.url[0]==0)
					this_i->encola(OLV_LIMP_EV_UNE_AMB_NW,NULL,FALSE);
				else
					this_i->encola(OLV_RECO_EV_SENS,NULL,FALSE);
			}
			break;
		}
	case OLV_RECO_EV_SENS:
		{
			//esta tarea lanza varios subthreads para realizar las peticiones de carga a los
			//sensores(les encola la tarea pide_info_sensores_sub), 
			//y estos cuando acaban le encolan al padre (el que los ha lanzado)
			//la tarea de dist_conj_fin
			hecho=TRUE;
			bien=this_i->pide_info_sens();
			break;
		}
	case OLV_RECO_EV_SENS_SUB:
		{
			//aquí entran los subthreads para hacer los cálculos de ángulos, cuando acaban
			//encolan al padre la tarea de fin
			int ithr;
			hecho=TRUE;
			if(e!=NULL)
				ithr=e->id_e;
			this_i->pide_info_sens_sub(ithr);
			break;
		}
	case OLV_RECO_EV_SENS_FIN:
		{
			//aquí entra el padre cuando van acabando los subthreads
			//si han terminado todos encola la siguiente tarea
			int i;
			int nno;
			hecho=TRUE;
			this_i->n_subthr_fin++;
			nno=0;
			if(this_i->n_subthr_fin==this_i->n_subthr)
			{		
				this_i->n_subthr_fin=0;
				for(i=0;i<this_i->n_subthr;i++)
				{
					if(this_i->subthrs[i]->prog_subthr<0)
						break;
					nno+=(int)this_i->subthrs[i]->prog_subthr;
				}
				if(i<this_i->n_subthr)
				{
					bien=FALSE;
					this_i->pon_mi_msg("Errores en la conexión con la base de datos de los sensores");
					break;
				}					
				bien=this_i->pide_info_sens_fin(nno);
				if(bien && (this_i->olv->modo_ejec<OLV_EJEC_DEBUG_NOSIGUE) && !this_i->pirate)//sigue
					this_i->encola(OLV_LIMP_EV_UNE_AMB_NW,NULL,FALSE);
			}
			break;
		}
	}
	if(!bien)
	{
		this_i->pon_mi_progre(OLV_TAREA_FIN_NOK,0);
	}
	if(!hecho)
		Colv_limp_thr::cola_proc(evento, clase,e);
}
//*************************************************************************************
/**
 * Rellena la información asociada de la red navegable y los datos de limpieza
 */
BOOL Colv_reco_thr::rellena_datos()
{	
	int icampu,icampkg,ia,uds_,icampcap,icampid,icampoid, capa_, idd;
	char nfile[MAX_PATH];
	Cb_file f;
	Fdbf dbf;
	char *uds, *kg, *capa, *id;
	double kg_,auxi;
	BOOL ret=TRUE;

	olvlog(LOG_TODO,"olv_limp_t","Rellenando matriz de info asociada a ámbitos");
	pon_mi_progre(OLV_TAREA_IMP, (int) (OliviaDef::GeneralDef::ProgrMax*2/3));
	
	uds=kg=capa=id=0;

	//lee dbf del shp
	strcpy_s(nfile,MAX_PATH,olv->paths.path_data);
	//cambiaext(nfile,".shp",".dbf");
	strcpy((Cdir_manager::extension_archivo(nfile)),"dbf");

	if(!f.abre(nfile,1) || !dbf.lee(&f))
	{
		pon_mi_msg("Error al abrir %s",nfile);
		ret=FALSE;
		goto fin;
	}

	//busca el campo de unidades
	icampu=dbf.findCol(olv_reco->camps_r.campo_uds);
	if(icampu==-1)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"No encontrado campo %s en\n%s",olv_reco->camps_r.campo_uds,nfile);
		ret=FALSE;
		goto fin;
	}
	icampoid=dbf.findCol(OLV_NOMB_OID);
	icampkg=icampcap=icampid=-1;
	//busca el campo de kgrec, si es el caso
	//si es 0 los kg por defecto, se lee el campo de kg, si es negativo, se lee el campo de capacidad porque o bien están
	//llenos o bien se lee la info de los sensores, pero tiene densidad
	if(olv_reco->kg_reco_def==0)	
	{
		icampkg=dbf.findCol(olv_reco->camps_r.campo_kgcont);
		if(icampkg==-1)
		{
			sprintf_s(err_str,OLV_MAX_ERR,"No encontrado campo %s en\n%s",olv_reco->camps_r.campo_kgcont,nfile);
			ret=FALSE;
			goto fin;
		}
	}
	else if(olv_reco->kg_reco_def<=0)//busca el campo de capacidad, si es el caso
	{
		icampcap=dbf.findCol(olv_reco->camps_r.campo_capa);
		if(icampcap==-1)
		{
			sprintf_s(err_str,OLV_MAX_ERR,"No encontrado campo %s en\n%s",olv_reco->camps_r.campo_capa,nfile);
			ret=FALSE;
			goto fin;
		}
		if(olv_reco->info_sens.camps.id[0])//es el caso de los sensores
		{
			icampid=dbf.findCol(olv_reco->info_sens.camps.id);
			if(icampid==-1)
			{
				sprintf_s(err_str,OLV_MAX_ERR,"No encontrado campo %s en\n%s",olv_reco->info_sens.camps.id,nfile);
				ret=FALSE;
				goto fin;
			}
		}
	}
	
	idd =dbf.leeNexRow();
	ia=0;
	while(idd == 1)
	{	
		///////////////////////////////
		uds_=1;
		uds_=dbf.getI(icampu);
		if(uds_<0 || uds_>50)
		{
			uds_=1;//pone por def
			olvlog(LOG_TODO,"olv_limp_t","Cuidado, info asociada %ld, puesto unidades por defecto a 1",ia+1);		
		}
		olv_limp->iaso[ia].inf_r.uds=uds_;

		///////////////////////////////		
		if(icampkg>-1)
		{		
			kg_=dbf.getI(icampkg);
			/*//por si viene con notación científica
			stringstream ss(kg);			
			ss >> kg_;
			if (ss.fail()) {kg_=0;}
			/////////////////////////////////
			//kg_=atof(dd);*/
			if(kg_<0 || kg_>10000)
			{
				kg_=50;//pone por def
				olvlog(LOG_TODO,"olv_limp_t","Cuidado, info asociada %ld, puesto kg por defecto a 50",ia+1);		
			}
			uds_=1; //pone las uds a 1 para no multiplicar: en caso de que venga el campo de carga ya está multiplicado
		}
		else if(icampcap>-1)
		{		
			capa_=dbf.getI(icampcap);
			if(capa_<0 || capa_>100000)
			{
				capa_=3000;//pone por def
				olvlog(LOG_TODO,"olv_limp_t","Cuidado, info asociada %ld, puesto capacidad por defecto a 3000 l",ia+1);		
			}
			kg_=capa_*olv_reco->dens_frac/1000; //en kg /1000 para pasar de m3 a l
		}
		else
			kg_=olv_reco->kg_reco_def;
		olv_limp->iaso[ia].inf_r.kg=kg_*uds_;//pone la carga total como la carga por el número de contenedores

		///////////////////////////////	

		if(icampid>=0)
		{			
			olv_limp->iaso[ia].inf_r.id = (char*)malloc(dbf.getSize(icampid)+1);
			if(!olv_limp->iaso[ia].inf_r.id)
				break;

			olv_limp->iaso[ia].inf_r.id[0]=0;
			if(dbf.getType(icampid)==DBF_TYPE_DATA_STR)
			{
				strcpy(olv_limp->iaso[ia].inf_r.id,dbf.getStr(icampid));
			}
			else
			{
				auxi=dbf.getD(icampid);
				if(auxi==(double)(int)auxi)
				{
					sprintf(olv_limp->iaso[ia].inf_r.id,"%ld",(int)auxi);
				}
				else
				{
					sprintf(olv_limp->iaso[ia].inf_r.id,"%lf",auxi);
				}
			}
		}

		if(icampoid>=0)
			olv_limp->iaso[ia].oid = dbf.getI(icampoid);

		//olvlog(LOG_TODO,"olv_limp_t","Rellena %0d %3.1f %ld %04d",ia, kg_,uds_,olv_limp->iaso[ia].oid);	

		///////////////////////////////
		//avisa de progreso
		if((ia%100==0) || (ia==(olv_limp->n_amb-1)))
		{
			pon_mi_progre(OLV_TAREA_IMP, (int) (OliviaDef::GeneralDef::ProgrMax*
				((1.0*(ia+1)/olv_limp->n_amb)/3)+2/3));
			olvlog(LOG_TODO,"olv_limp_t","Rellenando info asociada a ámbitos, %ld de %ld",
				ia+1,olv_limp->n_amb);
		}

		ia++;
		idd =dbf.leeNexRow();
	}
	if(ia<olv_limp->n_amb)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error al leer información asociada %ld en\n%s",ia,nfile);
		ret=FALSE;
		goto fin;
	}

	olvlog(LOG_TODO,"olv_limp_t","Finaliza Matriz de info asociada a ámbitos");	
	
fin:
	if(!ret)
		olvlog(LOG_TODO,"olv_limp_t","Fallos en Matriz de info asociada a ámbitos");

	olvlog(LOG_TODO,"olv_limp_t","Giro límite %lf",olv_limp->ang_lim);

	return ret;
}
//*************************************************************************************
/**
 * Para la conexión a la lectura de sensores
 */
BOOL Colv_reco_thr::pide_info_sens()
{
	olvlog(LOG_TODO,"olv_limp_t","Leyendo info de los sensores");
	pon_mi_progre(OLV_TAREA_SENS, 0);

	//Inicia el array donde se guarda la info de carga
	olv_reco->info_carg = (int *)malloc(olv_limp->n_amb*sizeof(int));
	if(!olv_reco->info_carg)
	{
		sprintf_s(err_str,OLV_MAX_ERR,"Error, sin memoria para info de carga");
		return FALSE;
	}

	//lanza los threads
	lanza_subthrs(OLV_RECO_EV_SENS_SUB);

	return TRUE;
}
//*************************************************************************************
/**
 * Rellena los valores de los sensores de cada contenedor
 * El thread entra aquí cuando los subthreads que realizan la tarea realmente han finalizado
 */
BOOL Colv_reco_thr::pide_info_sens_fin(int nno)
{	
	class AddColPorc : public IAddColDbf
	{
	public:
		Colv_reco *olv_reco;
		AddColPorc(Colv_reco *rr)
		{
			this->olv_reco=rr;
		}
		virtual void setData(int i, void *data)
		{
			if(data)
			{
				memcpy(data,(void*)&olv_reco->info_carg[i],sizeof(int));
			}

		};
	};
	AddColPorc dataDbf(olv_reco);
	ManagerDbfGdataTable dbfmgr;
	char path_dbf[MAX_PATH];
	////////////////	
	//para los threads
	para_subthrs();	

	//guarda la info al shp
	strcpy_s(path_dbf,MAX_PATH,olv_limp->olv->paths.path_data);
	//cambiaext(path_dbf,".shp",".dbf");
	strcpy((Cdir_manager::extension_archivo(path_dbf)),"dbf");
	if(!dbfmgr.AddCol(path_dbf,"PORC_RECO",GdataTable::Tint,&dataDbf))
	//if(!olv_limp->olv->olv_sh->add_col_dbf(path_dbf,olv_limp->n_amb,TIPO_IA_INT,(char*)olv_reco->info_carg,"PORC_RECO",err_str,OLV_MAX_ERR))
	{
		free(olv_reco->info_carg);
		olv_reco->info_carg=NULL;
		return FALSE;
	}

	olvlog(LOG_TODO,"olv_limp_t","FIN %ld peticiones de carga a sensores",
		olv_limp->n_amb);

	free(olv_reco->info_carg);
	olv_reco->info_carg=NULL;
	return TRUE;
}
//*************************************************************************************
/**
 * Rellena los valores de los sensores, es la parte de cálculos que 
 * realizan los subthreads. 'ithr' indica qué thread es, para calcular qué ámbitos le tocan.
 */
void Colv_reco_thr::pide_info_sens_sub(int ithr)
{
	int na_ini,na_fin,na_desp,na,nno;
	int KK, seg;
	Param_olv_limp_thr pp;
	Colv_sens_ws sens;
	double carg;
	BOOL mal=FALSE;

	const int SZ_CAMP =32;
	const int SZ_SENTEN =1024;
	char nfile[MAX_PATH];

	strcpy_s(nfile,MAX_PATH,olv->paths.path_data);
	//cambiaext(nfile,".shp",".dbf");
	strcpy((Cdir_manager::extension_archivo(nfile)),"dbf");

	////////////////
	pp.id_e=OLV_TAREA_SENS;//manda de parámetro la tarea de la que es el progreso
	KK=olv_limp->tipo_ambit;
	na_desp = (int)ceil(1.0*(olv_limp->n_amb)/n_subthr);	
	na_ini=ithr*na_desp;
	na_fin = min((ithr+1)*na_desp,olv_limp->n_amb);
	nno=0;
	////////////////
	
	olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Ambs %04d a %04d", ithr,na_ini, na_fin);
	
	seg = GetTickCount();

	/////////////////////////////////////
	//Conecta con el servicio
	sens.inicia(&olv_reco->info_sens);	
	/////////////////////////////////////

	/////////////////////////////////////
	//Bucle por cada ámbito de los que le tocan a este thread para pedir su carga
	/////////////////////////////////////
	for(na=na_ini;na<na_fin && !pirate; na++)
	{		
		carg=0;

		if(!olv_limp->iaso[na].inf_r.id || strlen(olv_limp->iaso[na].inf_r.id)==0)
		{
			olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Error en la petición de carga de contenedor %ld, no hay ID",
				ithr,na);
			carg=100;		
			olv_reco->info_carg[na]=(int) carg;
			continue;
		}

		/////////////////////////////////////
		//Tiene el id en info2
		carg = sens.dame_porc_cont_i(olv_limp->iaso[na].inf_r.id);
		if(carg==0)
		{
			olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Error en la petición de carga de contenedor %s: %s",ithr,
				olv_limp->iaso[na].inf_r.id,sens.err_str);
			carg=100;				
		}
		olv_reco->info_carg[na]=(int) carg;

		/////////////////////////////////////
		//Pone la carga recibida		
		if(carg>=olv_reco->info_sens.porc_lim)//Si la carga supera el valor límite, la pone
			olv_limp->iaso[na].inf_r.kg *= carg/100; //info1 contiene antes los kg del contenedor si estuviera lleno
		else
		{
			olv_limp->iaso[na].flgs |= OLV_LIMP_FLG_AMB_NO; //lo marca para no recogerlo
			nno++;
		}	

		//avisa de progreso
		if(((na-na_ini)%50==0) || ((na-na_ini)==(na_desp-1)))
		{
			olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Pidiendo info de carga a sensores %ld de %ld", ithr,
				(na-na_ini+1),na_desp);
			//avisa de progreso	
			prog_subthr=(1.0*(na-na_ini+1)/na_desp);
			thr_padre->encola(OLV_LIMP_EV_SUBTHR_PROG,&pp,FALSE);
		}
	}

	if(mal)
	{
		olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Error al pedir info de carga a sensores");
		prog_subthr=-1;//para avisar al padre de que ha habido un error

	}
	else
	{
		olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Fin peticiones de carga a sensores, %.3f seg", ithr, 1.0*(GetTickCount()-seg)/1000);
		prog_subthr=nno;
	}
	thr_padre->encola(OLV_RECO_EV_SENS_FIN,NULL,FALSE);

	/////////////////////////////////////
}
//*************************************************************************************
/**
 * Añade a la red de conjunciones en qué conjunción está la planta y la instalación
 */
BOOL Colv_reco_thr::pon_nodos_planta(double pt[3])
{	
	double pt_[3];
	memcpy(pt_,pt,3*sizeof(double));

	if(!Colv_limp_thr::pon_nodos_planta(pt))//es la instalación olv_limp->coor_instal
		return FALSE;

	if(Colv_geom::pto_equals(pt_, olv_reco->coor_plant))
	{
		memcpy(olv_reco->coor_plant,pt,3*sizeof(double));		
	}
	else
	{
		if(!Colv_limp_thr::pon_nodos_planta(olv_reco->coor_plant))
			return FALSE;
	}

	return TRUE;	
}
//*************************************************************************************
/**
 * Apunta en qué nodos está la planta y la instalación
 */
BOOL Colv_reco_thr::busca_conjs_planta(double pt[3], int *nod)
{
	double pt_[3];
	memcpy(pt_,pt,3*sizeof(double));

	if(!Colv_limp_thr::busca_conjs_planta(pt,nod))//es la instalación olv_limp->coor_instal, olv_limp->nod_instal
		return FALSE;

	if(Colv_geom::pto_equals(pt_, olv_reco->coor_plant))
	{
		olv_reco->nod_plant=*nod;	
	}
	else
	{
		if(!Colv_limp_thr::busca_conjs_planta(olv_reco->coor_plant,&olv_reco->nod_plant))
			return FALSE;
	}

	return TRUE;	
}
//*************************************************************************************
double Colv_reco_thr::dame_cost_jornada()
{
	return olv_limp->t_conv-olv_reco->t_sal*2-olv_limp->t_desc;
}
//*************************************************************************************
/**
 * Calcula el coste de los ámbitos a la planta e instalación
 */
BOOL Colv_reco_thr::calcula_cost_plant()
{
	int ic,ia,ka,nais, KK, ref_ia;
	Djkt_nodo *costes_nodos;
	BOOL mal=FALSE;

	//Inicia el array de orden /secuencia
	olv_reco->ord_sec_plan=(Secu_amb*)malloc(sizeof(Secu_amb)*2);
	if(!olv_reco->ord_sec_plan)
	{
		pon_mi_msg("Error, sin memoria para matriz de orden y secuencia");
		return FALSE;
	}
	memset(olv_reco->ord_sec_plan,0,sizeof(Secu_amb)*2);
	olvlog(LOG_TODO,"olv_limp_t","Calculando coste a planta e instalación");

	costes_nodos=NULL;
	if(olv_reco->nod_plant==olv_reco->nod_instal)
		KK=1;
	else
		KK=2;
	for(int k=0;k<KK;k++)
	{
		if(k==OLV_PLANT)//plant
			ic=olv_reco->nod_plant;
		else if(k==OLV_INSTAL)//instal
			ic=olv_reco->nod_instal;

		if(!Colv_geom::dijkstra_ang_inv_ok(olv_limp->cost_conj, olv_limp->ang_conj, olv_limp->conjs.n, 
			ic, &costes_nodos, &visto_ang))
		{
			mal=TRUE;
			break;
		}	
		
		olv_reco->ord_sec_plan[k].ctnod[0]=costes_nodos;
		olv_reco->ord_sec_plan[k].ctnod[1]=NULL;

		costes_nodos=NULL;
		
		//revisa si está aislado de algún ámbito
		nais=0;
		for(ia=0;ia<olv_limp->n_amb;ia++)
		{
			ref_ia=olv_limp->carto.get(ia).entity()->ref;
			if(olv_limp->iaso[ref_ia].flgs & OLV_LIMP_FLG_AMB_NO)
				continue;
			for(ka=0;ka<olv_limp->tipo_ambit;ka++)
			{			
				if(olv_reco->ord_sec_plan[k].ctnod[0][olv_limp->iaso[ref_ia].inod[ka]].dis>=MAYUSCULO)
				{
					nais++;
				}
			}
		}
		if(nais)
		{
			mal=TRUE;
			break;
		}
	}

	if(mal)
	{
		pon_mi_msg("Error al calcular costes de ámbitos a instalación");
		return FALSE;
	}

	if(KK==1)
	{
		olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0]=olv_reco->ord_sec_plan[OLV_INSTAL].ctnod[0];
		olv_reco->ord_sec_plan[OLV_PLANT].ctnod[1]=olv_reco->ord_sec_plan[OLV_INSTAL].ctnod[1];
	}

	////////////////////
	//inicializa array 
	olv_reco->ptos_vaci=(short*)malloc(olv_limp->n_amb*sizeof(short));
	if(!olv_reco->ptos_vaci)
		return FALSE;
	memset(olv_reco->ptos_vaci,0,olv_limp->n_amb*sizeof(short));	

	return TRUE;
}
//*************************************************************************************
/**
 *	Calcula el coste de desplazamiento de ir de ir por todos los ambitos sec desde ini hasta fin
 */
double Colv_reco_thr::dame_coste( Secu_amb * sec, int ini, int fin, Info_sec	*s, BOOL ind_abs)
{
	double d=0;
	int ind_cost, ind_cost1;
	int fin_old=fin;
	int id_ambf, ref_ambf;
	int id_ambf1;
	double capac_v=olv_reco->kg_max, cap_act=0,cap_h, cap_t;
	int nv_p, i, sel;//numero de veces por ir a planta
	double coste;
	double cap_g, dd;
	cap_t=cap_act;
	
	while(ini<fin)
	{
		id_ambf=s->iamb[sec[fin].iamb];
		id_ambf1=s->iamb[sec[fin-1].iamb];

		ref_ambf = olv_limp->carto.get(id_ambf).entity()->ref;


		if (ind_abs)
			ind_cost=id_ambf;
		else
			ind_cost=sec[fin].iamb;

		cap_t+=olv_reco->iaso[ref_ambf].inf_r.kg;//suma a la carga la basura del ambito 
		d+=olv_limp->cost_amb[id_ambf][id_ambf];//suma el coste del ambito
		d+=olv_limp->arch_dj.dame_dis(id_ambf1, 0, id_ambf,sec[fin].entrada);
		
		fin--;		
	}
	
	
	if (ind_abs)
		ind_cost=s->iamb[sec[ini].iamb];
	else
		ind_cost=sec[ini].iamb;
	id_ambf=s->iamb[sec[ini].iamb];
	d+=olv_reco->cost_amb[id_ambf][id_ambf];//suma el coste de hacer el primer ambito
	
	if(ini==0)//si ini es 0 falta sumar el coste de la planta a el primer ambito
	{		
		d+=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_instal, 0, s->iamb[sec[ini].iamb],0);
		d+=olv_reco->t_sal; //suma el coste de la salida
	}
	
	cap_t+=olv_limp->iaso[olv_limp->carto.get(id_ambf).entity()->ref].inf_r.kg;//suma a la carga total la basura del primer ambito	

	nv_p=(int)(cap_t/capac_v +1);//numero de veces que se tendra que ir a planta
	cap_h=nv_p*capac_v-cap_t;//carga con la que se puede jugar (holgura) capacidad desaprovechada
	if(cap_h>=capac_v)
	{
		cap_h-=capac_v;
		nv_p--;
	}
	
	cap_t+=olv_reco->iaso[olv_limp->carto.get(ind_cost).entity()->ref].inf_r.kg;
	//suma coste de ir a planta

	if (ind_abs)
		ind_cost=s->iamb[sec[fin_old].iamb];
	else
		ind_cost=sec[fin_old].iamb;
	id_ambf=s->iamb[sec[fin_old].iamb];//id del ultimo ambito

	nv_p--;//se descuenta uno porque se tiene que terminar en planta
	d+=olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0][olv_reco->iaso[olv_limp->carto.get(id_ambf).entity()->ref].inod[0]].dis;//suma el coste de ir del ultimo ambito a la planta
	d+=olv_reco->t_descarg;//suma el coste de descargar
	d+=olv_reco->ord_sec_plan[OLV_INSTAL].ctnod[0][olv_reco->nod_plant].dis;//suma el coste de ir de planta a instalacion
	d+=olv_reco->t_sal;//suma el coste de la llegada

	int iold=-1;
	BOOL errores=FALSE;
	double cos_tray=d;
	int veces_plan=nv_p;
	BOOL salir=FALSE;
	double cap_ult_cont;
	while (!salir)
	{
		salir=TRUE;
		cap_h=(1+veces_plan)*capac_v-cap_t;
		nv_p=veces_plan;
		coste=MAYUSCULO;
		cap_g=0;
		sel=-1;
		d=cos_tray;
		cap_act=0;
		int isel_old=-1;
		double cap_old;
		i=ini;
		
		while(nv_p>0 && i<=fin_old)
		{
			if (ind_abs)
				ind_cost=s->iamb[sec[i].iamb];
			else
				ind_cost=sec[i].iamb;
			id_ambf=s->iamb[sec[i].iamb];//id del ambito iesimo de la secuen
			ref_ambf = olv_limp->carto.get(id_ambf).entity()->ref;
			cap_old=cap_act;
			cap_act+=olv_reco->iaso[ref_ambf].inf_r.kg;//suma capacidad del ambito de la secuencia iesima
			cap_ult_cont=olv_reco->iaso[ref_ambf].inf_r.kg;
			i++;
			if(i>fin_old)
			{
				if(cap_act<capac_v)
					break;
			}
			id_ambf1=s->iamb[sec[i].iamb];//id del ambito iesimo+1 de la secuen
			if (ind_abs)
				ind_cost1=s->iamb[sec[i].iamb];
			else
				ind_cost1=sec[i].iamb;
			if((capac_v-cap_act)>cap_h)
			{
				//calcula si el siguiente entra
				
				if((cap_act+olv_reco->iaso[olv_limp->carto.get(id_ambf1).entity()->ref].inf_r.kg)>capac_v)
				{
					nv_p++;
					cap_h=cap_h+capac_v;
				}
				else
					continue;
			}
			 if(cap_act-capac_v<=0)
			{
				//prueba candidato
				//calcula el coste de ir a planta desde el i-1 y de planta a el i y se le resta el coste de ir del i-1 al i 
				dd=olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0][olv_reco->iaso[ref_ambf].inod[0]].dis;//coste del i-1 a planta
				dd+=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_plan,0,id_ambf1, 0);
				dd-=olv_limp->arch_dj.dame_dis(id_ambf,0,id_ambf1, 0);
							
				dd+=olv_reco->t_descarg;//suma el coste de descargar
				if(dd>=MAYUSCULO)
					errores=TRUE;//existen errores
				if(coste>dd)
				{
					sel=i;
					coste=dd;
					cap_g=capac_v-cap_act;
				}
			}
			else
			{
				//pone candidato
				//suma coste de ir a la planta y el de volver de ella
				if(coste>=MAYUSCULO)
				{
					if(errores)
						olvlog(LOG_TODO,"olv_limp_t","No conseguido candidato para ir a descargar");//algo va mal
					//pone una vuelta mas a planta en el i-1;
					salir=FALSE;
					veces_plan++;
					if(cap_ult_cont>capac_v)
					{
						olvlog(LOG_TODO,"olv_limp_t","Capacidad de contenedor %ld mas grande que la del vehiculo ", i);//algo va mal
						return MAYUSCULO;
					}
					break;
					//calcula coste

				}
				cap_act=0;
				cap_h-=cap_g;
				iold=i;
				isel_old=sel;
				i=sel;
				d+=coste;
				cap_g=0;
				coste=MAYUSCULO;
				sel=-1;
				nv_p--;

			}
		}
	}
	return d;	
}
//*************************************************************************************
/** 
 * Rellena los tiempos de desplazamiento
 */
void Colv_reco_thr::pon_t_desp(Info_sec *s, Secu_amb *sec)
{
	if((olv_limp->nod_instal>=0) && (s->namb>1))
	{				
		s->t_despl[0]=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_instal,0 ,s->iamb[sec[0].iamb],sec[0].entrada);
		s->t_despl[1]=olv_limp->ord_sec_plan[OLV_PLANT].ctnod[0][olv_reco->nod_instal].dis;
		
	}	
}
//*************************************************************************************
/**
 *	Calcula el coste de desplazamiento de ir por todos los ambitos sec desde ini hasta fin, e indica en qué puntos se va a vaciar
 */
double Colv_reco_thr::dame_coste_pon_viajes( Secu_amb * sec, int ini, int fin, Info_sec	*s, int *nvac)
{
	double d=0;
	int ind_cost, ind_cost1;
	int fin_old=fin;
	int id_ambf, ref_ambf;
	int id_ambf1;
	double capac_v=olv_reco->kg_max, cap_act=0,cap_h, cap_t;
	int nv_p, i, sel;//numero de veces por ir a planta
	double coste;
	double cap_g, dd;
	cap_t=cap_act;	

	BOOL ind_abs=TRUE;
	
	while(ini<fin)
	{
		id_ambf=s->iamb[sec[fin].iamb];
		id_ambf1=s->iamb[sec[fin-1].iamb];


		if (ind_abs)
			ind_cost=id_ambf;
		else
			ind_cost=sec[fin].iamb;
		ref_ambf = olv_limp->carto.get(id_ambf).entity()->ref;
		
		cap_t+=olv_reco->iaso[ref_ambf].inf_r.kg;//suma a la carga la basura del ambito 
		d+=olv_limp->cost_amb[id_ambf][id_ambf];//suma el coste del ambito
		d+=olv_limp->arch_dj.dame_dis(id_ambf1, 0, id_ambf,sec[fin].entrada);
		fin--;		
	}
	if (ind_abs)
		ind_cost=s->iamb[sec[ini].iamb];
	else
		ind_cost=sec[ini].iamb;
	id_ambf=s->iamb[sec[ini].iamb];
	d+=olv_reco->cost_amb[id_ambf][id_ambf];//suma el coste de hacer el primer ambito
	
	if(ini==0)//si ini es 0 falta sumar el coste de la planta a el primer ambito
	{
		d+=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_instal, 0, s->iamb[sec[ini].iamb],0);
		d+=olv_reco->t_sal;//suma el coste de la salida
	}
	
	cap_t+=olv_limp->iaso[olv_limp->carto.get(id_ambf).entity()->ref].inf_r.kg;//suma a la carga total la basura del primer ambito

	//////////////////
	//lo almacena
	s->dis_med=(float)cap_t;
	//////////////////

	nv_p=(int)(cap_t/capac_v +1);//numero de veces que se tendra que ir a planta
	cap_h=nv_p*capac_v-cap_t;//carga con la que se puede jugar (holgura) capacidad desaprovechada
	if(cap_h>=capac_v)
	{
		cap_h-=capac_v;
		nv_p--;
	}
	
	cap_t+=olv_reco->iaso[olv_limp->carto.get(ind_cost).entity()->ref].inf_r.kg;

	//suma coste de ir a planta
	if (ind_abs)
		ind_cost=s->iamb[sec[fin_old].iamb];
	else
		ind_cost=sec[fin_old].iamb;
	id_ambf=s->iamb[sec[fin_old].iamb];//id del ultimo ambito

	nv_p--;//se descuenta uno porque se tiene que terminar en planta
	d+=olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0][olv_reco->iaso[olv_limp->carto.get(id_ambf).entity()->ref].inod[0]].dis;//suma el coste de ir del ultimo ambito a la planta
	d+=olv_reco->ord_sec_plan[OLV_INSTAL].ctnod[0][olv_reco->nod_plant].dis;//suma el coste de ir de planta a instalacion
	d+=olv_reco->t_sal;//suma el coste de la llegada
	d+=olv_reco->t_descarg;//suma el coste de descargar
	///////////////////////////
	coste=MAYUSCULO;
	
	int iold=-1;
	BOOL errores=FALSE;
	double cos_tray=d;
	int veces_plan=nv_p;
	BOOL salir=FALSE;
	double cap_ult_cont;
	while (!salir)
	{
		salir=TRUE;
		cap_h=(1+veces_plan)*capac_v-cap_t;
		nv_p=veces_plan;
		coste=MAYUSCULO;
		cap_g=0;
		sel=-1;
		d=cos_tray;
		cap_act=0;
		int isel_old=-1;
		double cap_old;
		i=ini;
		//borra marcas------------
		for(int ii=0; ii<fin_old-1; ii++)
		{
			id_ambf=s->iamb[sec[ii].iamb];
			olv_reco->ptos_vaci[id_ambf]=0;
		}
		while(nv_p>0 && i<=fin_old)
		{
			if (ind_abs)
				ind_cost=s->iamb[sec[i].iamb];
			else
				ind_cost=sec[i].iamb;
			id_ambf=s->iamb[sec[i].iamb];//id del ambito iesimo de la secuen
			ref_ambf = olv_limp->carto.get(id_ambf).entity()->ref;
			cap_old=cap_act;
			cap_act+=olv_reco->iaso[ref_ambf].inf_r.kg;//suma capacidad del ambito de la secuencia iesima
			cap_ult_cont=olv_reco->iaso[ref_ambf].inf_r.kg;
			i++;
			if(i>fin_old)
			{
				if(cap_act<capac_v)
					break;
			}
			id_ambf1=s->iamb[sec[i].iamb];//id del ambito iesimo+1 de la secuen
			if (ind_abs)
				ind_cost1=s->iamb[sec[i].iamb];
			else
				ind_cost1=sec[i].iamb;
			if((capac_v-cap_act)>cap_h)
			{
				//calcula si el siguiente entra
				
				if((cap_act+olv_reco->iaso[olv_limp->carto.get(id_ambf1).entity()->ref].inf_r.kg)>capac_v)
				{
					nv_p++;
					cap_h=cap_h+capac_v;
				}
				else
					continue;
			}
			 if(cap_act-capac_v<=0)
			{
				
				//prueba candidato
				//calcula el coste de ir a planta desde el i-1 y de planta a el i y se le resta el coste de ir del i-1 al i 
				dd=olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0][olv_reco->iaso[ref_ambf].inod[0]].dis;//coste del i-1 a planta
				
				dd+=olv_limp->arch_dj.dame_dis(olv_limp->arch_dj.id_plan,0,s->iamb[sec[i].iamb],0);
				dd-=olv_limp->arch_dj.dame_dis(id_ambf, 0, s->iamb[sec[i].iamb],0);
				
				dd+=olv_reco->t_descarg;//suma el coste de descargar
				if(dd>=MAYUSCULO)
					errores=TRUE;//existen errores
				if(sel==-1
					|| (coste>dd))
				{
					sel=i;
					coste=dd;
					cap_g=capac_v-cap_act;
				}
			}
			else
			{
				//suma coste de ir a la planta y el de volver de ella
				if(coste>=MAYUSCULO)
				{
					if(errores)
						olvlog(LOG_TODO,"olv_limp_t","No conseguido candidato para ir a descargar");//algo va mal
					//pone una vuelta mas a planta en el i-1;
					salir=FALSE;
					veces_plan++;
					if(cap_ult_cont>capac_v)
					{
						olvlog(LOG_TODO,"olv_limp_t","Capacidad de contenedor %ld mas grande que la del vehiculo ", i);//algo va mal
						return MAYUSCULO;
					}
					break;
					//calcula coste

				}
				cap_act=0;
				cap_h-=cap_g;
				iold=i;
				isel_old=sel;
				i=sel;
				///////////////
				//pone candidato
				olv_reco->ptos_vaci[s->iamb[sec[i-1].iamb]]=(short)OLV_IDA_PLANT;
				///////////////
				d+=coste;
				cap_g=0;
				coste=MAYUSCULO;
				sel=-1;
				nv_p--;

			}
		}
	}	

	//Cuenta el número de veces que va a vaciar
	sel=0;
	for(i=0;i<s->namb;i++)
	{
		if(olv_reco->ptos_vaci[s->iamb[sec[i].iamb]])
			sel++;
	}
	id_ambf=s->iamb[sec[fin_old].iamb];//id del ultimo ambito
	olv_reco->ptos_vaci[id_ambf]=(short)OLV_IDA_PLANT_ULT; //indica que en el último se va a planta
	
	*nvac=sel;

	return d;	
}
//*************************************************************************************
/**
 * Lanza sub-threads 
 */
void Colv_reco_thr::lanza_subthrs(int tar, int nthr_def/*=-1*/)
{
	char nomb[32];
	Param_olv_limp_thr pp;
	int nn;
	if((nthr_def>0) && (nthr_def<n_subthr))
		nn=nthr_def;
	else
		nn=n_subthr;
	//Arranca los subthreads
	for(int i=0;i<nn;i++)
	{
		if(!subthrs[i])
			subthrs[i]=new Colv_reco_thr(olv_reco);
		sprintf_s(nomb,32,"limp_subth_%ld",i);
		pp.id_e=i;
		subthrs[i]->n_subthr = nn;
		subthrs[i]->thr_padre=this;
		subthrs[i]->pirate=FALSE;
		subthrs[i]->inicia(OLV_MILIS_COLA,&cola_proc,-1,nomb);		
		subthrs[i]->encola(tar,&pp,FALSE);
	}

	//fuerza fin para que avance olivia
	for(int i=nn;i<n_subthr;i++)
	{	
		if(!subthrs[i])
			subthrs[i]=new Colv_limp_thr(olv_limp);
		subthrs[i]->prog_subthr = 0;
	}
	for(int i=0;i<n_subthr-nn;i++)
		encola(tar+1,NULL,FALSE); //encola la tarea de fin
}
//*************************************************************************************
/**
 * Devuelve la planificación del sector iésimo, que realiza el thread 'ithr'
 */
void Colv_reco_thr::planifica_sub_1(int ithr, Matrix2d<float> &cost_amb)
{
	Info_sec	*s;
	Info_amb_sec *aa;
	int i,iaux,is_ini,is_fin,is_desp,is,jmin,nvac;
	 
	BOOL log_debug=FALSE;
	BOOL sal,sig;
	Djkt_nodo *costes_nodos;
	int nsecu,KK,ic_aux,ss;
	int nsecu2;
	Secu_amb *secu_ambi=NULL;
	Param_olv_limp_thr  pp;
	Djkt_nodo *buf_aux=NULL;
	int msecu1, msecu2;

	int *secu, *secu2;
	costes_nodos=NULL;
	msecu2 = msecu1 = olv_limp->conjs.n;
	secu=(int *)malloc(olv_limp->conjs.n*sizeof(int));
	if(!secu)
	{
		sal=TRUE;
		goto fin;
	}
	memset(secu,0,olv_limp->conjs.n*sizeof(int));
	secu2=(int *)malloc(olv_limp->conjs.n*sizeof(int));
	if(!secu2)
	{
		sal=TRUE;
		goto fin;
	}
	memset(secu2,0,olv_limp->conjs.n*sizeof(int));
	nsecu2=0;
	//////////////////////////
	pp.id_e=OLV_TAREA_PLANIF;//manda de parámetro la tarea de la que es el progreso
	ic_aux=0;
	KK=olv_limp->tipo_ambit;
	sal=sig=FALSE;
	jmin=0;
	prog_subthr=0;	
	//cost_amb=olv_limp->cost_amb;
	aa=olv_limp->amb_sec;
	iaux=-1;
	
	////////////////////////////////////////////////////
	//mira a ver cuántos sectores le tocan a este thread
	if(olv_limp->nsec<n_subthr)
	{
		//hay menos sectores que threads, o le toca uno o ninguno
		if(ithr<olv_limp->nsec)
		{
			//solo hace un sector, el ithr-esimo
			is_ini=ithr;
			is_fin=ithr+1;
		}
		else
		{
			//no hace ningún sector, no hace falta
			is_ini=0;
			is_fin=0;
		}
	}
	else
	{
		//hay más sectores que threads, le tocan más de uno
		is_desp=(int)ceil(1.0*(olv_limp->nsec)/n_subthr);
		is_ini=ithr*is_desp;
		is_fin=min((ithr+1)*is_desp,olv_limp->nsec);
	}	
	//////////////////////////
	if(is_fin==is_ini)
		olvlog(LOG_TODO,"olv_limp_t","Subthr %02d, No Planifica ningún sector", ithr);
	else if(is_fin-is_ini-1==0)
		olvlog(LOG_TODO,"olv_limp_t","Subthr %02d, Planifica sector %02d", ithr,is_ini);
	else
		olvlog(LOG_TODO,"olv_limp_t","Subthr %02d, Planifica sectores %02d a %02d", ithr,is_ini, is_fin-1);
	
	buf_aux=olv_limp->arch_dj.dame_buf_nodos();
	if(!buf_aux)
	{
		olvlog(LOG_TODO,"olv_limp_t","Error en planifica_sub 1 th: %ld  sin memo para buffer", ithr);
		sal=TRUE;
	}
	//////////////////////////
	//bucle en todos los sectores que le tocan al thread
	for(is=is_ini;is<is_fin && !pirate && !sal;is++)
	{	
		s = &olv_limp->sec[is];	
		if(s->namb<=0)
			continue;
		s->cost_despl_aux=0;	
		sig=FALSE;

		//busca el ámbito inicial de la planificiación
		secu_ambi=planifica_sect(s,olv_limp->ang_conj,OLV_LIMP_FACT_PERM);		
		if(!secu_ambi)
		{
			olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Imposible planificar sector %02d",ithr,is);
			sal=TRUE;
			continue;
		}
		if(esta_repe(secu_ambi, s->namb))			
		{
			olvlog(LOG_TODO,"olv_limp_t","Esta repe despues de planifica sec");
			sal=TRUE;
			continue;
		}
		nvac=0;
		s->cost_despl_aux=(float)dame_coste_pon_viajes(secu_ambi,0,s->namb-1,s,&nvac);
		
		if(s->cost_despl_aux==0)
		{
			olvlog(LOG_TODO,"olv_limp_t","Error al calcular viajes");
			sal=TRUE;
			continue;
		}
		olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Sector %02d, va a vaciar %ld veces",ithr,is,nvac);
		
		///////////////////////////////////////////
		//Añade la ruta de la instalación al primer punto
		double cc = 0, cc1 = 0;
		olv_limp->arch_dj.get_b(s->iamb[secu_ambi[0].iamb],secu_ambi[0].entrada, buf_aux);
		cc+=Colv_geom::ruta_dj_inv_ok(
			olv_reco->nod_instal,//id conjuncion inicial
			&secu2[0], //puntero a secuencia
			buf_aux, //nodos djktra conj final 
			olv_limp->conjs.n,
			&nsecu2);
		cc += olv_limp->t_sal;		
		if(!genera_planif_vaci(is,0, nsecu2, secu2,OLV_IDA_INST))
			sal=TRUE;
		///////////////////////////////////////////


		secu[0]=olv_limp->iaso[olv_limp->carto.get(s->iamb[secu_ambi[0].iamb]).entity()->ref].inod[secu_ambi[0].entrada];
		aa[s->iamb[secu_ambi[0].iamb]].iseq=0;
		//olv_limp->t_conv
		ss=1;
		int iam_ped;
		int iam_ent;
		for (i=1; i<s->namb; i++)
		{	
			///////////////////////////////////////////
			//Comprueba si hay que ir a vaciar
			if(olv_reco->ptos_vaci[s->iamb[secu_ambi[i-1].iamb]]==(short)OLV_IDA_PLANT)
			{
				//de i-1 a planta	
				cc+=Colv_geom::ruta_dj_inv_ok(
						olv_limp->iaso[olv_limp->carto.get(s->iamb[secu_ambi[i-1].iamb]).entity()->ref].inod[(secu_ambi[i-1].entrada+1)%2],
						&secu2[0], //puntero a secuencia
						olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0], //nodos djktra conj final 
						olv_limp->conjs.n,
						&nsecu2);
				cc += olv_reco->t_descarg;
				if(!genera_planif_vaci(is,0, nsecu2, secu2,OLV_IDA_PLANT))
				{
					sal=TRUE;
					break;
				}
				//de planta a i	
				olv_limp->arch_dj.get_b(s->iamb[secu_ambi[i].iamb],secu_ambi[i].entrada, buf_aux);
				iam_ped=s->iamb[secu_ambi[i].iamb];
				iam_ent=secu_ambi[i].entrada;
				cc+=Colv_geom::ruta_dj_inv_ok(
					olv_reco->nod_plant,
					&secu2[0], //puntero a secuencia
					buf_aux, //nodos djktra conj final 
					olv_limp->conjs.n,
					&nsecu2);
				
				if(!genera_planif_vaci(is,0, nsecu2, secu2,OLV_VUELTA_PLANT))
				{
					sal=TRUE;
					break;
				}
				
			}
			else
				iam_ped=iam_ent=-1;
			if(i==s->namb)
				continue;
			///////////////////////////////////////////
			
			if(iam_ped!=s->iamb[secu_ambi[i].iamb] || iam_ent!=secu_ambi[i].entrada)
				olv_limp->arch_dj.get_b(s->iamb[secu_ambi[i].iamb],secu_ambi[i].entrada, buf_aux);
			Colv_geom::ruta_dj_inv_ok(
				olv_limp->iaso[olv_limp->carto.get(s->iamb[secu_ambi[i-1].iamb]).entity()->ref].inod[(secu_ambi[i-1].entrada+1)%2],//id conjuncion inicial
				&secu[ss], //puntero a secuencia
				buf_aux, //nodos djktra conj final 
				olv_limp->conjs.n,
				&nsecu);			
			ss+=nsecu;

			//almacena el coste acumulado
			aa[s->iamb[secu_ambi[i].iamb]].iseq=i;
			
			//////////////////
			if((i%50)==0 || (i==s->namb-1))
			{
				//avisa de progreso	
				olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Planificando sector %02d, amb %ld de %ld", ithr,is,
					(i+1),(s->namb));
				prog_subthr=(1.0*(i+1)/(s->namb))*((is+1)/(is_fin-is_ini)); //porque son varios sectores
				thr_padre->encola(OLV_LIMP_EV_SUBTHR_PROG,&pp,FALSE);				
			}
			/////////////////

		}
		if(olv_limp->tipo_ambit==OLV_AMB_LIN)//añade el coste del último ámbito si es lineal
		{
			secu[ss++]=olv_limp->iaso[olv_limp->carto.get(s->iamb[secu_ambi[s->namb-1].iamb]).entity()->ref].inod[(secu_ambi[s->namb-1].entrada+1)%2];
		}

		///////////////////////////////////////////
		//Añade la ruta del último punto a descargar
		cc+=Colv_geom::ruta_dj_inv_ok(
				olv_limp->iaso[olv_limp->carto.get(s->iamb[secu_ambi[s->namb-1].iamb]).entity()->ref].inod[(secu_ambi[s->namb-1].entrada+1)%2],
				&secu2[0], //puntero a secuencia
				olv_reco->ord_sec_plan[OLV_PLANT].ctnod[0], //nodos djktra conj final 
				olv_limp->conjs.n,
				&nsecu2);
		cc += olv_reco->t_descarg;
		if(!genera_planif_vaci(is,0, nsecu2, secu2,OLV_IDA_PLANT))
		{
			sal=TRUE;
			break;
		}
		if(olv_reco->nod_instal!=olv_reco->nod_plant)
		{		
			//de descargar a la instalación
			cc+=Colv_geom::ruta_dj_inv_ok(
					olv_reco->nod_plant,
					&secu2[0], //puntero a secuencia
					olv_reco->ord_sec_plan[OLV_INSTAL].ctnod[0], //nodos djktra conj final 
					olv_limp->conjs.n,
					&nsecu2);			
			if(!genera_planif_vaci(is,0, nsecu2, secu2,OLV_VUELTA_INST))
			{
				sal=TRUE;
				break;
			}
		}
		cc += olv_limp->t_sal; //suma el tiempo tanto si va a instala como si no
		///////////////////////////////////////////
		
		if(esta_repe(secu_ambi, s->namb, FALSE))
			olvlog(LOG_TODO,"olv_limp_t","Esta repe despues de planificar");
		
		olvlog(LOG_TODO,"olv_limp_t","Subthr %ld, Planificando sector %02d, coste total %lf",ithr,is,s->cost_despl_aux);
		
		if(!pirate && !sal)
		{		
			//////////////////////////////////
			//genera la ruta y los puntos de control
			if(!genera_planif(is,s->cost_despl_aux/*-cc*/, ss, secu,OLV_PLAN_RECO))
				sal=TRUE;
			//olv_limp->sec[is].cost_ac = s->cost_despl_aux;
			olv_limp->sec[is].cost_ac=(float)(olv_limp->plan[is].elem[olv_limp->plan[is].nelem-1].coste+cc);			
		}
		//////////////////////////////////
		if(	secu_ambi)
		{			
			free(secu_ambi);
			secu_ambi=NULL;
		}
	}
	free(secu);
	free(secu2);
fin:
	//Ha terminado, encola al padre
	olv_limp->arch_dj.libera_buf(buf_aux);
	if(sal)
	{
		prog_subthr=-1;//para avisar al padre de que ha habido un error
	}
	thr_padre->encola(OLV_LIMP_EV_PLANIFICA_FIN,NULL,FALSE);
}
//*************************************************************************************
/**
 * Pone en la ruta en qué contenedores corresponden los puntos de control
 */
void Colv_reco_thr::pon_ptos_ctrl(Info_planif *pp, int npt_ctrl, double cost_ctrl)
{
	double cost_acum, cost_viajes;
	int i, ipc, iviaje;
	///////////////////////////////////////////////////////////////
	//Inicializa el array de puntos de control
	pp->pts_ctrl=(Info_planif_ctrl*)malloc((olv_limp->npts_ctrl-2+1)*sizeof(Info_planif_ctrl));
	if(!pp->pts_ctrl)
		return;
	memset(pp->pts_ctrl,0,(olv_limp->npts_ctrl-2+1)*sizeof(Info_planif_ctrl));
	ipc=0;

	/////////////////////////////
	cost_acum=cost_viajes=0;
	iviaje=1;//la primera ida será en el viaje 1 (ida desde inst,ida a planta)
	for(i=0;i<pp->nelem;i++)
	{	
		/////////////////////////////
		cost_acum=pp->elem[i].coste+cost_viajes;		
		
		//mira si toca punto de control
		if((cost_acum-ipc*(cost_ctrl/*+olv_limp->t_desc*/))>(cost_ctrl+1))
		{
			if(ipc<npt_ctrl)
			{			
				//añade como punto de control
				pp->pts_ctrl[ipc].ipt=i-1;
				ipc++;
			}
			else
				ipc=ipc;
		}

		if(pp->elem[i].tp==OLV_PLAN_TIP_AMB)
		{
			if(olv_reco->ptos_vaci[olv_limp->iaso[pp->elem[i].refe].iamb]==(short)OLV_IDA_PLANT)
			{
				cost_viajes+=pp->planif_insta[iviaje].elem[pp->planif_insta[iviaje].nelem-1].coste;//ida
				iviaje++;
				cost_viajes+=olv_reco->t_descarg;
				cost_viajes+=pp->planif_insta[iviaje].elem[pp->planif_insta[iviaje].nelem-1].coste;//vuelta
				iviaje++;
			}
		}
	}

	for(i=0;i<npt_ctrl;i++)
	{
		if(pp->pts_ctrl[i].ipt<0)
			pp->pts_ctrl[i].ipt=pp->nelem-1;
	}
}
//*************************************************************************************
/**
 * Dada la secuencia de las conjunciones que sigue la ruta para ir a vaciar, genera el obg
 */
BOOL Colv_reco_thr::genera_planif_vaci(int is, int ini, int fin, int *secu, int tip_viaje)
{	
	int i,nvaciados;
	Info_planif *pp,*pp_insta;
	Info_sec *ss;

	ss=&olv_limp->sec[is];
	pp=&olv_limp->plan[is];
	pp_insta = pp->planif_insta;
	nvaciados=0;
	if(!pp_insta)
	{
		nvaciados=1;//siempre está el último, que va a vaciar
		for(i=0;i<ss->namb;i++)
		{
			if(olv_reco->ptos_vaci[ss->iamb[i]]==(short)OLV_IDA_PLANT)
				nvaciados++;//por cada vez que va a descargar
		}		
	}
	if(!genera_planif_instala(is, nvaciados, ini, fin, secu, tip_viaje))
		return FALSE;
	
	return TRUE;
}
//*************************************************************************************
/**
 * Añade una línea al listado csv con el viaje a vaciar y vuelta
 */
BOOL Colv_reco_thr::genera_list_fila_vaci(Colv_csv *cc, char *fila0, int ielem, int isec, int secu, double tt, double *t0,BOOL is_fin)
{
	int h,m,seg,i,iplan;
	Info_planif *pp;
	double cost_despl,ltot,kgac;
	int iamb, iamb2;

	iamb=olv_limp->iaso[ielem].iamb;
	if(iamb<0)
		iamb=olv_limp->iaso[ielem].refe2;

	if(iamb<0 || !olv_reco->ptos_vaci[iamb])
		return TRUE;//no es punto en el que se va a vaciar

	if(!is_fin && (olv_reco->ptos_vaci[iamb]!=(short)OLV_IDA_PLANT))
		return TRUE;//no es punto en el que se va a vaciar

	//busca la ruta de este punto en el que se va a vaciar
	if(!olv_limp->plan[isec].planif_insta || !olv_limp->plan[isec].ninsta)
		return FALSE;

	for(i=0;i<olv_limp->plan[isec].ninsta;i++)
	{
		if(olv_limp->plan[isec].planif_insta[i].elem[0].refe==ielem)
			break;
	}
	if(i>=olv_limp->plan[isec].ninsta)
		return FALSE;

	iplan=i;

	//ha encontrado la planificación, coge el tiempo de desplazamiento
	pp = &olv_limp->plan[isec].planif_insta[i];
	if(!pp->nelem)
		return FALSE;
	cost_despl = pp->elem[pp->nelem-1].coste;
	ltot=pp->m[OLV_DESP];

	//////////////////
	//pone el tiempo acumulado anterior, en el que se inicia este vaciado, aprovecha y lo guarda aquí	
	pp->t[OLV_TTO]=tt;
	//////////////////

	//////////////////
	//Calcula los kg acumulados
	kgac=0;
	for(i=0;i<olv_limp->plan[isec].nelem;i++)
	{
		if(olv_limp->plan[isec].elem[i].tp!=OLV_PLAN_TIP_AMB)
			continue;
		iamb2=olv_limp->iaso[olv_limp->plan[isec].elem[i].refe].refe2;
		kgac+=olv_limp->iaso[iamb2].inf_r.kg;
		if(olv_limp->plan[isec].elem[i].refe==ielem)
			break;
	}
	if(i>=olv_limp->plan[isec].nelem)
		return FALSE;

	//le resta los kg acumulados en el viaje anterior
	i=iplan;
	while((i-2)>0)//dos antes está la anterior planif a vaciar, si la hubiera
	{
		kgac-=olv_limp->plan[isec].planif_insta[i-2].m[OLV_TTO];//aprovecha y lo guarda aquí
		i-=2;
	}
	pp->m[OLV_TTO]=kgac;
	//////////////////

	dame_h_m_s(tt, &h, &m, &seg);
	sprintf_s(fila0,256,"%02d;%04d;%s;%.1f;%s;%.1f;%02d:%02d:%02d;\r\n",isec+1,secu,"",kgac,"Ida a descargar",ltot,h,m,seg);
	if(!cc->escribe(fila0))
	{
		return FALSE;
	}
	*t0 += cost_despl + olv_reco->t_descarg;
	tt += cost_despl + olv_reco->t_descarg;

	if (is_fin)
		*t0 = tt;

	if(olv_reco->ptos_vaci[iamb]!=(short)OLV_IDA_PLANT)
		return TRUE;

	//escribe la vuelta de la descarga
	if((iplan+1)>=olv_limp->plan[isec].ninsta)
		return TRUE;
	pp = &olv_limp->plan[isec].planif_insta[iplan+1];
	if(!pp->nelem)
		return FALSE;
	cost_despl = pp->elem[pp->nelem-1].coste;
	ltot=pp->m[OLV_DESP];

	//////////////////
	//pone el tiempo acumulado
	pp->t[OLV_TTO]=tt;
	//////////////////

	*t0+=cost_despl;
	tt+=cost_despl;
	dame_h_m_s(tt, &h, &m, &seg);
	sprintf_s(fila0,256,"%02d;%04d;%s;%s;%s;%.1f;%02d:%02d:%02d;\r\n",isec+1,secu,"","","Vuelta de descargar",ltot,h,m,seg);
	if(!cc->escribe(fila0))
	{
		return FALSE;
	}

	//reinicia, para que no vuelva a entrar
	olv_reco->ptos_vaci[iamb]=0;


	return TRUE;
}
//*************************************************************************************
/**
 * Quita al tiempo total el del último desplazamiento y la última descarga, solo para reco
 */
void Colv_reco_thr::quita_t_ult_desc(int s, double *t)
{
	int tt=(int)*t;
	if(olv_limp->plan[s].ninsta>2 && olv_limp->plan[s].planif_insta[olv_limp->plan[s].ninsta-2].nelem>0) //quita el tiempo de desplazamiento de la instalación a la planta
		tt-=(int)olv_limp->plan[s].planif_insta[olv_limp->plan[s].ninsta-2].elem[olv_limp->plan[s].planif_insta[olv_limp->plan[s].ninsta-2].nelem-1].coste;
	tt-=olv_reco->t_descarg;
	*t=tt;
}
//*************************************************************************************
/**
 * Añade una columna de observación al listado si es contenedores
 */
void Colv_reco_thr::dame_observ_cont(int iamb, char *observ)
{
	int i=olv_limp->iaso[iamb].iamb;
	if(i<0)
		i=olv_limp->iaso[iamb].refe2;
	sprintf_s(observ,32,"%ld",olv_limp->iaso[i].inf_r.uds);
}
//*************************************************************************************
/**
 * Añade las columnas de información a la ruta, tiempos, longitudes, y demás
 */
BOOL Colv_reco_thr::guarda_cols_ruta(char *path_shp)
{
	char *info;
	char path_dbf[MAX_PATH];
	double tt;
	int h,m,s,j;
	int nsec, i, isec_novac,p;
	ManagerDbfGdataTable dbfmgr;
	GdataTable db;

	//cuenta el número de sectores no vacíos
	nsec=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb!=0)
			nsec++;
	}

	/////////////////////////////////////

	if(!Colv_limp_thr::guarda_cols_ruta(path_shp))
		return FALSE;	

	strcpy_s(path_dbf,MAX_PATH,path_shp);
	//cambiaext(path_dbf,".shp",".dbf");
	strcpy((Cdir_manager::extension_archivo(path_dbf)),"dbf");

	info = (char *)malloc(nsec* OLV_SHP_SZ_CAMP_SZ);
	if(!info)
	{
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);
	AddColsDbf dataDbf(info);
	if (!dbfmgr.LeeDbf(path_dbf, &db))
	{
		free(info);
		return FALSE;
	}

	//elimina col M_DESP
	if (!dbfmgr.DelCol(NULL, "M_DESP"))
	{
		free(info);
		return FALSE;
	}

	//renombra T_DESP por T_RUTA
	if (!db.rename(db.getInd("T_DESP"),"T_RUTA"))
	{
		free(info);
		return FALSE;
	}

	//sustituye col m total
	isec_novac = 0;
	for (i = 0; i < olv_limp->nsec; i++)
	{
		if (olv_limp->sec[i].namb == 0)
			continue;

		tt = 0;
		for(p=0;p<olv_limp->plan[i].ninsta;p++)
		{
			tt += olv_limp->plan[i].planif_insta[p].m[OLV_DESP];
		}

		tt += olv_limp->plan[i].m[OLV_DESP] + olv_limp->plan[i].m[OLV_TTO];
		//para guardar en número
		((double*)info)[isec_novac] = tt;

		isec_novac++;
	}
	if (!dbfmgr.AddCol(NULL, "M_TOTAL", GdataTable::Tdouble, &dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info, 0, nsec * OLV_SHP_SZ_CAMP_SZ);	

	//sustituye la columna de uds de tratamiento porque hay contenedores que son varias unidades
	isec_novac=0;
	for(i=0;i<nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		tt=0;
		for(j=0;j<olv_limp->sec[i].namb;j++)
			tt+=olv_limp->iaso[olv_limp->sec[i].iamb[j]].inf_r.uds;
		//para guardar en número
		((int*)info)[isec_novac] = tt;
		isec_novac++;
	}
	if(!dbfmgr.AddCol(NULL,"UDS_TRAT",GdataTable::Tint,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);

	//Kg recogidos
	isec_novac=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		tt=olv_limp->sec[i].dis_med;
		//para guardar en número
		((double*)info)[isec_novac] = tt;
		isec_novac++;
	}
	if(!dbfmgr.AddCol(NULL,"KG_TOT_REC",GdataTable::Tdouble,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);

	//número de descargas
	isec_novac=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		tt=(olv_limp->plan[i].ninsta-1)/2;
		//para guardar en número
		((int*)info)[isec_novac] = tt;
		isec_novac++;
	}
	if(!dbfmgr.AddCol(NULL,"N_DESCARG",GdataTable::Tint,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);

	//rellena la info de duración de los desplazamientos a descargar
	isec_novac=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		tt=0;
		if(olv_limp->sec[i].namb==0)
			continue;
		for(p=1;p<olv_limp->plan[i].ninsta;p++)
		{
			if(olv_limp->plan[i].planif_insta[p].nelem==0)
				continue;
			if (olv_limp->plan[i].planif_insta[p].ninsta == OLV_IDA_PLANT || olv_limp->plan[i].planif_insta[p].ninsta == OLV_VUELTA_PLANT)
				tt+=olv_limp->plan[i].planif_insta[p].elem[olv_limp->plan[i].planif_insta[p].nelem-1].coste;
		}		
		dame_h_m_s(tt, &h, &m, &s);
		sprintf_s(&info[isec_novac*OLV_SHP_SZ_CAMP_CHAR],OLV_SHP_SZ_CAMP_CHAR,"%02d:%02d:%02d h",h,m,s);
		isec_novac++;
	}
	if(!dbfmgr.AddCol(NULL,"T_DESCARG",GdataTable::Tstring,&dataDbf,OLV_SHP_SZ_CAMP_CHAR))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,nsec* OLV_SHP_SZ_CAMP_SZ);

	//añade col m descarg
	isec_novac = 0;
	for (i = 0; i < olv_limp->nsec; i++)
	{
		if (olv_limp->sec[i].namb == 0)
			continue;
		tt = 0;
		for (p = 0; p < olv_limp->plan[i].ninsta; p++)
		{
			if (olv_limp->plan[i].planif_insta[p].ninsta == OLV_IDA_PLANT || olv_limp->plan[i].planif_insta[p].ninsta == OLV_VUELTA_PLANT)
				tt += olv_limp->plan[i].planif_insta[p].m[OLV_DESP];
		}
		//para guardar en número
		((double*)info)[isec_novac] = tt;

		isec_novac++;
	}
	if (!dbfmgr.AddCol(NULL, "M_DESCARG", GdataTable::Tdouble, &dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info, 0, nsec * OLV_SHP_SZ_CAMP_SZ);

	free(info);

	if (!dbfmgr.grabaDbf(path_dbf, &db))
	{
		return FALSE;
	}
	return TRUE;
}
//*************************************************************************************
/**
 * Añade las columnas de información a la ruta, tiempos, longitudes, y demás
 */
BOOL Colv_reco_thr::guarda_cols_insta(char *path_shp)
{
	char *info;
	char path_dbf[MAX_PATH];
	double tt;
	//int h;
	int insta, ninsta_parc,ninsta,ninsta_novac;
	ManagerDbfGdataTable dbfmgr;
	GdataTable db;

	/////////////////////////////////////

	if(!Colv_limp_thr::guarda_cols_insta(path_shp))
		return FALSE;	

	//cuenta el número de instalaciones
	ninsta=0;
	for(int i=0;i<olv_limp->nsec;i++)
	{
		for(insta=0;insta<olv_limp->plan[i].ninsta;insta++)
		{
			if(olv_limp->plan[i].planif_insta[insta].nelem!=0)
				ninsta++;
		}
	}

	//añade una columna a la ruta de tiempo de ruta
	strcpy_s(path_dbf,MAX_PATH,path_shp);
	//cambiaext(path_dbf,".shp",".dbf");
	strcpy((Cdir_manager::extension_archivo(path_dbf)),"dbf");

	info = (char *)malloc(ninsta* OLV_SHP_SZ_CAMP_SZ);
	if(!info)
	{
		return FALSE;
	}
	memset(info,0,ninsta* OLV_SHP_SZ_CAMP_SZ);
	AddColsDbf dataDbf(info);
	if (!dbfmgr.LeeDbf(path_dbf, &db))
	{
		free(info);
		return FALSE;
	}

	//kg descargados
	ninsta_parc=0;
	for(int i=0;i<olv_limp->nsec;i++)
	{
		ninsta_novac=0;
		for(insta=0;insta<olv_limp->plan[i].ninsta;insta++)
		{
			if(olv_limp->plan[i].planif_insta[insta].nelem==0)
				continue;

			if(olv_limp->plan[i].planif_insta[insta].ninsta==OLV_IDA_PLANT)
				tt=olv_limp->plan[i].planif_insta[insta].m[OLV_TTO];
			else 
				tt=0;

			((double*)info)[insta + ninsta_parc] = tt;
			ninsta_novac++;
		}		
		ninsta_parc+=ninsta_novac;
	}
	if(!dbfmgr.AddCol(NULL,"KG_DESCARG",GdataTable::Tdouble,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ninsta* OLV_SHP_SZ_CAMP_SZ);

	//num de trayecto a descargar
	ninsta_parc=0;
	tt=0;
	int tt2=0;
	for(int i=0;i<olv_limp->nsec;i++)
	{
		ninsta_novac=0;
		tt=1;
		for(insta=0;insta<olv_limp->plan[i].ninsta;insta++)
		{
			if(olv_limp->plan[i].planif_insta[insta].nelem==0)
				continue;

			if(olv_limp->plan[i].planif_insta[insta].ninsta==OLV_VUELTA_PLANT)
				tt++;
			
			((int*)info)[insta + ninsta_parc] = tt;
			ninsta_novac++;
		}		
		ninsta_parc+=ninsta_novac;
	}
	if(!dbfmgr.AddCol(NULL,"VIAJE",GdataTable::Tint,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ninsta* OLV_SHP_SZ_CAMP_SZ);

	free(info);

	if (!dbfmgr.grabaDbf(path_dbf, &db))
	{
		return FALSE;
	}
	return TRUE;
}
//*************************************************************************************
/**
 * Comprueba si en este elemento se va a descargar y en ese caso no se cuenta el desplazamiento hasta el siguiente
 */
BOOL Colv_reco_thr::comprueba_descarg(int iamb)
{
	return (olv_reco->ptos_vaci[iamb]==(short)OLV_IDA_PLANT);
}
//*************************************************************************************
/**
 * Añade las columnas de información a la ruta, tiempos, longitudes, y demás
 */
BOOL Colv_reco_thr::guarda_cols_ruta_tram(char *path_shp)
{
	char *info;
	char path_dbf[MAX_PATH];
	double tt;
	int i, it,ntram,nt,nt_parc;
	Info_planif *pinsta;
	ManagerDbfGdataTable dbfmgr;
	GdataTable db;

	if(!Colv_limp_thr::guarda_cols_ruta_tram(path_shp))
		return FALSE;

	//añade

	//cuenta el número de sectores no vacíos
	ntram=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		ntram+=(int)olv_limp->tramos[i].size();
	}

	//añade una columna a la ruta de tiempo de ruta
	strcpy_s(path_dbf,MAX_PATH,path_shp);
	//cambiaext(path_dbf,".shp",".dbf");
	strcpy((Cdir_manager::extension_archivo(path_dbf)),"dbf");

	info = (char *)malloc(ntram* OLV_SHP_SZ_CAMP_SZ);
	if(!info)
	{
		return FALSE;
	}
	memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);
	AddColsDbf dataDbf(info);
	if (!dbfmgr.LeeDbf(path_dbf, &db))
	{
		free(info);
		return FALSE;
	}

	//M_RUTA
	nt_parc=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		nt=(int)olv_limp->tramos[i].size();

		for(it=0;it<nt;it++)
		{	
			pinsta=olv_limp->plan[i].planif_insta;
			tt=olv_limp->tramos[i][it].long_tr;
			//como es solo ruta le quita las instalaciones
			tt -= (pinsta[olv_limp->tramos[i][it].iins[0]].m[OLV_DESP] + pinsta[olv_limp->tramos[i][it].iins[1]].m[OLV_DESP]);
			if (olv_limp->tramos[i][it].iins[1] > (olv_limp->tramos[i][it].iins[0] + 1)) //si la planta y la instala no son las mismas
				tt -= pinsta[olv_limp->tramos[i][it].iins[1] - 1].m[OLV_DESP];

			((double*)info)[nt_parc + it] = tt;
		}
		nt_parc+=nt;
	}
	if(!dbfmgr.AddCol(NULL,"M_RUTA",GdataTable::Tdouble,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);

	//N_AMB
	nt_parc=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		nt=(int)olv_limp->tramos[i].size();
		for(it=0;it<nt;it++)
		{	
			tt=olv_limp->tramos[i][it].namb;
			((int*)info)[nt_parc + it] = tt;
		}
		nt_parc+=nt;
	}
	if(!dbfmgr.AddCol(NULL,"N_AMB",GdataTable::Tint,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);

	//UDS_TTO
	nt_parc=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		nt=(int)olv_limp->tramos[i].size();
		for(it=0;it<nt;it++)
		{	
			tt=olv_limp->tramos[i][it].ncont;
			((int*)info)[nt_parc + it] = tt;
		}
		nt_parc+=nt;
	}
	if(!dbfmgr.AddCol(NULL,"UDS_TRAT",GdataTable::Tint,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);

	//KG_RECO
	nt_parc=0;
	for(i=0;i<olv_limp->nsec;i++)
	{
		if(olv_limp->sec[i].namb==0)
			continue;
		nt=(int)olv_limp->tramos[i].size();
		for(it=0;it<nt;it++)
		{	
			tt=olv_limp->plan[i].planif_insta[2*it+1].m[OLV_TTO];
			((double*)info)[nt_parc + it] = tt;
		}
		nt_parc+=nt;
	}
	if(!dbfmgr.AddCol(NULL,"KG_TOT_REC",GdataTable::Tdouble,&dataDbf))
	{
		free(info);
		return FALSE;
	}
	memset(info,0,ntram* OLV_SHP_SZ_CAMP_SZ);
	free(info);

	if (!dbfmgr.grabaDbf(path_dbf, &db))
	{
		return FALSE;
	}
	return TRUE;
}
//*************************************************************************************
/**
 * Rellena la info de los tramos
 */
void Colv_reco_thr::rellena_tramos()
{
	Info_planif *pp;
	Info_tramos *tramo;
	int ie,it,nt;

	Colv_limp_thr::rellena_tramos();

	for(int is=0;is<olv_limp->nsec;is++)
	{
		pp=&olv_limp->plan[is];
		nt=(int)olv_limp->tramos[is].size();
		for(it=0;it<nt;it++)
		{		
			tramo = &olv_limp->tramos[is][it];
			tramo->ncont=0;
			for(ie=tramo->ie[0]; ie<=tramo->ie[1];ie++)
			{	
				if (pp->elem[ie].tp != OLV_PLAN_TIP_AMB)
					continue;
				tramo->ncont+=olv_limp->iaso[olv_limp->iaso[pp->elem[ie].refe].refe2].inf_r.uds;
			}				
		}
	}
}
//*************************************************************************************
/**
 * Como los viajes a instalaciones están ordenados, y los tramos también
 * le corresponde a cada tramo it el viaje it y el it+1, excepto al último, que le pueden 
 * corresponder 3 viajes si la instalación y la descarga no son en el mismo sitio
 * Además, actualiza el tiempo de los tramos
 */
int Colv_reco_thr::rellena_insta_tramos()
{
	int it, nt, nins,ii;
	Info_planif *pinsta;
	Info_tramos *tramo;

	Colv_limp_thr::rellena_insta_tramos();

	ii=0; //para saber si hace algún tramo o no
	for(int is=0;is<olv_limp->nsec;is++)
	{
		nt=(int)olv_limp->tramos[is].size();
		nins = olv_limp->plan[is].ninsta;
		if(!nins)
			continue;
		if(olv_limp->plan[is].planif_insta[nins-1].nelem==0)
			nins--; //es porque la descarga y planta son la misma
		pinsta = olv_limp->plan[is].planif_insta;
		for(it=0;it<nt;it++)
		{
			tramo = &olv_limp->tramos[is][it];

			if (it == 0)//primer tramo, le suma el tiempo de llegar
				tramo->t_ini -= olv_limp->t_sal;
			tramo->t_fin += olv_reco->t_descarg;
			if(it == (nt-1))
				tramo->t_fin += olv_limp->t_sal;

			tramo->t_total_tr = (float)(tramo->t_fin - tramo->t_ini);
		}
		ii++;		
	}
	return ii;
}
//*************************************************************************************
#endif