#include "basis.h"

#include "dbtest.h"

static DBHANDLE * pDB;

/* ---------------------------------------------------------------- */

#define BLOB_FILE    "test.dat"
#define BLOB_WFILE   "test1.dat"

#define BLOBJ_MIN    10000
#define BLOBJ_MORE   50000

int BLOBJ_Read(DBHANDLE * pDBHANDLE, TFSurrogat fszFK_Id, TFShort fsFK_Table, 
              char * data, int max, char ** pdata, int * pmax, int * psize)
{
  MBlobj_Data MDBlobj;
  BLOBJ Blobj;
  
  MBlobj_Data_Init(&MDBlobj);
  BLOBJ_Init(&Blobj);
  { /* begin declare */
  Blobj_Data * pDBlobj;
  int iRc = TRUE;
  COMPR Compr;
  int i, size = 0;

  COMPR_Init (&Compr, SIZE_FBinary);

  COMPR_FmtBinFix (&Compr);

  COPY_FSurrogat(Blobj.fszFK_Id, fszFK_Id);
  COPY_FShort(Blobj.fsFK_Table, fsFK_Table);
  if (! BLOBJ_Select_FK(&Blobj, pDBHANDLE)) {
    fprintf(stderr, "(BLOBJ_Read) Error in BLOBJ_Select_FK\n");
    return FALSE;
  } else {
    while (BLOBJ_Fetch_FK(&Blobj, pDBHANDLE)) {
      COMPR_AddBin (&Compr, Blobj.fszComprData);
    }
    if (Blobj.fcCompressed == '1') 
      COMPR_FmtCompVar (&Compr);
  } 

  COMPR_Reset (&Compr);
  if (COMPR_GetId(&Compr) != Blobj_Data_TABLENR) {
    fprintf(stderr, "(BLOBJ_Read) Corrupted BLOBJ data-header\n");
    COMPR_Free(&Compr);
    return FALSE;
  }
  if (! COMPR_Read (&Compr, &MDBlobj)) {
    fprintf(stderr, "(BLOBJ_Read) Corrupted BLOBJ data-content\n");
    COMPR_Free(&Compr);
    return FALSE;
  }
  for (i = 0; i < MDBlobj.iCount; i++) {
    pDBlobj = MBlobj_Data_GetPtr(&MDBlobj, i);
    size = DATA_Add(size, BINARY_DATA(pDBlobj->fszBinData), BINARY_LEN(pDBlobj->fszBinData), 
                    data, max, pdata, pmax, BLOBJ_MIN, BLOBJ_MORE, NULL, NULL);
  }
  *psize = size;
  MBlobj_Data_Free(&MDBlobj);

  COMPR_Free(&Compr);

  return iRc;
} /* declare end */
}

int BLOBJ_Write(DBHANDLE * pDBHANDLE, TFSurrogat fszFK_Id, TFShort fsFK_Table, 
                int compressed, char * data, int size) 
{
  MBlobj_Data MDBlobj;
  Blobj_Data DBlobj;
  BLOBJ Blobj;
  
  MBlobj_Data_Init(&MDBlobj);
  Blobj_Data_Init(&DBlobj);
  BLOBJ_Init(&Blobj);
  { /* begin declare */
  COMPR Compr;
  short int sItemNumber;
  int iRc = TRUE; 
  int idx = 0;

  if (! BLOBJ_DeleteAll(pDBHANDLE)) {
    fprintf(stderr, "(BLOBJ_Write) Error in BLOBJ_DeleteAll\n");
    return FALSE;
  }

  COMPR_Init (&Compr, SIZE_FBinary);

  if (compressed) {
    COMPR_FmtCompVar (&Compr);
    Blobj.fcCompressed = '1';
  } else
    COMPR_FmtBinFix (&Compr);

  while (idx < size) {
    if (idx + SIZE_FBinary > size) {
      int rsize = size - idx;
      memcpy(BINARY_DATA(DBlobj.fszBinData), &data[idx], rsize);
      BINARY_LEN(DBlobj.fszBinData) = rsize;
      idx = size;
    } else {
      memcpy(BINARY_DATA(DBlobj.fszBinData), &data[idx], SIZE_FBinary);
      BINARY_LEN(DBlobj.fszBinData) = SIZE_FBinary;
      idx += SIZE_FBinary;
    }
    MBlobj_Data_Add(&MDBlobj, &DBlobj);
  }

  COMPR_Write (&Compr, &MDBlobj);
  MBlobj_Data_Free(&MDBlobj);

  COMPR_Reset (&Compr);

  sItemNumber = 1;
  COPY_FSurrogat(Blobj.fszFK_Id, fszFK_Id);
  COPY_FShort(Blobj.fsFK_Table, fsFK_Table);
  while (COMPR_GetBin (&Compr, &Blobj.fszComprData)) {
    Blobj.fsItemNumber = sItemNumber++;
    if (! BLOBJ_Insert (&Blobj, pDBHANDLE)) {
      fprintf(stderr, "(BLOBJ_Write) Error in BLOBJ_Insert\n");
      COMPR_Free(&Compr);
      return FALSE;
    }
  } 

  COMPR_Free(&Compr);

  return iRc;
} /* declare end */
}

