#pragma once
#ifndef Fdbf_H
#define Fdbf_H
#include "base_head.h"
#include "b_file.h"
#include "garray.h"
#pragma pack(1)

typedef	struct	Hdr_dbf
{
	BYTE	ver,year,mes,dia;	// cuatro primeros bytes	
	long	nrec;				// nº de records (filas)
	short	nb_cab;		// nº de bytes de la cabecera
	short	nb_rec;		// nº de bytes de cada record
	BYTE	res[20];
} Hdr_dbf;

typedef	struct	Fld_dbf
{
	char	nombre[11];	// nombre del campo
	BYTE	tipo;		// tipo de campo
						// C	caracter
						// N	número
						// L	lógico (Y/N,T/F, y mas)
						// D	fecha (YYYYMMDD)
						// F	float, double
	BYTE	res1[4];
	BYTE	nb;			// nº de bytes del campo
	//Nuevo elena 201709
	union
	{
		BYTE	res2[15];
		struct{


			BYTE	nd;	//nº de decimales
			BYTE	res2_[14];		
		};
	};	
} Fld_dbf;

#pragma pack(8)

#define DBF_TYPE_DATA_STR	'C'
#define DBF_TYPE_DATA_I64	 'D'
#define DBF_TYPE_DATA_D		 'F' 
#define DBF_TYPE_DATA_BOOL	 'L' 
#define DBF_TYPE_DATA_BIN	 'M' 
#define DBF_TYPE_DATA_I		 'N' 

//clase base de dbf-------------------------------------
class UTILES_EXPORT Fdbf
{
	Hdr_dbf head;
	Cgarray<Fld_dbf>colm;
	Cgarray<char> buf;//buffer de fila
	Cgarray<char> buf2;//buffer auxi

	Cgarray<int>iniCol;//indice a el bite deonde empieza la columna iesima dentro de una fila
	Cb_file *f;
	int nReadRow;//numero de filas leidas actualmente
public:
	Fdbf(void);
	~Fdbf(void);

	//funciones de lectura
	bool lee( Cb_file *file);
	int leeNexRow();//devuelve 1 si ok 0 si no mas -1 si error
	
	double getD(int ncol);
	int getI(int ncol);
	char* getStr(int ncol);
	__int64 getI64(int ncol);
	char* get(int ncol);//devuelve buffer tal cual

	BYTE getType(int ncol);
	char* getName(int ncol);
	int findCol(char *name);

	int getSize(int ncol);
	int getNrow();
	int getNcolm();
	//funciones de escritura
	bool set(int ncol, int nRow, Cb_file *file);
	bool setCol(int icol, char *name, BYTE type, int size, int ndecimals=0);
	
	bool addVal(int icol, int v);
	bool addVal(int icol, double v);
	bool addVal(int icol, __int64 v);
	bool addVal(int icol, char* v);
	bool addVal(int icol, void* v);
	bool finRow();

private:
	bool bufMem(int ncol);
	bool iniciaRecords();
};

//clase lisener de lectura
class UTILES_EXPORT ListenerDbf_W
{
public:
	virtual bool DbfSet(int nrow, int ncolm){return true;}
	virtual bool DbfSetColm(char* name, BYTE type, int size){return true;}
	virtual bool DbfaddVal(int icol, int v){return true;}
	virtual bool DbfaddVal(int icol, double v){return true;}
	virtual bool DbfaddVal(int icol, __int64 v){return true;}
	virtual bool DbfaddVal(int icol, char* v){return true;}
	virtual bool DbfaddVal(int icol, void* v){return true;}
	virtual bool DbfFinRow(){return true;}
	virtual bool DbfFinR(){return true;}

};
//clase lisener de escritura
class UTILES_EXPORT ListenerDbf_R
{
public:
	virtual bool DbfGet(int *nrow, int *ncolm){return false;}
	virtual bool DbfGetColm(int icol, char* name, BYTE *type, int *size, int*ndecimal){return false;}
	virtual bool DbfGetVal(int irow, int icol, int* v){return false;}
	virtual bool DbfGetVal(int irow, int icol, double* v){return false;}
	virtual bool DbfGetVal(int irow, int icol, __int64* v){return false;}
	virtual bool DbfGetVal(int irow, int icol, char** v){return false;}
	virtual bool DbfGetVal(int irow, int icol, void** v){return false;}
	virtual bool DbfFinW(){return false;}

};


//clase manager dbf-------------------------
class UTILES_EXPORT ManagerDbf
{
public:
	static bool leer(Cb_file *file, ListenerDbf_W* lr);
	static bool grabar(Cb_file *file, ListenerDbf_R* lw);

	static bool leer(char* file, ListenerDbf_W* lr);
	static bool grabar(char* file, ListenerDbf_R* lw);
};

#endif
/*
ejemplo de uso--------------------------------
escritura---------
if(!f.abre("d:\\temp\\p2.dbf",2,true))
error =true;
if(!dbf.set(3,5,&f))
error = true;
if(!dbf.setCol(0,"id",DBF_TYPE_DATA_I,10))
error = true;
if(!dbf.setCol(1,"idf",DBF_TYPE_DATA_D,10,3))
error = true;
if(!dbf.setCol(2,"str",DBF_TYPE_DATA_STR,128))
error = true;
for(int i =0; i<5; i++)
{
if(!dbf.addVal(0,i))
error = true;
if(!dbf.addVal(1,i+(i*1./10)))
error = true;
if(!dbf.addVal(2,"holaHolita"))
error = true;
if(!dbf.finRow())
error = true;
}
f.cierra();
//lectura
if(!f.abre("d:\\temp\\p2.dbf",1))
error =true;
if(!dbf.lee(&f))
error = true;
idd =dbf.leeNexRow();
while(idd ==1)
{
int ii = dbf.getI(0);
double d= dbf.getD(1);
char* ss = dbf.getStr(2);

ii++;
d++;
ss[0]=0;
idd =dbf.leeNexRow();
}
*/