/*   -*- coding: utf-8 -*-  */
/**********************************************************************
*  fichier  : HfdHcb.c
*  Auteur   : Jacques DUCLOY
*  Date     : Octobre 94
*  adaptations : Janvier 97
*  $Id: HfdHcb.c,v 1.3 2005/07/11 16:46:58 parmentf Exp $
*
************************************************************************
* 
*     Copyright (C) 1996 CRIN - CNRS & INRIA Lorraine
*
***********************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "SxmlNode.h"
#include "Hfd.h"
#include "Hcs.h"

/******************************** Digit  ******************************/

#define HfdHcbDigitInit(c) c->curPos=c->initString

HfdHcbDigit* HfdHcbDigitCreate(char *digitStr)
{
  HfdHcbDigit* newCtrl;

  newCtrl = (HfdHcbDigit*) malloc(sizeof(HfdHcbDigit));
  HfdToolStrCopy(newCtrl->initString, digitStr);
  HfdHcbDigitInit(newCtrl);
  newCtrl->prev=NULL;
  newCtrl->next=NULL;
  return newCtrl;
}

int HfdHcbDigitNext(HfdHcbDigit* digit)
{
  if (!digit)return 0; /* return NULL; */
  digit->curPos++;
  if (digit->curPos[0])return 1;
  else 
    {
      digit->curPos=digit->initString;
      return HfdHcbDigitNext(digit->prev);
    }
}

/****************************** ListDigit ******************************/

HfdHcbListDigit *HfdHcbListDigitCreate(SxmlNode *n)
{
  HfdHcbListDigit *l;
  HfdHcbDigit *d;
  SxmlNode *s;

  l=(HfdHcbListDigit *)malloc(sizeof(HfdHcbListDigit));
  l->first=NULL;
  l->last =NULL;
  l->card=0;
  SxmlReset (n);
  while ((s=SxmlNextNode(n)))
    {
       l->card++;
       d=HfdHcbDigitCreate(SxmlLeafText(s));
       HfdToolListPrevNextInsert(l,d);
    }
 
  l->profile=malloc(l->card+1);
  return l;
}

void HfdHcbListDigitBuildProfile(HfdHcbListDigit* ld)
{
  int i;
  HfdHcbDigit *d;

  i=0;
  if ((d=ld->first))
    {
      do
	{
	  ld->profile[i++]=d->curPos[0];
	}
      while((d=d->next));
      ld->profile[i]=0;
    }
}

char *HfdHcbListDigitFirstProfile(HfdHcbListDigit* ld)
{
  HfdHcbDigit *d;

  if ((d=ld->first))
    {
      do
	{
	  d->curPos=d->initString;
	}
      while((d=d->next));
      HfdHcbListDigitBuildProfile(ld);
      return ld->profile;
    }
  else return NULL;
}

int HfdHcbListDigitNextProfile(HfdHcbListDigit* ld)
{
  if (HfdHcbDigitNext(ld->last))
    {
      HfdHcbListDigitBuildProfile(ld);
      return 1;
    }
  else return 0; /* return NULL; */
}

/****************************** PathUnit *******************************/

HfdHcbPathUnit *HfdHcbPathUnitCreate(SxmlNode *nodeDir, HfdHcb *hcb)
{
  HfdHcbPathUnit* unit;

  unit =(HfdHcbPathUnit*)malloc(sizeof(HfdHcbPathUnit));
  HfdToolListPrevNextInsert(hcb->listPathUnit,unit);

  unit->listDigit=HfdHcbListDigitCreate(nodeDir);
  unit->state='\0';
  hcb->listPathUnit->pathLength+= unit->listDigit->card + 3 /* .dd */ +1;
  unit->path= malloc(hcb->listPathUnit->pathLength +1);
  hcb->listPathUnit->keyLength+= unit->listDigit->card  +1;
  unit->key=malloc(hcb->listPathUnit->keyLength + 1);

  return unit;
}

