#include <io.h>
#include <malloc.h>
#include <fcntl.h>
#include <share.h>
#include <string.h>
#include "dbf.h"

extern "C" void *CreateLoadDbf(char *Name);
extern "C" void DeleteDbf(void *Basa);
extern "C" void GetFieldItDbf(void *Basa,int Items, char *Field, char *str);
extern "C" void SetFieldItDbf(void *Basa,int Items, char *Field, char *str);
extern "C" int GetCountItDbf(void *Basa);
extern "C" int SaveDbf(void *Basa);
//-------------------------------------------------------
//----------------- TBasaDBF для работы с DBF -----------
//-------------------------------------------------------
TBasaDBF::TBasaDBF()
{
 db_head_ptr =(db_head *)calloc(sizeof(db_head),1);
 db_head_ptr->ver=3;

 db_head_ptr->numb_rec=0;
 db_head_ptr->len_head=sizeof(db_head)+2;
 db_head_ptr->len_rec=1;
 name = strdup("compl2.dbf");

 db_field_ptr = NULL;
 items = NULL;
}

TBasaDBF::~TBasaDBF()
{
 int i;

 if(db_field_ptr){free(db_field_ptr); db_field_ptr=NULL;}
 if(items)
 {
  for(i=0;i<db_head_ptr->numb_rec;i++) free(items[i]);
  free(items); items = NULL;
 }
 free(db_head_ptr);
}

int TBasaDBF::LoadFile(char *Name)
{
 int hd,i;
 db_head db_head_temp;

 free(name);
 name = strdup(Name);
 hd=sopen(Name,O_BINARY|O_RDWR,SH_DENYNO);
 if(hd <= 0) return(-1);

 lseek(hd,0,SEEK_SET);
 read(hd, &db_head_temp, sizeof(db_head));                /* читать заголовок  dbf-файла */
 if(filelength(hd)!=(db_head_temp.len_head+(db_head_temp.len_rec*db_head_temp.numb_rec)+1)){close(hd); return(-1);}

 if(db_field_ptr){ free(db_field_ptr); db_field_ptr=NULL;}
 if(items)
 {
  for(i=0;i<db_head_ptr->numb_rec;i++) free(items[i]);
  free(items); items = NULL;
 }

 lseek(hd,0,SEEK_SET);
 read(hd, db_head_ptr, sizeof(db_head));                /* читать заголовок  dbf-файла */

 db_field_ptr = (db_str_rec *)calloc(db_head_ptr->len_head-sizeof(db_head)-2,1);
 read(hd,db_field_ptr,db_head_ptr->len_head-sizeof(db_head)-2);
 lseek(hd,2,SEEK_CUR);

 items=(void **)calloc(db_head_ptr->numb_rec, sizeof(void **));
 for(i=0;i<db_head_ptr->numb_rec;i++)
 {
  items[i]=(void *)calloc(db_head_ptr->len_rec,1);
  read(hd,items[i],db_head_ptr->len_rec);
 }
 close(hd);
 return(db_head_ptr->numb_rec);
}

int TBasaDBF::SaveFile(char *Name)
{
 int i,hd;

 if(Name == NULL) Name = name;
 hd=sopen(Name,O_BINARY|O_RDWR|O_CREAT|O_TRUNC,SH_DENYNO,S_IWRITE);
 if(hd<=0)return(-1);

 ::write(hd,db_head_ptr,sizeof(db_head));
 ::write(hd,db_field_ptr,db_head_ptr->len_head-sizeof(db_head)-2);
 ::write(hd,"\x0D\x00",2);
 for(i=0;i<db_head_ptr->numb_rec;i++)

 {
  ::write(hd,items[i],db_head_ptr->len_rec);
 }
 ::write(hd,"\x1A",1);
 close(hd);
 return(0);
}

int TBasaDBF::GetCountItems()
{
 return(db_head_ptr->numb_rec);
}

int TBasaDBF::LoadFields(db_str_rec *fields,int number)
{
 int i;

 if(db_field_ptr){ free(db_field_ptr); db_field_ptr=NULL;}
 db_field_ptr = (db_str_rec *)calloc(number,sizeof(db_str_rec));
 memcpy(db_field_ptr,fields,number*sizeof(db_str_rec));

 if(items)
 {
  for(i=0;i<db_head_ptr->numb_rec;i++) free(items[i]);
  free(items); items = NULL;
 }

 db_head_ptr->numb_rec=0;
 db_head_ptr->len_head=sizeof(db_head)+2+number*sizeof(db_str_rec);
 db_head_ptr->len_rec=1;
 for(i=0;i<number;i++) db_head_ptr->len_rec+=(db_field_ptr+i)->len_fild;

 return(0);
}

