/***********************************************************************
*
*      Projet  : DilibSxml
*      Module  : SxmlNode
*      Fichier : SxmlSearch.c
*      Auteur  : J. Ducloy
*
*      Derniere mise a jour Decembre 2001
*      $Id: SxmlSearch.c,v 1.6 2003/08/01 14:57:06 parmentf Exp $
*
************************************************************************
* 
*     Copyright (C) 2001 CNRS INIST
*
************************************************************************/
/**
   @file

   @brief Functions for SxmlSearchTable handling
   
   @author &copy; INIST-CNRS
   @author Jacques DUCLOY <DilibMaster@inist.fr>
 */

#include "Except.h"
#include "SxmlNode.h"
#include "StrDict.h"
#include "StrSearch.h"
#include <stdlib.h>

/**
   Set the table part of the @a xt1 SxmlSearchTable to @a t1 (which is
   a StrSearchTable).

   Initialize @a xt1's structure:
   - set @a xt1 value to @a t1
   - set the @c #iter child of @a xt1 to 0
   - set the @c #key child of @a xt1 to NULL
   - set the @c #value child of @a xt1 to NULL

   @param xt1
   @param t1
   @return the modified @a xt1
 */
SxmlSearchTable *SxmlSearchTableSetTable(SxmlSearchTable *xt1,
				       StrSearchTable *t1)
{
  SxmlNode *iter;
  SxmlNode *key;
  SxmlNode *v1;
  SxmlSetNodeValue(xt1,(char *)t1);
  iter=SxmlContainerIntegerCreate(0);
  SxmlAppendChild(xt1,iter);
  SxmlSetNodeName(iter,"#iter");
  key=SxmlContainerStringCreate(NULL);
  SxmlAppendChild(xt1,key);
  SxmlSetNodeName(key,"#key");
  v1=SxmlNodePointerCreate(NULL);
  SxmlAppendChild(xt1,v1);
  SxmlSetNodeName(v1,"#value");
  return xt1;
}

/**
   Creates a table container which will be managed according to @a
   type1.  @a type1 has the following profile: @c
   [op][s][cop][sx][cop]

   Memory allocation mode can have following value: 

   -    c : element is owner (will be freed), duplication (clone) will be done 
   -    o : element is the owner
   -    p : element is only a pointer 

   When an element is cloned, you don't need to care about its freeing.

   Warning: @n
   If you use @c o (owner) memory allocation mode, don't pass
   constant as key (for character #2, or value for character #4), or
   don't free it: it will be freed!  If you use @c p (pointer) memory
   allocation mode, you still have to free the values!

   Remember: @n
   In all cases, you must free an SxmlSearchTable using
   @ref SxmlContainerValueFree.


   @param type1 type of the table. It contains 5 characters.
   <ol>
   <li> @c [op]  the StrSearchTable is <strong>o</strong>wned or <strong>p</strong>ointed</li>
   <li> @c [s]   key values are <strong>s</strong>trings</li>
   <li> @c [cop] key values are <strong>c</strong>loned, <strong>o</strong>wned or <strong>p</strong>ointed</li>
   <li> @c [sx]  values are <strong>s</strong>trings or <strong>X</strong>mlNodes</li>
   <li> @c [cop] values are <strong>c</strong>loned, <strong>o</strong>wned or <strong>p</strong>ointed</li>
   </ol>

   @return the created SxmlSearchTable.
   @see SxmlContainerValueFree
 */
/*
         type  [op][sx][cop][sx][cop]         
               NULL or empty  pspxp    
         byte 0 : table mode
              1 : key type
              2 : key mode
              3 : value type
              4 : value mode

         byte 1 3 : element type
              s : string
              x : SxmlNode

         byte 0 2 4 : management mode
              c : element is owner in clone mode
              o : container/element is owner (store mode)
              p : container is a pointer

 */
SxmlDict *SxmlDictCreate(char *type1)
{
  SxmlDict *table1;
  char *typeTable;
  if (!type1)typeTable="pspxp";
  else if (type1[0])typeTable=type1;
  else typeTable="pspxp";
  switch (type1[3])
    {
    case 's':
      table1=SxmlContainerCreate(SXML_CONTAINER_STR_DICT);
      break;
    case 'x':
      table1=SxmlContainerCreate(XML_CONTAINER_XML_SEARCH_TABLE);
      break;
    default:
      ExceptSetError("SxmlSearch","SY", "code value not fit in: ",type1,"",2);
    }
  SxmlSetAttribute(table1,"#type",typeTable);
  if (typeTable[0]=='o')
    {
      StrSearchTable *tab1;
      tab1=StrSearchTableCreate(10,10);
      SxmlSearchTableSetTable(table1,tab1);
      SxmlSetNodeValueToFree(table1);
    }
  return table1;
}