char* HfdHcbPathUnitBuildPath(HfdHcb *hcb, HfdHcbPathUnit *unit, char *suff)
{
    strcpy(unit->path, unit->prev->path);
    strcat(unit->path,"/");
    strcat(unit->path, unit->listDigit->profile);
    strcat(unit->path,".");
    strcat(unit->path,suff);
    return(unit->path);
}


char* HfdHcbPathUnitBuildKey(HfdHcb *hcb, HfdHcbPathUnit *unit)
{
  if (unit->prev)
    {
      strcpy(unit->key, unit->prev->key);
      strcat(unit->key, unit->listDigit->profile);
      return(unit->key);
    }
  else return NULL;
}

char* HfdHcbPathUnitFirstKey(HfdHcb *hcb, HfdHcbPathUnit *unit)
{
  if (unit->prev)
    {
      HfdHcbListDigitFirstProfile( unit->listDigit);
      return HfdHcbPathUnitBuildKey(hcb, unit);
    }
  else return NULL;
}

char* HfdHcbPathUnitFirstPath(HfdHcb *hcb, HfdHcbPathUnit *unit, char *suff)
{

  HfdHcbListDigitFirstProfile(unit->listDigit);
  HfdHcbPathUnitBuildPath(hcb, unit, suff);
  HfdHcbPathUnitBuildKey(hcb, unit);
  return(unit->path);
}

char* HfdHcbPathUnitNextPath(HfdHcb *hcb, HfdHcbPathUnit *unit, char *suff)
{
  if (HfdHcbListDigitNextProfile(unit->listDigit))
    {
      HfdHcbPathUnitBuildPath(hcb, unit, suff);
      HfdHcbPathUnitBuildKey(hcb, unit);
      return(unit->path);
    }
  else return NULL;
}
/********************** ListPathUnit *************************************/

void HfdHcbListPathUnitCreate(HfdHcb *hcb)
{
  HfdHcbPathUnit *root;
  static char *empty = "" ;

  hcb->listPathUnit=
    (HfdHcbListPathUnit *)malloc(sizeof(HfdHcbListPathUnit ));
  hcb->listPathUnit->first=NULL;
  hcb->listPathUnit->last=NULL;

  root=(HfdHcbPathUnit *)malloc(sizeof(HfdHcbPathUnit));
  HfdToolListPrevNextInsert(hcb->listPathUnit,root);
  root->path=hcb->rootPath;
  root->key=empty;
  hcb->listPathUnit->pathLength = strlen(hcb->rootPath)+1;
  hcb->listPathUnit->keyLength =0;
}

/************************** HhdDirControlBloc ****************************/


HfdHcbDir* HfdHcbDirCreate(SxmlNode *nodeDir, HfdHcb *hcb)
{
  HfdHcbDir* dcb;

  dcb = (HfdHcbDir *) malloc(sizeof(HfdHcbDir));
  dcb->prev=NULL;
  dcb->next=NULL;
  dcb->pathDigit=HfdHcbPathUnitCreate(nodeDir,hcb);

  return dcb;
}

char *HfdHcbDirFirstDir(HfdHcb *hcb, HfdHcbDir *dcb)
{
  char *newPath;

  newPath=HfdHcbPathUnitFirstPath(hcb, dcb->pathDigit, "dd");
  mkdir (newPath, hcb->umask);
  return newPath;
}

char *HfdHcbDirNextDir(HfdHcb *hcb, HfdHcbDir *dir)
{
  char *newPath;

  if ((newPath=HfdHcbPathUnitNextPath(hcb, dir->pathDigit, "dd")))
    {
      mkdir (newPath, hcb->umask);
      return newPath;
    }
  else
    {
      if(dir->prev)
	{
	  HfdHcbDirNextDir(hcb, dir->prev);
	  return HfdHcbDirFirstDir(hcb, dir);
	}
      else return NULL;
    }
}
/******************************* HCB_ListDir *****************************/

