/**********************************************************************
*
*  projet   : DilibPro
*  module   : Dam  (Dilib Acces Method)
*  fichier  : DamHCB.c
*  Auteur   : Jacques DUCLOY
*  Date     : Octobre 94
*  adaptations : Janvier 97
*  $Id: DamHCB.c,v 1.3 2005/07/11 16:46:58 parmentf Exp $
*
************************************************************************
* 
*     Copyright (C) 1976 CRIN - CNRS & INRIA Lorraine
*
***********************************************************************/

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

#include "SgmlPath.h"

#include "DamFile.h"
#include "DamHCB.h"
#include "DamTool.h"

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

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

DamHCB_Digit* DamHCB_DigitCreate(char *digitStr)
{
  DamHCB_Digit* newCtrl;

  newCtrl = (DamHCB_Digit*) malloc(sizeof(DamHCB_Digit));
  DamToolStrCopy(newCtrl->initString, digitStr);
  DamHCB_DigitInit(newCtrl);
  newCtrl->prev=NULL;
  newCtrl->next=NULL;
  return newCtrl;
}

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

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

DamHCB_ListDigit *DamHCB_ListDigit_Create(SgmlNode *n)
{
  DamHCB_ListDigit *l;
  DamHCB_Digit *d;

  l=(DamHCB_ListDigit *)malloc(sizeof(DamHCB_ListDigit));
  l->first=NULL;
  l->last =NULL;
  l->card=0;

  SgmlDo
    (n,s,
     {
       l->card++;
       d=DamHCB_DigitCreate(SgmlLeafGetData(s));
       DamToolListPrevNextInsert(l,d);
     });
  l->profile=malloc(l->card+1);
  return l;
}

