#include "StdAfx.h"
#include "Fdbf.h"
//*****************************************************************************************
Fdbf::Fdbf(void)
{
}
//*****************************************************************************************
Fdbf::~Fdbf(void)
{
}
//*****************************************************************************************
bool Fdbf::lee( Cb_file *file)
{
	int ncol;
	colm.n =0;
	iniCol.n =0;
	buf.n=0;
	if(!file->lee(&head, sizeof(head)))
		return false;
	ncol = (head.nb_cab - sizeof(Hdr_dbf) - 1) / sizeof(Fld_dbf);
	if(ncol<=0)
		return false;
	if(!(colm+=ncol))
		return false;
	if(!(iniCol+=ncol))
		return false;
	colm.n = ncol;
	iniCol.n = ncol;
	//pilla info de campos-----------------------
	if(!file->lee(&colm[0], sizeof(Fld_dbf)*colm.n))
		return false;
	int aux =1;
	for(int i =0; i<colm.n; i++)
	{
		iniCol[i]=aux;
		aux+=colm[i].nb;
	}
	//lee reserva
	if(!file->lee(&ncol, 1))
		return false;
	if(!(buf+=head.nb_rec))
		return false;
	buf.n = head.nb_rec;
	f= file;
	nReadRow =0;
	return true;
}
//*****************************************************************************************
int Fdbf::leeNexRow()//devuelve 1 si ok 0 si no mas -1 si error
{
	if(nReadRow>=head.nrec)
		return 0;
	if(!f->lee(&buf[0], head.nb_rec))
		return -1;
	nReadRow++;
	return 1;
}
//*****************************************************************************************
char* Fdbf::getName(int ncol)
{
	if(ncol>=colm.n)
		return 0;
	return colm[ncol].nombre;
}
//*****************************************************************************************
BYTE Fdbf::getType(int ncol)
{
	if(ncol>=colm.n)
		return 0;
	return colm[ncol].tipo;
}
//*****************************************************************************************
int Fdbf::getSize(int ncol)
{
	if(ncol>=colm.n)
		return 0;
	return (int)colm[ncol].nb;
}
//*****************************************************************************************
int Fdbf::getNrow()
{
	return head.nrec;
}
//*****************************************************************************************
int Fdbf::getNcolm()
{
	return colm.n;
}
//*****************************************************************************************
char* Fdbf::get(int ncol)
{
	if(ncol>=colm.n)
		return 0;
	//if(!f->lee(&buf[0], head.nb_rec))
	//	return NULL;
	return &buf[iniCol[ncol]];
}
//*****************************************************************************************
bool Fdbf::bufMem(int ncol)
{	
	char*d = get(ncol);
	int nb = colm[ncol].nb+1;
	if(buf2.m<nb)
	{
		buf2.n=0;
		if(!(buf2+=nb))
			return false;
	}
	buf2.n = nb;
	char *s=&buf2[0];
	memcpy(s,d,nb-1);
	buf2[nb-1] = 0;
	return  true;
}
//*****************************************************************************************
double Fdbf::getD(int col)
{
	if(!bufMem(col))
		return 0;
	char *str=&buf2[0];
	/*double k;
	if ((*camp)[ic].tipo == 6)
	{
		sscanf(str,"%x",&k);
		return(k);
	}
	else if ((*camp)[ic].tipo == 7)
	{
		str[2] = 0;
		str[5] = 0;
		k = atol(str) * 3600;
		k = atol(&str[3]) * 60 + k;
		k = atol(&str[6]) + k;
		return(k);
	}*/
	return(atof(&buf2[0]));
}
//*****************************************************************************************
int Fdbf::getI(int col)
{
	return (int)getD(col);
}
//*****************************************************************************************
char* Fdbf::getStr(int col)
{
	if(!bufMem(col))
		return 0;
	char *str=&buf2[0];
	char*s=&buf2[buf2.n-1];
	while((*s == ' ' || *s==0) && s!=str)
	{
		*s = 0;
		s--;
	}

	return str;
}
//*****************************************************************************************
__int64 Fdbf::getI64(int col)
{
	if(!bufMem(col))
		return 0;
	char *str=&buf2[0];
	int dd,mm,aa;
	dd = atol(&str[6]);
	str[6] = 0;
	mm = atol(&str[4]);
	str[4] = 0;
	aa = atol(str);
	CTime tt(aa,mm,dd,0,0,0,-1);
	return(tt.GetTime());
}
//*****************************************************************************************
bool Fdbf::set(int ncol, int nRow, Cb_file *file)
{
	f = file;
	colm.n =0;
	nReadRow =-1;
	if(!(colm+=ncol))
		return false;
	iniCol.n =0;
	if(!(iniCol+=ncol))
		return false;
	memset(&head,0,sizeof(Hdr_dbf));

	CTime tt =  CTime::GetCurrentTime();
	colm.n = ncol;
	iniCol.n = ncol;
	head.ver =3;
	head.dia=(BYTE)tt.GetDay();
	head.mes=(BYTE)tt.GetMonth();
	head.dia=(BYTE)(tt.GetYear() - 1900);
	head.nrec=nRow;
	head.nb_cab = (short) (ncol * sizeof(Fld_dbf) + 1 + sizeof(Hdr_dbf));
	if(!f->escribe(&head, sizeof(head)))
		return false;
	return true;
}
//*****************************************************************************************
bool Fdbf::setCol(int icol, char *name, BYTE type, int size, int ndecimals)
{
	if(icol<0 || icol>colm.n)
		return false;
	nReadRow =-1;
	int i =0;
	//copia de nombre segura--------
	for(; i<11; i++)
	{
		colm[icol].nombre[i]=name[i];
		if(!name[i])
			break;
	}
	colm[icol].nombre[i] =0;
	//------------------------------
	colm[icol].tipo = type;
	colm[icol].nb = size;
	colm[icol].nd = ndecimals;

	switch(type)
	{
	case(DBF_TYPE_DATA_I64):
	case(DBF_TYPE_DATA_STR):
	case(DBF_TYPE_DATA_BIN):
	case(DBF_TYPE_DATA_I):
		colm[icol].nd  =0;
		break;
	}
	
	return true;
}
//*****************************************************************************************
bool Fdbf::iniciaRecords()
{
	if(nReadRow>=0)
		return true;
	nReadRow =0;
	int nb =1;
	for(int i =0; i<colm.n; i++)
	{
		iniCol[i]=nb;
		nb +=colm[i].nb;
	}
	buf.n =0;
	if(!(buf+=nb))
		return false;
	buf.n =nb;
	head.nb_rec = nb;
	if(!f->irAini())
		return false;
	if(!f->escribe(&head, sizeof(head)))
		return false;
	//graba info------------------------
	if(!f->escribe(&colm[0], sizeof(Fld_dbf)*colm.n))
		return false;
	//graba terminacion de head
	char ff = 13;
	if(! f->escribe(&ff, sizeof(ff)))
		return false;
	return true;
}
//*****************************************************************************************
bool Fdbf::addVal(int icol, int v)
{
	char st1[64];
	if(!iniciaRecords())
		return false;
	buf2.n =0;

	if(!(buf2+=(colm[icol].nb+1)))
		return false;
	buf2.n =colm[icol].nb+1;

	sprintf(st1,"%%0%ldd",colm[icol].nb);
	sprintf(&buf2[0],st1,v);
	
	int n = (int)strlen(&buf2[0]);
	if (n > colm[icol].nb)
		n = colm[icol].nb;
	//alinea a la derecha
	char *st = &buf[iniCol[icol]];
	memset(st,0x20, colm[icol].nb);
	memcpy(st+colm[icol].nb-n,&buf2[0],n);
	return true;
}
//*****************************************************************************************
bool Fdbf::addVal(int icol, double v)
{
	char st1[64];
	if(!iniciaRecords())
		return false;
	buf2.n =0;

	if(!(buf2+=colm[icol].nb))
		return false;
	buf2.n =colm[icol].nb;

	sprintf(st1,"%%1.%ldlf",colm[icol].nd);
	sprintf(&buf2[0],st1,v);
	
	int n =(int) strlen(&buf2[0]);
	if (n > colm[icol].nb)
		n = colm[icol].nb;
	//alinea a la derecha
	char *st = &buf[iniCol[icol]];
	memset(st,0x20, colm[icol].nb);
	memcpy(st+colm[icol].nb-n,&buf2[0],n);
	return true;
}
//*****************************************************************************************
bool Fdbf::addVal(int icol, __int64 v)
{
	char st1[32];
	CTime tt(v);

	if(!iniciaRecords())
		return false;

	buf2.n =0;

	if(!(buf2+=colm[icol].nb))
		return false;
	buf2.n =colm[icol].nb;

	strcpy(st1,tt.Format("%Y%m%d"));

	sprintf(&buf2[0],st1,v);

	int n =(int) strlen(&buf2[0]);
	if (n > colm[icol].nb)
		n = colm[icol].nb;
	//alinea a la derecha
	char *st = &buf[iniCol[icol]];
	memset(st,0x20, colm[icol].nb);
	memcpy(st+colm[icol].nb-n,&buf2[0],n);

	return true;
}
//*****************************************************************************************
bool Fdbf::finRow()
{
	//comprueba maximo
	if(nReadRow>= head.nrec)
		return false;
	nReadRow++;
	buf[0]=' ';
	//graba buffer en archivo
	if(!f->escribe(&buf[0], buf.n))
		return false;
	//si es el final graba head
	if(nReadRow>= head.nrec)
	{
		buf[0]=26;
		if(!f->escribe(&buf[0], 1))
			return false;
	}
	return true;
}
//*****************************************************************************************
bool Fdbf::addVal(int icol, char* v)
{
	if(!iniciaRecords())
		return false;
	int i =0;
	char *dt=&buf[iniCol[icol]];
	double maxi = colm[icol].nb;
	//copia de nombre segura--------
	for(; i<maxi; i++)
	{
		dt[i]=v[i];
		if(!v[i])
			break;
	}
	dt[i] =0;
	return true;
}
//*****************************************************************************************
bool Fdbf::addVal(int icol, void* v)
{
	if(!iniciaRecords())
		return false;
	memcpy(&buf[iniCol[icol]],v,colm[icol].nb);
	return true;
}
//*****************************************************************************************
int Fdbf::findCol( char *name )
{
	for(int i =0; i<colm.n;i++)
	{
		if(0==strcmp(colm[i].nombre,name))
			return i;
	}
	return -1;
}
//*****************************************************************************************
bool ManagerDbf::leer(char* file, ListenerDbf_W* lr)
{
	Cb_file f;
	if(!f.abre(file,1,0,true))
		return false;
	
	return leer(&f,lr);
}
//*****************************************************************************************
bool ManagerDbf::leer(Cb_file* f, ListenerDbf_W* lr)
{
	Fdbf dbf;
	if(!dbf.lee(f))
		return false;
	int nrow = dbf.getNrow();
	int ncolm = dbf.getNcolm();
	if(!lr->DbfSet(nrow, ncolm))
		return false;
	//prepara las columnas---------------
	for(int i =0; i<ncolm; i++)
	{
		if(!lr->DbfSetColm(dbf.getName(i),dbf.getType(i),dbf.getSize(i)))
			return false;
	}
	//recorre las filas---------------
	int error =dbf.leeNexRow();
	while(error ==1)
	{
		//por cada fila recorre las columnas
		for(int i =0; i<ncolm; i++)
		{
			bool res =false;
			switch(dbf.getType(i))
			{
			case(DBF_TYPE_DATA_STR):
				res =lr->DbfaddVal(i,dbf.getStr(i));
				break;
			case(DBF_TYPE_DATA_I64):
				res =lr->DbfaddVal(i,dbf.getI64(i));
				break;
			case(DBF_TYPE_DATA_D):
				res =lr->DbfaddVal(i,dbf.getD(i));
				break;
			case(DBF_TYPE_DATA_BOOL):
				return false;
				break;
			case(DBF_TYPE_DATA_BIN):
				res =lr->DbfaddVal(i,dbf.get(i));
				break;
			case(DBF_TYPE_DATA_I):
				res =lr->DbfaddVal(i,dbf.getI(i));
				break;
			default:
					return false;
			}
			if(!res)
				return false;
		}
		if(!lr->DbfFinRow())
			return false;
		error =dbf.leeNexRow();
	}
	
	return error == 0 && lr->DbfFinRow();

}
//*****************************************************************************************
bool ManagerDbf::grabar(char* file, ListenerDbf_R* lw)
{
	Cb_file f;
	if(!f.abre(file,2,true))
		return false;
	return grabar(&f,lw);
}
//*****************************************************************************************
bool ManagerDbf::grabar(Cb_file* f, ListenerDbf_R* lw)
{
	Fdbf dbf;
	int nrow =-1;
	int ncolm =-1;
	char name[11];
	BYTE type;
	int size;
	int nd;
	if(!lw->DbfGet(&nrow, &ncolm) /*|| nrow<=0 || ncolm<=0*/)
		return false;
	if(!dbf.set(ncolm, nrow, f))
		return false;
	//prepara las columnas---------------
	for(int i =0; i<ncolm; i++)
	{
		if(!lw->DbfGetColm(i,name,&type,&size,&nd))
			return false;
		if(!dbf.setCol(i,name,type,size,nd))
			return false;
	}
	//recorre las filas---------------
	char *cv;
	void *vv;
	double dv;
	int iv;
	__int64 i64v;
	for(int j =0;j<nrow; j++)
	{
		//por cada fila recorre las columnas
		for(int i =0; i<ncolm; i++)
		{
			bool res =false;
			switch(dbf.getType(i))
			{
			case(DBF_TYPE_DATA_STR):
				res =lw->DbfGetVal(j, i, &cv) && dbf.addVal(i,cv);
				break;
			case(DBF_TYPE_DATA_I64):
				res =lw->DbfGetVal(j, i, &i64v) && dbf.addVal(i,i64v);
				break;
			case(DBF_TYPE_DATA_D):
				res =lw->DbfGetVal(j, i, &dv) && dbf.addVal(i,dv);
				break;
			case(DBF_TYPE_DATA_BOOL):
				return false;
				break;
			case(DBF_TYPE_DATA_BIN):
				res =lw->DbfGetVal(j, i, &vv) && dbf.addVal(i,vv);
				break;
			case(DBF_TYPE_DATA_I):
				res = lw->DbfGetVal(j, i, &iv) && dbf.addVal(i,iv);

				break;
			default:
				return false;
			}
			if(!res)
				return false;
		}
		if(!lw->DbfFinW())
			return false;
		if(!dbf.finRow())
			return false;
	}

	return true;
}
//*****************************************************************************************