void HfdHcbListDirCreate(HfdHcb *hcb)
{
  SxmlNode       *nodeDir;
  SxmlNode       *hfdStruct;
  HfdHcbDir     *dcb;

  hcb->listDir=(HfdHcbListDir *)malloc(sizeof(HfdHcbListDir ));
  hcb->listDir->first=NULL;
  hcb->listDir->last=NULL;

  hfdStruct=SxmlGetFirstChildByTagName(hcb->desc, "struct");
  nodeDir=SxmlGetFirstChildByTagName(hfdStruct, "dir");
  while(nodeDir)
    {
       dcb=HfdHcbDirCreate(nodeDir, hcb);
       HfdToolListPrevNextInsert(hcb->listDir,dcb);
       nodeDir=SxmlGetNextSiblingByTagName(nodeDir,"dir");
    }
  /*
  SgmlPathStrDo
    (hcb->desc, "/hfd/struct/dir", nodeDir,
     {
       dcb=HfdHcb_Dir_Create(nodeDir, hcb);
       HfdToolListPrevNextInsert(hcb->listDir,dcb);
     });
  */
}

char* HfdHcbListDirFirstDir(HfdHcb* hcb)
{
  HfdHcbListDir *lDir;
  HfdHcbDir     *dir;
  char           *path;

  if((lDir=hcb->listDir))
    {
      dir=lDir->first;
      do{ path=HfdHcbDirFirstDir(hcb,dir);}
      while((dir=dir->next));
    }
  else path=hcb->rootPath;

  return path;
}

char* HfdHcbListDirNextDir(HfdHcb* hcb)
{
  return HfdHcbDirNextDir(hcb, hcb->listDir->last);
}


/*************************** HCBFilePath **********************************/
void HfdHcbFilePathCreate(HfdHcb *hcb)
{
  SxmlNode *hfdStructFile;
  SxmlNode       *hfdStruct;

  hfdStruct=SxmlGetFirstChildByTagName(hcb->desc, "struct");
  hfdStructFile=SxmlGetFirstChildByTagName(hfdStruct, "file");

  /*  SgmlPathStrSearchFirst(hcb->desc,"/hfd/struct/file", hfdStructFile); */
  hcb->filePathUnit=HfdHcbPathUnitCreate(hfdStructFile, hcb);
}

void HfdHcbFilePathFirstFile(HfdHcb* hcb)
{
  char *newPath;
  newPath=HfdHcbPathUnitFirstPath(hcb,hcb->filePathUnit, "df");
  hcb->file=fopen(newPath,"w");
}

int HfdHcbFilePathNextFile(HfdHcb* hcb)
{
  char *newPath;
  fclose(hcb->file);
  if ((newPath=HfdHcbPathUnitNextPath(hcb,hcb->filePathUnit, "df")))
    {
      hcb->file=fopen(newPath,"w");
    }
  else
    {
      if (HfdHcbListDirNextDir(hcb))
	HfdHcbFilePathFirstFile(hcb);
      else return 0;
    }
  return 1;
}
/*************************** HfdRecordKey *******************************/
void HfdHcbRecordPathCreate(HfdHcb *hcb)
{
  SxmlNode *hfdStructKey;
  SxmlNode       *hfdStruct;
  hfdStruct=SxmlGetFirstChildByTagName(hcb->desc, "struct");
  hfdStructKey=SxmlGetFirstChildByTagName(hfdStruct, "key");
  /* SgmlPathStrSearchFirst(hcb->desc,"/hfd/struct/key", hfdStructKey); */
  hcb->recordPathUnit=HfdHcbPathUnitCreate(hfdStructKey, hcb);
}

char *HfdHcbRecordPathFirstKey(HfdHcb* hcb)
{
  HfdHcbListPathUnit *lUnit;
  HfdHcbPathUnit     *unit;

  if((lUnit=hcb->listPathUnit))
    {
      unit=lUnit->first;
      do{ HfdHcbPathUnitFirstKey(hcb,unit);}
      while((unit=unit->next));
    }
  return hcb->recordPathUnit->key;
}

char *HfdHcbRecordPathNextKey(HfdHcb* hcb)
{
  if (HfdHcbListDigitNextProfile(hcb->recordPathUnit->listDigit))
    {
      HfdHcbPathUnitBuildKey(hcb,hcb->recordPathUnit);
    }
  else
    {
      HfdHcbFilePathNextFile(hcb);
      HfdHcbListDigitFirstProfile(hcb->recordPathUnit->listDigit);
      HfdHcbPathUnitBuildKey(hcb,hcb->recordPathUnit);
    }
  return hcb->recordPathUnit->key;
}