int TBasaDBF::addField(int pos,db_str_rec *field_ptr)
{
 int number,rec_len=1,i;
 db_str_rec *temp;
 char *str;

 number=(db_head_ptr->len_head-sizeof(db_head)-2)/sizeof(db_str_rec);
 if(pos<number)
 {
  temp=(db_str_rec *)calloc(number-pos,sizeof(db_str_rec));
  db_field_ptr=(db_str_rec *)realloc(db_field_ptr,(number+1)*sizeof(db_str_rec));
  memcpy(temp,db_field_ptr+pos,(number-pos)*sizeof(db_str_rec));
  memcpy(db_field_ptr+pos,field_ptr,sizeof(db_str_rec));
  memcpy(db_field_ptr+pos+1,temp,(number-pos)*sizeof(db_str_rec));
  free(temp);

  if(db_head_ptr->numb_rec)
  {
   for(i=0;i<pos;i++) rec_len+= (db_field_ptr+i)->len_fild;
   str=(char *)calloc(db_head_ptr->len_rec-rec_len,1);
   for(i=0;i<db_head_ptr->numb_rec;i++)
   {
    items[i]=realloc(items[i],db_head_ptr->len_rec+field_ptr->len_fild);
    memcpy(str,(char *)items[i]+rec_len,db_head_ptr->len_rec-rec_len);
    memcpy((char *)items[i]+rec_len+field_ptr->len_fild,str,db_head_ptr->len_rec-rec_len);
    memset((char *)items[i]+rec_len,' ',field_ptr->len_fild);
   }
   free(str);
  }
 }
 else
 {
  if(db_field_ptr)db_field_ptr=(db_str_rec *)realloc(db_field_ptr,(number+1)*sizeof(db_str_rec));
  else db_field_ptr=(db_str_rec *)calloc(1,sizeof(db_str_rec));
  memcpy(db_field_ptr+number,field_ptr,sizeof(db_str_rec));

  if(items)
  {
   for(i=0;i<db_head_ptr->numb_rec;i++)
   {
    items[i]=realloc(items[i],db_head_ptr->len_rec+field_ptr->len_fild);
    memset((char *)items[i]+db_head_ptr->len_rec,' ',field_ptr->len_fild);
   }
  }
 }
 db_head_ptr->len_head+=sizeof(db_str_rec);
 db_head_ptr->len_rec+=field_ptr->len_fild;

 return(0);
}

db_str_rec *TBasaDBF::getField(int posField)
{
 int number;

 number=(db_head_ptr->len_head-sizeof(db_head)-2)/sizeof(db_str_rec);
 if(posField >= number) return(NULL);
 return(db_field_ptr+posField);
}

db_str_rec *TBasaDBF::getField(char *NameField)
{
 int number, i, posField= -1;

 number=(db_head_ptr->len_head-sizeof(db_head)-2)/sizeof(db_str_rec);
 for(i=0;i<number;i++) if(!strcmp(NameField,(db_field_ptr+i)->name)){posField=i;break;}
 if(posField== -1) return(NULL);
 return(db_field_ptr+posField);
}

int TBasaDBF::CreateItems(int pos)
{
 void *temp;
 int number=db_head_ptr->numb_rec;

 if(pos<number)
 {
  temp=(void *)calloc(number-pos,sizeof(void *));
  items=(void **)realloc(items,(number+1)*sizeof(void **));
  memcpy(temp,items+pos,(number-pos)*sizeof(void *));
  items[pos]=(void *)calloc(db_head_ptr->len_rec,1);
  memset(items[pos],' ',db_head_ptr->len_rec);
  memcpy(items+pos+1,temp,(number-pos)*sizeof(void *));
  free(temp);
 }
 else
 {
  if(items)items=(void **)realloc(items,(number+1)*sizeof(void **));
  else items=(void **)calloc(1,sizeof(void **));
  items[db_head_ptr->numb_rec]=(void *)calloc(db_head_ptr->len_rec,1);
  memset(items[number],' ',db_head_ptr->len_rec);
 }
 db_head_ptr->numb_rec++;
 return(0);
}

