#include "StdAfx.h"
#include "CartoBase.h"
#include "CartoBaseShpManager.h"
#include "CartoBaseDBFManager.h"
#include "dir_manager.h"
#include "Fdbf.h"
//*****************************************************************************************
CartoBase::CartoBase(void)
{
	ref = 0;
	typeIA = IntIa;
	strcpy(iaName, "Ia");
	iaEx =this;
}
//*****************************************************************************************

CartoBase::~CartoBase(void)
{
}
//*****************************************************************************************
int CartoBase::getNumberEntities()
{
	return _entities.n;
}
//*****************************************************************************************
double* CartoBase::getPto(int i)
{
	return _points[i].pts;
}
//*****************************************************************************************
int CartoBase::getNumberPtos()
{
	return _points.n;
}
//*****************************************************************************************
CartoBaseInfoEntity CartoBase::getEntity(int i)
{
	return get(i);
}
//*****************************************************************************************
CartoBaseInfoEntity CartoBase::get(int i)
{
	return CartoBaseInfoBuilder::get(i, this);
}
//*****************************************************************************************
CartoBaseInfoEntity CartoBase::getRef(int r)
{
	return CartoBaseInfoBuilder::get(refIndex[r], this);
}
//*****************************************************************************************
int CartoBase::getEntityRef( int ientity )
{
	return _entities[ientity].ref;
}
//*****************************************************************************************
bool CartoBase::add(CartoEntity& element)
{
	bool res = 0<=element.CopyInTo(this);
	if(res && iaEx && typeIA != NIa)
		iaEx->IaAdd(_entities[_entities.n-1].ref);
	return res;
}
//*****************************************************************************************
bool CartoBase::add(CartoBase& cad)
{
	return false;
}
//*****************************************************************************************
bool CartoBase::grabar(char *path)
{
	Cb_file f;
	if(!f.abre(path,2,1))
		return false;
	return grabar(&f);
}
//*****************************************************************************************
bool CartoBase::leer(char *path)
{
	Cb_file f;
	if(!f.abre(path,1,0,true))
		return false;
	return leer(&f);
}
//*****************************************************************************************
bool CartoBase::grabar(Cb_file *f)
{
	char st[16];
	int version;
	memset(st,0,16);
	strcpy(st,TYPE_FILE);
	if(!f->escribe(st, 16))
		return false;
	version = VERSION_CART_BASE;
	if(!f->escribe(&version, sizeof(version)))
		return false;
	
	if(!f->escribe(&_defaultColor, sizeof(_defaultColor)))
		return false;
	if(!f->escribe(&_defaultpaintedProps, sizeof(_defaultpaintedProps)))
		return false;
	if(!_entities.graba(f))
		return false;
	if(!_points.graba(f))
		return false;
	if(!_lines.graba(f))
		return false;
	if(!_paintedProps.graba(f))
		return false;
	if(!_colors.graba(f))
		return false;
	return true;
}
//*****************************************************************************************
bool CartoBase::leer (Cb_file* f)
{
	char st[16];
	int version;
	memset(st,0,16);
	if(!f->lee(st, 16) || strcmp(st, TYPE_FILE))
		return false;
	if(!f->lee(&version, sizeof(version)) || version!= VERSION_CART_BASE)
		return false;
	if(!f->lee(&_defaultColor, sizeof(_defaultColor)))
		return false;

	if(!f->lee(&_defaultpaintedProps, sizeof(_defaultpaintedProps)))
		return false;
	_entities.n = 0;
	if(!_entities.leer(f))
		return false;
	_points.n = 0;
	if(!_points.leer(f))
		return false;
	_lines.n = 0;
	if(!_lines.leer(f))
		return false;
	_paintedProps.n = 0;
	if(!_paintedProps.leer(f))
		return false;
	_colors.n = 0;
	if(!_colors.leer(f))
		return false;
	iniIndexRef();
	return true;
}
//*****************************************************************************************
int CartoBase::add(CartoBaseEntity* src)
{
	if(_entities+(*src))
	{
		_entities[_entities.n-1].ref = ref;
		refIndex[ref++] = _entities.n-1;
		return _entities.n-1;
	}
	return -1;
}
//*****************************************************************************************
int CartoBase::add(CartoBasePoint* src)
{
	if(_points+(*src))
		return _points.n-1;
	return -1;
}
//*****************************************************************************************
int CartoBase::add(CartoBaseLine* src)
{
	if(_lines+(*src))
		return _lines.n-1;
	return -1;
}
//*****************************************************************************************
int CartoBase::add(CartoBasePaintedProps* src)
{
	if(_paintedProps+(*src))
		return _paintedProps.n-1;
	return -1;
}
//*****************************************************************************************
int CartoBase::add(CartoBaseColor* src)
{
	if(_colors+(*src))
		return _colors.n-1;
	return -1;
}
//*****************************************************************************************
int CartoBase::addDefaultPaintedProps()
{
	_defaultpaintedProps.color = _colors.n;
	_colors+_defaultColor;
	_paintedProps+_defaultpaintedProps;
	_defaultpaintedProps.color = -1;
	return _paintedProps.n-1;
}
//*****************************************************************************************
void CartoBase::del()
{
	_entities.n=0;
	_points.n=0;
	_lines.n=0;
	_paintedProps.n=0;
	_colors.n=0;
}
//*****************************************************************************************
EntitiesArray* CartoBase::filter(EntitiesArray* dst, FilterEntities* filter)
{
	CartoBaseInfoEntity e = get(0);
	while(e.isValid())
	{
		if(filter->IsSeletedEntity(&e))
		{
			if(!((*dst)+e))
				return 0;
		}
		e = e.next();
	}
	return dst;
}
//*****************************************************************************************
bool CartoBase::remove(int i)
{
	if(i<_entities.n)
	{
		_entities[i].flagsInt |= CARTOBASE_DELETED_ENTITY;
		if(iaEx)
			iaEx->IaRemove(_entities[i].ref);
		return true;
	}
	return false;
}
//*****************************************************************************************
bool CartoBase::removeRef(int r)
{
	return remove(refIndex[r]);
}
//*****************************************************************************************
bool CartoBase::clear()
{
	return false;//no funciona
	//verifica entidades
	int ind =0;
	std::map<int,int> indsl;
	int il,ip,ic, id;
	std::map<int,int> indsp;
	std::map<int,int> indsc;
	std::map<int,int> indsd;//indices de pintado
	il = ip=ic=id = 0;
	//borra entidades marcadas
	for(int i =0; i<_entities.n; i++)
	{
		if(_entities[i].flagsInt & CARTOBASE_DELETED_ENTITY)
			continue;
		if(i == ind)
		{
			ind++;
			continue;
		}
		_entities[ind++]=_entities[i];
	}

	
	//si borrados
	if(ind == _entities.n)
		goto ajus_mem;
	
	//verifica
	_entities.n = ind;
	for(int i =0; i<_entities.n; i++)
	{
		int aux = _entities[i].idPaintp;
		//revisa propiedades de pintado
		if(indsd.find(aux) == indsd.end())
		{
			indsd[aux] = id++;
			//revisa color
			if(indsc.find(_paintedProps[i].color) == indsc.end())
				indsc[_paintedProps[i].color] =ic++;
			_paintedProps[i].color = indsc[_paintedProps[i].color];
		}
		_entities[i].idPaintp = indsd[aux];
		//segun tipo de entidad
		aux =_entities[i].id;
		switch(_entities[i].type)
		{
		case(CartoBaseTypes::Point):
			{
				if(indsp.find(aux) == indsp.end())
					indsp[aux] = ip++;	
				_entities[i].id = indsp[aux];
				break;
			}
		case(CartoBaseTypes::Line):
			{
				if(indsl.find(aux) == indsl.end())
				{
					indsl[aux] = il++;
				}

				int nn = _lines[aux].n;
				aux= _lines[aux].ini;

				for(int ii =0; ii<nn; ii++)
				{
					if(indsp.find(aux+ii) == indsp.end())
						indsp[aux+ii] = ip++;		
				}
				_lines[_entities[i].id].ini = indsp[aux];

				_entities[i].id = indsl[_entities[i].id];
				break;
			}
		}
	}
	//recolocacion---------------------

	for (std::map<int, int>::iterator
		iid = indsp.begin();
		iid != indsp.end();
		++iid)
	{
		if(iid->second ==iid->first)
			continue;
		_points[iid->second] = _points[iid->first];
	}
	_points.n=(int)indsp.size();
	for (std::map<int, int>::iterator
		iid = indsl.begin();
		iid != indsl.end();
		++iid)
	{
		if(iid->second ==iid->first)
			continue;
		_lines[iid->second] = _lines[iid->first];
	}
	_lines.n=(int)indsl.size();
	for (std::map<int, int>::iterator
		iid = indsd.begin();
		iid != indsd.end();
		++iid)
	{
		if(iid->second ==iid->first)
			continue;
		_paintedProps[iid->second] = _paintedProps[iid->first];
	}
	_paintedProps.n=(int)indsd.size();
	for (std::map<int, int>::iterator
		iid = indsc.begin();
		iid != indsc.end();
		++iid)
	{
		if(iid->second ==iid->first)
			continue;
		_colors[iid->second] = _colors[iid->first];
	}
	_colors.n=(int)indsc.size();
	
ajus_mem:
	//ajusta memoria
	if(!_entities.ajusta_mem())
		return false;
	if(!_points.ajusta_mem())
		return false;
	if(!_lines.ajusta_mem())
		return false;
	if(!_paintedProps.ajusta_mem())
		return false;
	if(!_colors.ajusta_mem())
		return false;
	indexRef();
	return true;
}
//*****************************************************************************************
bool CartoBase::FastClear()
{
	//verifica entidades

	int ind =0;
	//borra entidades marcadas
	for(int i =0; i<_entities.n; i++)
	{
		if(_entities[i].flagsInt & CARTOBASE_DELETED_ENTITY)
			continue;
		if(i == ind)
		{
			ind++;
			continue;
		}
		_entities[ind++]=_entities[i];
	}
	_entities.n =ind;
	reIndexRef();
	return true;
}
//*****************************************************************************************
bool CartoBase::MemClear()
{
	if(!FastClear())
		return false;
	int npts =0;
	int nlin=0;
	//cuenta tipos de entidades-----------
	for(int i =0; i< _entities.n; i++)
	{
		switch(_entities[i].type)
		{
		case(CartoBaseTypes::Point):
			npts++;
			break;
		case(CartoBaseTypes::Line):
			
			nlin++;
			npts+=_lines[_entities[i].id].n;
			break;;
		default:
			break;
		}
	}
	
	for(int i =0; i<_paintedProps.n; i++)
		_paintedProps[i].flags &= ~0x1; 
	for(int i =0; i<_colors.n; i++)
		_colors[i].flags &= ~0x1; 
	Cgarray<CartoBasePoint> points;//coordenadas
	Cgarray<CartoBaseLine> lines;//lineas
	Cgarray<CartoBasePaintedProps> paintedProps;//propiedades de pintado
	Cgarray<CartoBaseColor> colors;
	//pide memoria para arrays auxiliares
	
	if(!(points+=npts))
		return false;
	if(!(lines+=nlin))
		return false;
	for(int i =0; i<_entities.n; i++)
	{
		CartoBaseInfoEntity e =get(i);

		switch(e.entity()->type)
		{
		case(CartoBaseTypes::Point):
			points+ *e.pto();
			e.entity()->id = points.n-1;
			break;
		case(CartoBaseTypes::Line):
			lines+*e.line();
			lines[lines.n-1].ini = points.n;
			for(int jj =0; jj<e.line()->n; jj++)
				points+ e.pto()[jj];
			e.entity()->id = lines.n-1;
			break;
		default:
			break;
		}
		//revisa propiedades de pintado
		if(e.paintp()->flags & 0x1)
		{
			e.entity()->idPaintp = e.paintp()->color;
			continue;
		}
		
		paintedProps+*e.paintp();
		//revisa color

		if(e.color()->flags & 0x1)
		{
			paintedProps[paintedProps.n-1].color = e.color()->color;
		}
		else
		{
			paintedProps[paintedProps.n-1].color = colors.n;
			colors+*e.color();
			e.color()->flags |=0x1 ;
			e.color()->color = colors.n-1;
		}
		e.paintp()->flags |= 0x1;
		e.entity()->idPaintp = paintedProps.n;
	}

	if(_colors.ptr)
		free(_colors.ptr);
	_colors = colors;
	colors.ptr = NULL;

	if(_lines.ptr)
		free(_lines.ptr);
	_lines = lines;
	lines.ptr = NULL;

	if(_paintedProps.ptr)
		free(_paintedProps.ptr);
	_paintedProps = paintedProps;
	paintedProps.ptr = NULL;

	if(_points.ptr)
		free(_points.ptr);
	_points = points;
	points.ptr = NULL;
	
	//ajusta memoria
	if(!_entities.ajusta_mem())
		return false;
	if(!_points.ajusta_mem())
		return false;
	if(!_lines.ajusta_mem())
		return false;
	if(!_paintedProps.ajusta_mem())
		return false;
	if(!_colors.ajusta_mem())
		return false;
		
	return true;
}
//*****************************************************************************************
bool CartoBase::importShp(char* path)
{
	CartoBaseShpManager shp;
	Cb_file f;
	char patdbf[256];
	if(!f.abre(path,1,0,1))
		return false;
	shp.set(this);
	int oldia =typeIA ;
	typeIA = NIa;
	if(!shp.ImportShp(&f))
	{
		typeIA = oldia;
		return false;
	}
	typeIA = oldia;
	if(typeIA== NIa || typeIA == IntIa)
		return true;
	CartoBaseDBFManager dbf;
	return dbf.leer(Cdir_manager::cambia_extension_archivo(path,patdbf,"dbf"),this);
}
//*****************************************************************************************
bool CartoBase::exportShp(char* path)
{
	return fexportShp(path);
}
//*****************************************************************************************
bool CartoBase::ptosExportShp(char* path)
{
	return fexportShp(path, CartoBaseTypes::Point);
}
//*****************************************************************************************
bool CartoBase::linesExportShp(char* path)
{
	return fexportShp(path, CartoBaseTypes::Line);
}
//*****************************************************************************************
bool CartoBase::fexportShp(char* path, int type)
{
	char patdbf[256];

	CartoBaseShpManager shp;

	Cb_file f;
	Cb_file fshx;

	if(!f.abre(path,2,1))
		return false;
	if(!fshx.abre(Cdir_manager::cambia_extension_archivo(path,patdbf,"shx"),2,1))
		return false;
	
	if(!shp.ExportShp(&f,&fshx,this, type))
		return false;
	if(typeIA== NIa)
		return true;
	CartoBaseDBFManager dbf;
	FiterCartoBase enti;
	if(type == CartoBaseTypes::Ndef)
		type = _entities[0].type;
	for(int i =0; i<_entities.n; i++)
	{
		if(_entities[i].type == type)
			enti.ind+i;

	}
	enti.cb = this;
	return dbf.grabar(Cdir_manager::cambia_extension_archivo(path,patdbf,"dbf"), this,&enti);
	//exporta dbf;
}
//*****************************************************************************************
void CartoBase::iniIndexRef()
{
	refIndex.clear();
	for(int i=0; i<_entities.n; i++)
	{
		_entities[i].ref=i;
		refIndex[i]=i;
	}
	ref = _entities.n;
}
//*****************************************************************************************
void CartoBase::reIndexRef()
{
	refIndex.clear();
	for(int i=0; i<_entities.n; i++)
	{
		refIndex[_entities[i].ref]=i;
	}
}
//*****************************************************************************************
void CartoBase::indexRef(bool buscaRepes)
{
	refIndex.clear();
	int ref_max=-1;
	int r;
	bool repes =false;
	//busca maximo u si hay repes
	for(int i=0; i<_entities.n; i++)
	{
		r =_entities[i].ref;
		refIndex[r]=i;
		if(r>ref_max)
			ref_max = r;
	}
	if(ref<= ref_max)
		ref = ref_max;
	if(!buscaRepes)
		return;

	for(int i=0; i<_entities.n; i++)
	{
		r =_entities[i].ref;
		if(refIndex[r]!= i)
		{
			//referencias repetidas
			_entities[i].ref =ref;
			refIndex[ref] = i;
			ref++;
		}
	}
}
//*****************************************************************************************
void* CartoBase::getIa( int refEnt )
{
	if(iaEx)
		return iaEx->IaGet(refEnt);
	return NULL;
}
//*****************************************************************************************
void CartoBase::setExIa( DataIaCartoBase* ia )
{
	typeIA = ExIa;
	iaEx=ia;
	iaEx->CBSet(this);
	//aņade a ia entidades existentes
	for (int i =0; i<_entities.n; i++)
	{
		if(_entities[i].flagsInt & CARTOBASE_DELETED_ENTITY)
			continue;
		iaEx->IaAdd((_entities[i].ref));
	}
}
//*****************************************************************************************
bool CartoBase::IaGetSize( int *ncolm )
{
	*ncolm =1;
	return true;
}
//*****************************************************************************************
bool CartoBase::IaGetColm( int icol, char* name, BYTE *type, int *size, int*ndecimal )
{
 if(icol!=0)
	 return false;
 *size = 10;
 *ndecimal=0;
	*type = DBF_TYPE_DATA_I;
 strcpy(name,iaName);
 return true;
}
//*****************************************************************************************
bool CartoBase::IaGetVal( int refEnt, int icol, int* v )
{
	if(icol!=0)
		return false;
	*v =getRef(refEnt).entity()->ia;
	return true;
}
//*****************************************************************************************
void CartoBase::setNameIa( char *name )
{
	strcpy(iaName, name);
}
//*****************************************************************************************

CartoBaseInfoEntity FiterCartoBase::getEntity( int i )
{
	return cb->get(ind[i]);
}
//*****************************************************************************************
int FiterCartoBase::getNumberEntities()
{
	return ind.n;
}
//*****************************************************************************************