void DamHCB_ListDigit_BuildProfile(DamHCB_ListDigit* ld)
{
  int i;
  DamHCB_Digit *d;

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

char *DamHCB_ListDigit_FirstProfile(DamHCB_ListDigit* ld)
{
  DamHCB_Digit *d;

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

int DamHCB_ListDigit_NextProfile(DamHCB_ListDigit* ld)
{
  if (DamHCB_Digit_Next(ld->last))
    {
      DamHCB_ListDigit_BuildProfile(ld);
      return 1;
    }
  else return 0; /* return NULL; */
}

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

DamHCB_PathUnit *DamHCB_PathUnit_Create(SgmlNode *nodeDir, DamHCB *hcb)
{
  DamHCB_PathUnit* unit;

  unit =(DamHCB_PathUnit*)malloc(sizeof(DamHCB_PathUnit));
  DamToolListPrevNextInsert(hcb->listPathUnit,unit);

  unit->listDigit=DamHCB_ListDigit_Create(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* DamHCB_PathUnit_BuildPath(DamHCB *hcb, DamHCB_PathUnit *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* DamHCB_PathUnit_BuildKey(DamHCB *hcb, DamHCB_PathUnit *unit)
{
  if (unit->prev)
    {
      strcpy(unit->key, unit->prev->key);
      strcat(unit->key, unit->listDigit->profile);
      return(unit->key);
    }
  else return NULL;
}

char* DamHCB_PathUnit_FirstKey(DamHCB *hcb, DamHCB_PathUnit *unit)
{
  if (unit->prev)
    {
      DamHCB_ListDigit_FirstProfile( unit->listDigit);
      return DamHCB_PathUnit_BuildKey(hcb, unit);
    }
  else return NULL;
}

char* DamHCB_PathUnit_FirstPath(DamHCB *hcb, DamHCB_PathUnit *unit, char *suff)
{

  DamHCB_ListDigit_FirstProfile(unit->listDigit);
  DamHCB_PathUnit_BuildPath(hcb, unit, suff);
  DamHCB_PathUnit_BuildKey(hcb, unit);
  return(unit->path);
}

char* DamHCB_PathUnit_NextPath(DamHCB *hcb, DamHCB_PathUnit *unit, char *suff)
{
  if (DamHCB_ListDigit_NextProfile(unit->listDigit))
    {
      DamHCB_PathUnit_BuildPath(hcb, unit, suff);
      DamHCB_PathUnit_BuildKey(hcb, unit);
      return(unit->path);
    }
  else return NULL;
}
/********************** ListPathUnit *************************************/

void DamHCB_ListPathUnit_Create(DamHCB *hcb)
{
  DamHCB_PathUnit *root;
  static char *empty = "" ;

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

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

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


DamHCB_Dir* DamHCB_Dir_Create(SgmlNode *nodeDir, DamHCB *hcb)
{
  DamHCB_Dir* dcb;

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

  return dcb;
}

char *DamHCB_Dir_FirstDir(DamHCB *hcb, DamHCB_Dir *dcb)
{
  char *newPath;

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

char *DamHCB_Dir_NextDir(DamHCB *hcb, DamHCB_Dir *dir)
{
  char *newPath;

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

void DamHCB_ListDir_Create(DamHCB *hcb)
{
  SgmlNode       *nodeDir;
  DamHCB_Dir     *dcb;

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

  SgmlPathStrDo
    (hcb->desc, "/hfd/struct/dir", nodeDir,
     {
       dcb=DamHCB_Dir_Create(nodeDir, hcb);
       DamToolListPrevNextInsert(hcb->listDir,dcb);
     });
}

char* DamHCB_ListDir_FirstDir(DamHCB* hcb)
{
  DamHCB_ListDir *lDir;
  DamHCB_Dir     *dir;
  char           *path;

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

  return path;
}

char* DamHCB_ListDir_NextDir(DamHCB* hcb)
{
  return DamHCB_Dir_NextDir(hcb, hcb->listDir->last);
}


/*************************** HCB_FilePath **********************************/
void DamHCB_FilePath_Create(DamHCB *hcb)
{
  SgmlNode *hfdStructFile;
  SgmlPathStrSearchFirst(hcb->desc,"/hfd/struct/file", hfdStructFile);
  hcb->filePathUnit=DamHCB_PathUnit_Create(hfdStructFile, hcb);
}

void DamHCB_FilePath_FirstFile(DamHCB* hcb)
{
  char *newPath;
  newPath=DamHCB_PathUnit_FirstPath(hcb,hcb->filePathUnit, "df");
  hcb->file=fopen(newPath,"w");
}

int DamHCB_FilePath_NextFile(DamHCB* hcb)
{
  char *newPath;
  fclose(hcb->file);
  if ((newPath=DamHCB_PathUnit_NextPath(hcb,hcb->filePathUnit, "df")))
    {
      hcb->file=fopen(newPath,"w");
    }
  else
    {
      if (DamHCB_ListDir_NextDir(hcb))
	DamHCB_FilePath_FirstFile(hcb);
      else return 0;
    }
  return 1;
}
/*************************** HfdRecordKey *******************************/
void DamHCB_RecordPath_Create(DamHCB *hcb)
{
  SgmlNode *hfdStructKey;
  SgmlPathStrSearchFirst(hcb->desc,"/hfd/struct/key", hfdStructKey);
  hcb->recordPathUnit=DamHCB_PathUnit_Create(hfdStructKey, hcb);
}

char *DamHCB_RecordPath_FirstKey(DamHCB* hcb)
{
  DamHCB_ListPathUnit *lUnit;
  DamHCB_PathUnit     *unit;

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

char *DamHCB_RecordPath_NextKey(DamHCB* hcb)
{
  if (DamHCB_ListDigit_NextProfile(hcb->recordPathUnit->listDigit))
    {
      DamHCB_PathUnit_BuildKey(hcb,hcb->recordPathUnit);
    }
  else
    {
      DamHCB_FilePath_NextFile(hcb);
      DamHCB_ListDigit_FirstProfile(hcb->recordPathUnit->listDigit);
      DamHCB_PathUnit_BuildKey(hcb,hcb->recordPathUnit);
    }
  return hcb->recordPathUnit->key;
}

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

DamHCB *DamHCB_Create(SgmlNode *desc)
{
  DamHCB *newHCB;

  newHCB=(DamHCB*)malloc (sizeof(DamHCB));

  newHCB->listDir       =NULL;
  newHCB->pathNameBuffer=NULL;
  newHCB->currentPath   =NULL;
  newHCB->key           =NULL;
  newHCB->umask         =S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
  newHCB->damFile       =DamFileCreate();
  DamHCBdesc(newHCB)=desc;
  SgmlPathStrSearchFirstData(newHCB->desc,"/hfd/name", newHCB->name);
  DamToolStrCat2(newHCB->descFile,newHCB->name,".hcs");
  DamToolStrCat2(DamHCB_RootPath(newHCB), newHCB->name,".hfd");

  DamHCB_ListPathUnit_Create(newHCB);
  DamHCB_ListDir_Create(newHCB);
  DamHCB_FilePath_Create(newHCB);
  DamHCB_RecordPath_Create(newHCB);
  
  return newHCB;
}

void DamHCB_Free(DamHCB *hcb)
{
  if (hcb)
    {
      if (hcb->descFile) free (hcb->descFile);
      if (hcb->rootPath) free (hcb->rootPath);
      if (hcb->damFile) DamFile_Free (hcb->damFile);
      free (hcb);
    }
}

char *DamHCB_GetPath(DamHCB *hcb, char *key)
{
  char *path;
  DamHCB_Dir *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 DamHCB_Print(DamHCB *h)
{
  FILE *fdesc;

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