/* ------------- */

int main (int argc, char *argv[])
{
  TEST Test;
  TEST Test1;
  
  TEST_Init(&Test);
  TEST_Init(&Test1);
  { /* begin declare */
  _MCMP MCmp;
  _CMP * pCmp;
  char dbname[20];
  int iRc = TRUE;
  int i, iCount;

  /* determine dbname from the commandline without default 'sdsys'
     if no dbname is given use 'test' */
  strcpy(dbname, "-");
  ARGV_GetDB_Name(argv, argc, dbname);
  if (strcmp(dbname, "") == 0) 
    strcpy(dbname, "test");

  if (! DBHANDLE_Init(&pDB, dbname)) {
    fprintf(stderr, "DBHANDLE_Init error!");
    exit(1);
  }
  /* cleanup the test-table */
  if (! TEST_DeleteAll(pDB)) {
    fprintf(stderr, "TEST_DeleteAll error!");
    exit(1);
  }
  COPY_FLong (Test.flIVal, 1000);
  COPY_FDouble (Test.fdDVal, 1000);
  /* without use of transactions each db-command 
     is done as one transaction */
  COPY_FChar_35 (Test.fszName, "Name1");
  if (! TEST_Insert(&Test, pDB)) {
    fprintf(stderr, "TEST_Insert error!");
    exit(1);
  }
  /* with use of transaction the database is blocked
     until DB_Commmit or DB_Rollback */
  if (! DB_Begin(pDB)) {
    fprintf(stderr, "DB_Begin error!");
    exit(1);
  }
  COPY_FChar_35 (Test.fszName, "Name2");
  if (! TEST_Insert(&Test, pDB)) {
    fprintf(stderr, "TEST_Insert error!");
    exit(1);
  }
  COPY_FChar_35 (Test.fszName, "Name3");
  if (! TEST_Insert(&Test, pDB)) {
    fprintf(stderr, "TEST_Insert error!");
    exit(1);
  }
  if (! DB_Commit(pDB)) {
    fprintf(stderr, "DB_Commit error!");
    exit(1);
  }
  /* this transaction uses DB_Rollback */
  if (! DB_Begin(pDB)) {
    fprintf(stderr, "DB_Begin error!");
    exit(1);
  }
  COPY_FChar_35 (Test.fszName, "Name4");
  if (! TEST_Insert(&Test, pDB)) {
    fprintf(stderr, "TEST_Insert error!");
    exit(1);
  }
  COPY_FChar_35 (Test.fszName, "Name5");
  if (! TEST_Insert(&Test, pDB)) {
    fprintf(stderr, "TEST_Insert error!");
    exit(1);
  }
  if (! DB_RollBack(pDB)) {
    fprintf(stderr, "DB_RollBack error!");
    exit(1);
  }
  /* read and print all items from the database */
  if (TEST_Select(&Test, pDB)) {
    fprintf(stdout, "%s\n", TEST_Attribs());
    while (TEST_Fetch(&Test, pDB)) {
      fprintf(stdout, "%s\n", TEST_Data(pDB, &Test));
    }
  }
  /* update-transaction */
  if (! DB_Begin(pDB)) {
    fprintf(stderr, "DB_Begin error!");
    exit(1);
  }
  COPY_FChar_35 (Test.fszName, "Name2");
  if (! TEST_SelectLk(&Test, pDB)) {
    fprintf(stderr, "TEST_SelectLk error!");
    exit(1);
  }
  COPY_FChar_35 (Test.fszName, "Name21");
  if (! TEST_Update(&Test, pDB)) {
    fprintf(stderr, "TEST_Update error!");
    exit(1);
  }
  if (! DB_Commit(pDB)) {
    fprintf(stderr, "DB_Commit error!");
    exit(1);
  }
  /* read and print all items from the database */
  if (TEST_Select(&Test, pDB)) {
    fprintf(stdout, "%s\n", TEST_Attribs());
    while (TEST_Fetch(&Test, pDB)) {
      fprintf(stdout, "%s\n", TEST_Data(pDB, &Test));
    }
  }

  /* --------------- */
  /* -  BLOB-Test  - */
  /* --------------- */

  if (! existsfile(BLOB_FILE)) {
    fprintf(stderr, "Warning: File '%s' does not exists!\n", BLOB_FILE);
  } else {
    char * data;
    int size;

    data = read_binfile(BLOB_FILE, &size);
    if (data == NULL || size == 0) {
      fprintf(stderr, "Warning: File '%s' read error or empty!\n", BLOB_FILE);
    } else {
      char * rdata;
      int rsize, rmax = -1;

      if (! BLOBJ_Write(pDB, Test.fszTEST_Id, TEST_TABLENR, FALSE, data, size)) {
        fprintf(stderr, "BLOBJ_Write error!\n");
        exit(1);
      }
      if (! BLOBJ_Read(pDB, Test.fszTEST_Id, TEST_TABLENR, NULL, -1, &rdata, &rmax, &rsize)) {
        fprintf(stderr, "BLOBJ_Write error!\n");
        exit(1);
      }
      if (! write_binfile(BLOB_WFILE, rdata, rsize)) {
        fprintf(stderr, "Warning: File '%s' write error!\n", BLOB_WFILE);
      }
      if (size != rsize) {
        fprintf(stderr, "BLOBJ_Write/Read error! (write-size = %d, read-size = %d)\n", size, rsize);
        exit(1);
      }
      if (memcmp(data, rdata, size) != 0) {
        fprintf(stderr, "BLOBJ_Write/Read error! (different file contents)\n");
        exit(1);
      }
    }
  }

  /* compare database-rows */
  _MCMP_Init(&MCmp);
  COPY_FChar_35 (Test.fszName, "Name1");
  if (! TEST_SelectLk(&Test, pDB)) {
    fprintf(stderr, "TEST_SelectLk error!");
    exit(1);
  }
  COPY_FChar_35 (Test1.fszName, "Name21");
  if (! TEST_SelectLk(&Test1, pDB)) {
    fprintf(stderr, "TEST_SelectLk error!");
    exit(1);
  }

  iCount = TEST_Compare(pDB, &Test, &Test1, &MCmp);

  /* print all differences */
  if (iCount == 0) {
    fprintf(stdout, "No differences!\n");
  } else {
    fprintf(stdout, "%d differences\n", iCount);
    fprintf(stdout, "%s\n", _CMP_Attribs());
    for (i = 0; i < MCmp.iCount; i++) {
      pCmp = _MCMP_GetPtr(&MCmp, i);
      fprintf(stdout, "%s\n", _CMP_Data(pDB, pCmp));
    }
  }
  _MCMP_Free(&MCmp);

  exit(0);
} /* declare end */
}