/************************** HfdControlBloc ***********************************/

HfdHcb *HfdHcbCreateEmpty()
{
  HfdHcb *newHCB;
  newHCB=(HfdHcb*)malloc (sizeof(HfdHcb));

  newHCB->name          =NULL;
  newHCB->desc          =NULL;
  newHCB->listDir       =NULL;
  newHCB->pathNameBuffer=NULL;
  newHCB->currentPath   =NULL;
  newHCB->key           =NULL;
  newHCB->wBuf           =NewBuffer();
  newHCB->umask         =S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
  newHCB->hfdFile       =HfdFileCreate();

  return newHCB;
}

HfdHcb *HfdHcbCreate(SxmlNode *desc)
{
  HfdHcb *newHCB;

  newHCB=HfdHcbCreateEmpty();
  HfdHcbDesc(newHCB)=desc;
  /*  SgmlPathStrSearchFirstData(newHCB->desc,"/hfd/name", newHCB->name); */
  newHCB->name=SxmlLeafText(SxmlGetFirstChildByTagName(newHCB->desc, "name"));
  HfdToolStrCat2(newHCB->descFile, newHCB->name,".hcs");
  HfdToolStrCat2(HfdHcbRootPath(newHCB), newHCB->name,".hfd");
  
  HfdHcbListPathUnitCreate(newHCB);
  HfdHcbListDirCreate(newHCB);
  HfdHcbFilePathCreate(newHCB);
  HfdHcbRecordPathCreate(newHCB);
  return newHCB;
}

HfdHcb *HfdCreate(char *pathRoot)
{
  HfdHcb *newHCB;
  SxmlNode *desc;
  newHCB=HfdHcbCreateEmpty();
  BufferStrcpy(newHCB->wBuf, pathRoot);
  BufferStrcat(newHCB->wBuf, ".hcs");
  desc=SxmlFromFile(BufferString(newHCB->wBuf));
  HfdHcbDesc(newHCB)=desc;
 
  /*  newHCB->name=SxmlLeafText(SxmlGetFirstChildByTagName(newHCB->desc, "name")); */
  newHCB->name=pathRoot;

  HfdToolStrCat2(newHCB->descFile,newHCB->name,".hcs");
  HfdToolStrCat2(HfdHcbRootPath(newHCB), newHCB->name,".hfd");

  HfdHcbListPathUnitCreate(newHCB);
  HfdHcbListDirCreate(newHCB);
  HfdHcbFilePathCreate(newHCB);
  HfdHcbRecordPathCreate(newHCB);
  return newHCB;
}

void HfdHcbFree(HfdHcb *hcb)
{
  if (hcb)
    {
      if (hcb->descFile) free (hcb->descFile);
      if (hcb->rootPath) free (hcb->rootPath);
      if (hcb->hfdFile) HfdFileFree (hcb->hfdFile);
      if (hcb->wBuf) BufferFree(hcb->wBuf);
      free (hcb);
    }
}

char *HfdHcbGetPath(HfdHcb *hcb, char *key)
{
  char *path;
  HfdHcbDir *dir;
  char *leftKey;
  int lProfile;

  leftKey=key;
  path=hcb->pathNameBuffer;
  strcpy (path, hcb->rootPath);
  strcat (path,"/");
  dir=hcb->listDir->first;
  if(dir)
    {
      do
	{
	  lProfile=dir->pathDigit->listDigit->card;
	  strncat(path, leftKey, lProfile);
	  strcat (path,".dd");
	  leftKey+= lProfile;
	  strcat (path,"/");
	}
      while ((dir=dir->next));
    }
  strncat(path, leftKey, hcb->filePathUnit->listDigit->card);
  strcat (path, ".df");
  return path;
}