SxmlDict *NewSxmlStrDict()
{
  SxmlDict *table;
  table=SxmlDictCreate("ospsp");
  return table;
}

/* Adds into the SxmlSearchTable t1, the pair k1-i1, where k1 is the
   key, and i1 the value. 
   If the key already exists in t1, its associated value is replaced,
   else a new element is created, which key is k1 and value is i1.

   Returns i1.

   Takes into account the memory management mode given at t1 creation.
   
   If the key mode is 'c', the key is cloned before being added in the
   table (if it already existed, nothing changes).
   If the key mode is 'o', the key is now owned by the table, that is
   to say that it will be freed by the table (possibly at SxmlFree).
   If the key mode is 'p', the key is only pointed by the table, and
   never freed by it (even during a SxmlFree(t1)): you must free it,
   when it is no more used.

   If the value mode is 'c', the value is cloned, and it will be
   managed by the table.
   If the value mode is 'o', the value is owned by the table, that is
   to say that it will be freed by the table (possibly at SxmlFree);
   you must not free i1!
   If the value mode is 'p', the value is only pointed by the table,
   and never freed by it (even during a SxmlFree(t1)): you must free
   i1, when it is no more used.
*/
SxmlDict *SxmlDictSet(SxmlDict *t1,
				  char           *k1,
				  char           *i1)
{
  char *type;
  char *ik;
  char *i2;
  char *existVal;

  type=SxmlGetAttribute(t1,"#type");
  existVal=StrSearch((StrSearchTable *)SxmlNodeValue(t1),k1);
  switch(type[2])
    {
    case 'c':
      if(existVal)ik=StrSearchLastKey;
      else
	{
	  ik=strdup(k1);
	  if(!ik)ExceptSetError("SxmlSearch","MA","Memory allocation failed","","",2);
	}
      break;
    case 'o':
     if(existVal)
       {
	 free(k1);
	 ik=StrSearchLastKey;
       }
     else ik=k1;
     break;
    case 'p':
      ik=k1;
      break;
    }

  switch(type[4])
    {
    case 'c':
      if(existVal)
	{
	  if (type[3]=='s')free(existVal);
	  else SxmlFree((SxmlNode *)existVal);
	}
      if (type[3]=='x')i2=(char *)SxmlClone((SxmlNode *)i1);
      else 
	{
	  if(!(i2=strdup(i1)))
	    ExceptSetError("SxmlSearch","MA","Memory allocation failed","","",2);
	}
      if(existVal)StrSearchPut((StrSearchTable *)SxmlNodeValue(t1), ik,i2);
      else       StrSearchAdd((StrSearchTable *)SxmlNodeValue(t1), ik,i2);
      break;
    case 'o':
    if(existVal)
	{
	  if (type[3]=='s')free(existVal);
	  else SxmlFree((SxmlNode *)existVal);
	  StrSearchPut((StrSearchTable *)SxmlNodeValue(t1), ik,i1);
	}
      else StrSearchAdd((StrSearchTable *)SxmlNodeValue(t1), ik,i1);
      break;
    case 'p':
      if(existVal)StrSearchPut((StrSearchTable *)SxmlNodeValue(t1), ik,i1);
      else StrSearchAdd((StrSearchTable *)SxmlNodeValue(t1), ik,i1);
      break;
    }
  /*
  if(existVal)
    {
      switch(type[2])
	{
	case 's':
	case 'x':
	  i2=i1;
	  break;
	case 'S':
	  free(existVal);
	  if(!(i2=strdup(i1)))
	    ExceptSetError("SxmlSearch","MA","Memory allocation failed","","",2);
	  break;
	case 'X':
	  SxmlFree((SxmlNode *)existVal);
	  i2=(char *)SxmlClone((SxmlNode *)i1);
	  break;
	}
      StrSearchPut((StrSearchTable *)SxmlNodeValue(t1), ik,i2);
    }
  else
    {
      switch(type[2])
	{
	case 's':
	case 'x':
	  i2=i1;
	  break;
	case 'S':
	  if(!(i2=strdup(i1)))
	    ExceptSetError("SxmlSearch","MA","Memory allocation failed","","",2);
	case 'X':
	  i2=(char *)SxmlClone((SxmlNode *)i1);
	  break;
	}
      StrSearchAdd((StrSearchTable *)SxmlNodeValue(t1), ik,i2);
    }
  */
  return (SxmlNode *)i1;
}

