/**********************************************************************
 *
 *  module   : Hfd
 *  fichier  : HfdBaseBool.c
 *  Auteur   : Jacques DUCLOY
 *  Date     : octobre 2016
 *
 **********************************************************************/
 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "SxPath.h"
#include "HfdBase.h"
#include "StrDict.h"

HfdBase *HfdBaseCreate()
{
  HfdBase *newBase;
  newBase=(HfdBase *)malloc(sizeof(HfdBase));
  newBase->baseName=NULL;
  newBase->listIndexes=StrDictCreate(5,5);
  newBase->implicitIndex=NULL;
  return newBase;
}

void     HfdBaseFree(HfdBase *base)
{
  if (base->baseName) free(base->baseName);
  if (base->implicitIndex)
    {
      char *key;
      StrDictIteratorReset(base->listIndexes);
      while((key=StrDictNext(base->listIndexes)))
	{
	  HfdIndexClose ((HfdIndex *)StrDictValue(base->listIndexes));
	  free (key);
	}
      StrDictFree(base->listIndexes);
    }
  free (base);
}

char *HfdBaseSetBaseName( HfdBase *base, char *name)
{
  if (base->baseName) free(base->baseName);
  base->baseName=strdup(name);
  return base->baseName; 
}

int HfdIndexPrintMode;
/*
  x  : XmlMode
  s  : short split
  k  : split with copy key
  
 */

void HfdIndexBoolInit()
{
  HfdIndexPrintMode='x';
}

HfdIndex* HfdBaseNewIndex(HfdBase *base, char *indexCode)
{
  static Buffer *HfdBaseBufHfd=NULL;
  HfdIndex *newIndex;

  if (!HfdBaseBufHfd) HfdBaseBufHfd=NewBuffer();
  if (!base->baseName)HfdBaseSetBaseName(base, ".");
  BufferStrcpy(HfdBaseBufHfd, base->baseName);
  BufferStrcat(HfdBaseBufHfd, "/");
  BufferStrcat(HfdBaseBufHfd, indexCode);
  BufferStrcat(HfdBaseBufHfd, ".i");
  if ((newIndex=HfdIndexOpenRead(BufferString(HfdBaseBufHfd))))
    {
      StrDictAddNewDatum(base->listIndexes, strdup(indexCode), (char *)newIndex);
      if (!base->implicitIndex) base->implicitIndex=newIndex;
    }
  else 
    {
      fprintf(stderr, "index %s not founded\n",BufferString(HfdBaseBufHfd) );
      exit (EXIT_FAILURE);
    }
  return newIndex;
}

SxmlNode *HfdBaseTerm(HfdBase *base, SxmlNode *nodeTerm)
{
  char *term;
  SxmlNode *indexSxmlRecord;
  char *indexCode;
  HfdIndex *index;
  if (!nodeTerm)return NULL;
  term=SxmlLeafText(nodeTerm);
  indexCode=SxmlGetAttribute(nodeTerm, "index");
  if (!indexCode)
    indexSxmlRecord=HfdIndexReadSxmlRecord(base->implicitIndex, term);
  else
    {
      index=(HfdIndex *) StrDictSearch(base->listIndexes, indexCode);
      if (!index) index=HfdBaseNewIndex(base, indexCode);
      indexSxmlRecord=HfdIndexReadSxmlRecord(index, term);
    }
  if (!indexSxmlRecord) return NULL;
  return SxmlGetFirstChildByTagName(SxmlLastChild(indexSxmlRecord),"l");
}

SxmlNode *HfdBaseTermFromStr(HfdBase *base, char *str)
{
  if (!str)return NULL;
  if (str[0]==':')
    {
      char *posColon;
      SxmlNode *termNode;
      static Buffer *bufIndex=NULL;
      posColon=strchr(str+1, ':');
      if (!posColon)return SxmlLeafCreate("term", str);
      termNode=SxmlLeafCreate("term", posColon+1);
      if (!bufIndex) bufIndex=NewBuffer();
      BufferStrncpy(bufIndex, str+1, posColon-str-1);
      SxmlSetAttribute(termNode, "index", BufferString(bufIndex));
      return termNode;
    }
  else
    {
      return SxmlLeafCreate("term", str);
    }
}
SxmlNode *HfdBaseAnd (HfdBase *base, SxmlNode *nodeAnd)
{
   SxmlNode *currentResult;
   SxmlNode *nextResult;
   SxmlNode *currentInputNode;
   if (!nodeAnd)return NULL;
   currentInputNode=SxmlFirstChild(nodeAnd);
   currentResult=NULL;
   while (currentInputNode)
     {
       nextResult=HfdBaseEvalExpr(base, currentInputNode );
       /*
       if (SxmlNodeHasName(currentInputNode, "term"))
	 {
	   nextResult=HfdBaseTerm(base, currentInputNode);
       */
       if (nextResult)
	 {
	   if (currentResult)
	     {
	       SxmlNode *lAnd;
	       lAnd=HfdIndexAnd(currentResult,nextResult);
	       SxmlFree(currentResult);
	       if (!lAnd) return NULL;
	       currentResult=lAnd;
	     }
	   else
	     {
	       currentResult=SxmlRemoveChild(nextResult);
	     }
	 }
       else return NULL;
       currentInputNode=SxmlNextSibling(currentInputNode);
       if (!currentInputNode) return currentResult;
     }
   return NULL;
}

SxmlNode *HfdBaseOr (HfdBase *base, SxmlNode *nodeOr)
{
   SxmlNode *currentResult;
   SxmlNode *nextResult;
   SxmlNode *currentInputNode;
   if (!nodeOr)return NULL;
   currentInputNode=SxmlFirstChild(nodeOr);
   currentResult=NULL;
   while (currentInputNode)
     {
       nextResult=HfdBaseEvalExpr(base, currentInputNode );
       /*
       if (SxmlNodeHasName(currentInputNode, "term"))
       {
	   nextResult=HfdBaseTerm(base, currentInputNode);
       */
       if (nextResult)
	 {
	   if (currentResult)
	     {
	       SxmlNode *lOr;
	       lOr=HfdIndexOr(currentResult,nextResult);
	       SxmlFree(currentResult);
	       currentResult=lOr;
	     }
	   else
	     {
	       currentResult=SxmlRemoveChild(nextResult);
	     }
	 }
       currentInputNode=SxmlNextSibling(currentInputNode);
       if (!currentInputNode) return currentResult;
     }
   return NULL;
}

SxmlNode *HfdBaseEvalExpr(HfdBase *base, SxmlNode *expr)
{
  SxmlNode *resultList;
  if (SxmlNodeHasName(expr, "term")) 
    {
      resultList=HfdBaseTerm(base, expr);
      return resultList;
    }
  else if (SxmlNodeHasName(expr, "and")) 
    {
      resultList=HfdBaseAnd(base, expr);
      return resultList;
    }
  else if (SxmlNodeHasName(expr, "or")) 
    {
      resultList=HfdBaseOr(base, expr);
      return resultList;
    }
  return NULL;
}

SxmlNode *HfdBaseResultFromBoolExpr(HfdBase *base, SxmlNode *expr)
{
  SxmlNode *resultList;
  SxmlNode *resultNode;
  SxmlNode *queryNode;
  resultList=HfdBaseEvalExpr(base, expr);
  resultNode=SxmlElementCreate("result");
  queryNode=SxmlElementCreate("query");
  SxmlAppendChild(queryNode, expr);
  SxmlAppendChild(resultNode, queryNode);
  if (resultList)  SxmlAppendChild(resultNode, resultList);
  return resultNode;
}