void HfdHcbPrint(HfdHcb *h)
{
  FILE *fdesc;

  fdesc=fopen(h->descFile,"w+"); 
  SxmlFilePrint(h->desc, fdesc);
  fprintf(fdesc,"\n"); 
  fclose(fdesc);
}



/****************** HfdOpenReadKey *********************************/

HfdHcb *HfdOpenReadKey(char *pathRoot)
{
  HfdHcb *hcb;
  SxmlNode *desc;
  SxmlNode *hfdDescName;
  char *path;

  hcb=NULL;

  path = malloc(strlen(pathRoot)+5);
  strcpy (path,pathRoot);
  strcat (path,".hcs");
  if ((desc=SxmlFromFile(path)))
    {
      hcb=HfdCreate(pathRoot);
      hcb->pathNameBuffer=malloc(HfdHcbPathNameSize(hcb));
      hcb->currentPath=malloc(HfdHcbPathNameSize(hcb));
      strcpy(hcb->currentPath,"");
      HfdSetFirstKey(hcb);
      hcb->isRunning=0;
    }
  free(path);
  return hcb;
}

/****************** HfdOpenPath ************************************/

int HfdOpenPath(HfdHcb *hfd, char *path)
{
  if (strcmp(path,HfdCurrentPath(hfd))==0) return 1;
  if (HfdFileOpen(hfd->hfdFile, path)) 
    {
      strcpy(HfdCurrentPath(hfd),path);
      return 1;
    }
  return 0;
}

/****************** DamHfdOpenPathCont ********************************/

int HfdOpenPathCont(HfdHcb *hfd, char *path, char *tag)
{
  if (strcmp(path, HfdCurrentPath(hfd))==0) return 1;
  if (HfdFileOpenReadCont(hfd->hfdFile, path)) 
    {
      strcpy(HfdCurrentPath(hfd),path);
      HfdFileSetRecordTag(hfd->hfdFile, tag);
      return 1;
    }
  return 0;
}




/****************** HfdRecordReadKey *******************************/

/**
   Returns the record of the @a hfd which key equals @a key.
 */

HfdRecord *HfdRecordReadKey(HfdHcb *hfd, char *key)
{
     char    *path;
     path=HfdHcbGetPath(hfd,key);
     hfd->isRunning=1;
     if (HfdOpenPath(hfd,path) )
       {
	 HfdRecord *rec;
	 if((rec=HfdFileGetRecordKey(hfd->hfdFile,key)))
	   {
	     strcpy(hfd->key,key);
	     return rec;
	   }
	 else return NULL;
       }
     else return NULL;
}

SxmlNode *HfdSxmlReadKey(HfdHcb *hfd, char *key)
{
     char    *path;
     hfd->isRunning=1;
     path=HfdHcbGetPath(hfd,key);
     if (HfdOpenPath(hfd,path) )
       {
	 SxmlNode *rec;
	 if((rec=HfdFileGetSxmlKey(hfd->hfdFile,key)))
	   {
	     strcpy(hfd->key,key);
	     return rec;
	   }
	 else return NULL;
       }
     else return NULL;
}


void HfdSetFirstKey(HfdHcb *hfd)
{
  SxmlNode *hfdStruct;
  int iKey;
  char *digit;
  /*  SgmlTreeIterator *it1 ;*/
  char *firstKey;

  /* hfdStruct=SxmlGetFirstChildByTagName(hfd->desc, "struct"); */
  firstKey=HcsGetFirstKey(hfd->desc);
  /*
  it1=SgmlTreeIteratorCreate();
  SgmlTreeIteratorInit(it1,hfdStruct);
  iKey=0;
  while (SgmlTreeNextData(it1))iKey++;
  */
  if(!hfd->key)
    {
      hfd->key=malloc(strlen(firstKey)+1);
      hfd->regKey=malloc(strlen(firstKey)+1);
    }
  /*
  SgmlTreeIteratorInit(it1,hfdStruct);
  iKey=0;
  while ((digit=SgmlTreeNextData(it1)))hfd->key[iKey++]=digit[0];
  hfd->key[iKey++]=0;
  */
  strcpy (hfd->key, firstKey);
}