int TBasaDBF::ModifiFieldIt(int posItems,int posField,char *str)
{
 int rec_len=1,number,i;

 number=(db_head_ptr->len_head-sizeof(db_head)-2)/sizeof(db_str_rec);
 if(posField>=number) return(-1);
 for(i=0;i<posField;i++) rec_len+= (db_field_ptr+i)->len_fild;
 if(posItems>=db_head_ptr->numb_rec) return(-1);
 strncpy((char *)items[posItems]+rec_len,str,(db_field_ptr+posField)->len_fild);
 return(0);
}

int TBasaDBF::ModifiFieldIt(int posItems,char *NameField,char *str)
{
 int rec_len=1,number,i,posField= -1;
// float temp;

 number=(db_head_ptr->len_head-sizeof(db_head)-2)/sizeof(db_str_rec);
 for(i=0;i<number;i++) if(!strcmp(NameField,(db_field_ptr+i)->name)){posField=i;break;}
 if(posField== -1) return(-1);
 for(i=0;i<posField;i++) rec_len+= (db_field_ptr+i)->len_fild;
 if(posItems>=db_head_ptr->numb_rec) return(-1);

// if((db_field_ptr+posField)->tip_fild=='N')
// {
//  temp=atof(str); fcvt(temp,(db_field_ptr+posField)->dec_field,str);
// }
 strncpy((char *)items[posItems]+rec_len,str,(db_field_ptr+posField)->len_fild);
 return(0);
}

int TBasaDBF::GetFieldIt(int posItems,int posField, char *str)
{
 int rec_len=1,number,i;

 number=(db_head_ptr->len_head-sizeof(db_head)-2)/sizeof(db_str_rec);
 if(posField>=number) return(-1);
 for(i=0;i<posField;i++) rec_len+= (db_field_ptr+i)->len_fild;
 if(posItems>=db_head_ptr->numb_rec) return(-1);
 strncpy(str,(char *)items[posItems]+rec_len,(db_field_ptr+posField)->len_fild);
 str[(db_field_ptr+posField)->len_fild]=0;
 return(0);
}

int TBasaDBF::GetFieldIt(int posItems,char *NameField, char *str)
{
 int rec_len=1,number,i,posField= -1;

 number=(db_head_ptr->len_head-sizeof(db_head)-2)/sizeof(db_str_rec);
 for(i=0;i<number;i++) if(!strcmp(NameField,(db_field_ptr+i)->name)){posField=i;break;}
 if(posField== -1) return(-1);
 for(i=0;i<posField;i++) rec_len+= (db_field_ptr+i)->len_fild;
 if(posItems>=db_head_ptr->numb_rec) return(-1);
 strncpy(str,(char *)items[posItems]+rec_len,(db_field_ptr+posField)->len_fild);
 str[(db_field_ptr+posField)->len_fild]=0;
 return(0);
}

int TBasaDBF::DeleteItems(int pos)
{
 void *temp;
 int number=db_head_ptr->numb_rec;

 if(pos>=number) return(-1);
 if(pos!=number-1)
 {
  temp=(void *)calloc(number-pos-1,sizeof(void *));
  memcpy(temp,items+pos+1,(number-pos-1)*sizeof(void *));
  free(items[pos]);
  items=(void **)realloc(items,(number-1)*sizeof(void **));
  memcpy(items+pos,temp,(number-pos-1)*sizeof(void *));
  free(temp);
 }
 else
 {
  free(items[pos]);
  items=(void **)realloc(items,(number-1)*sizeof(void **));
 }
 db_head_ptr->numb_rec--;
 return(0);
}

//===========================================================================
void *CreateLoadDbf(char *Name)
{
 TBasaDBF *basa = new TBasaDBF();
 if(basa->LoadFile(Name)== -1){ delete basa; return NULL;}
 return basa;
}

void DeleteDbf(void *Basa)
{
 delete (TBasaDBF *)Basa;
}

void GetFieldItDbf(void *Basa,int Items, char *Field, char *str)
{
 ((TBasaDBF *)Basa)->GetFieldIt(Items,Field,str);
}

void SetFieldItDbf(void *Basa,int Items, char *Field, char *str)
{
 ((TBasaDBF *)Basa)->ModifiFieldIt(Items,Field,str);
}

int GetCountItDbf(void *Basa)
{
 return ((TBasaDBF *)Basa)->GetCountItems();
}

int SaveDbf(void *Basa)
{
 return ((TBasaDBF *)Basa)->SaveFile(NULL);
}