SxmlNode *SxmlSearchTableGetKeyedItem(SxmlSearchTable *t1,
				    char           *k1)
{
  return (SxmlNode *)StrSearch((StrSearchTable *)SxmlNodeValue(t1),k1);
}

char *SxmlDictSearch(SxmlDict *d1, char *k1)
{
  return StrDictSearch( (StrDict *)SxmlNodeValue(d1),k1);
}
/* returns the next key of the table, and makes the corresponding
   element the current one. */
char *SxmlSearchTableNextKey(SxmlSearchTable *t1)
{
  int indic;
  StrSearchTable *t2;
  char *k1;
  SxmlNode *v1;

  t2=(StrSearchTable *)SxmlNodeValue(t1);
  indic=SxmlNodeIntegerValue(SxmlFirstChild(t1));
  if(indic==StrSearchOutOfRange)return NULL;
  indic=StrSearchIndicNext(t2,indic);
  if(indic==StrSearchOutOfRange)return NULL;
  SxmlSetNodeIntegerValue(SxmlFirstChild(t1),indic);
  SxmlSetNodeValue
    (SxmlNextSibling(SxmlFirstChild(t1)),k1=StrSearchIndicKey(t2,indic));
  v1=(SxmlNode *)StrSearchIndicValue(t2,indic);
  SxmlSetNodeValue(SxmlLastChild(t1),(char *)v1);
  return k1;
}

char *SxmlSearchTableReset(SxmlSearchTable *t1)
{
  int indic;
  int indic2;
  StrSearchTable *t2;
  char *k1;
  SxmlNode *v1;
  t2=(StrSearchTable *)SxmlNodeValue(t1);
  indic=StrSearchIndicReset(t2);
  indic2=StrSearchIndicNext(t2,indic);
  SxmlSetNodeIntegerValue(SxmlFirstChild(t1),indic);
  SxmlSetNodeValue
    (SxmlNextSibling(SxmlFirstChild(t1)),k1=StrSearchIndicKey(t2,indic2));
  v1=(SxmlNode *)StrSearchIndicValue(t2,indic2);
  SxmlSetNodeValue(SxmlLastChild(t1),(char *)v1);
  return k1;
}

void SxmlSearchTableDump(SxmlSearchTable *t1)
{
  char *k1;
  printf ("----- table\n");
  SxmlSearchTableReset(t1);
  while((k1=SxmlSearchTableNextKey(t1)))
    {
      printf(" %s:",k1);
      SxmlDump(SxmlSearchTableValue(t1));
    }
  printf ("----- end table\n");
}

SxmlSearchTable *SxmlSearchTableAddStream(SxmlSearchTable *t1,
					char           *s1)
{
  StrSearchAddTable((StrSearchTable *)SxmlNodeValue(t1),s1);
  return t1;
}

SxmlSearchTable *SxmlSearchTableAddFromProcNode(SxmlSearchTable *t1,
					      SxmlNode        *x1)
     /*
       analyses SxmlNode containing key, value, file, env for adding
                new values in a given table t1
      */
{
  char *key;
  char *fileName;
  if ((key=SxmlGetAttribute(x1,"key")))
    {
      char *value;
      if ((value=SxmlGetAttribute(x1,"value")))
	SxmlSearchTableSetKeyItem(t1,key,value);
      else SxmlSearchTableSetKeyItem(t1,key,"");
    }
  if ((fileName=SxmlGetAttribute(x1,"file")))
    {
      char *envAtt;
      if((envAtt=SxmlGetAttribute(x1,"env")))
	{
	  char *envVal;
	  Buffer *bufFile;
	  envVal=getenv(envAtt);
	  bufFile=BufferFromString(envVal);
	  BufferStrcat(bufFile,"/");
	  BufferStrcat(bufFile,fileName);
	  SxmlSearchTableAddStream(t1,BufferString(bufFile));
	  BufferFree(bufFile);
	}
      else SxmlSearchTableAddStream(t1,fileName);
    }
  return t1;
}

SxmlSearchTable *SxmlSearchTableToFile(SxmlSearchTable *t1,
				     char *s1)
{
  StrSearchTableToFile((StrSearchTable *)SxmlNodeValue(t1),s1);
  return t1;
}
