/*   -*- coding: utf-8 -*-  */

/****************************************************************************
*
*      Projet  : DilibPro
*      Module  : Sxml
*      Fichier : SxmlNodeKernel.c
*      Auteur  : J. Ducloy
*
*      Derniere mise a jour Decembre 2000
*      $Id: SxmlNodeKernel.c,v 1.4 2005/09/19 13:49:54 parmentf Exp $
*
************************************************************************
* 
*     Copyright (C) 2001 CNRS INIST
*
****************************************************************************/
#include "SxmlNode.h"
#include "SgmlNode.h"
#include "Except.h"

int       SxmlFirstCall=1;
int       SxmlNumberOfNodes;
int       SxmlNumberOfFreeNodes;
int       SxmlPurifyMode=0;
SxmlNode  *SxmlNodesFreeList;

void SxmlKernelInit()
{
  SxmlFirstCall=0;
  SxmlNumberOfNodes=0;
  SxmlNumberOfFreeNodes=0;
  SxmlNodesFreeList=NULL;
}

int SxmlSetTraceLevel(level1)
     int level1;
{
  if (level1 > 20)
    {
      SxmlPurifyMode=1;
      DilibSetTraceLevel(level1-20);
    }
  else
    {
      DilibSetTraceLevel(level1);
    }
  return level1;
}

int SxmlNodesFreeListLenght()
{
  int i;
  SxmlNode *n1;
  i=0;
  n1=SxmlNodesFreeList;
  while(n1)
    {
      i++;
      n1=SxmlNextSibling(n1);
    }
  return i;
}

SxmlNode	*SxmlNodeBasicCreate()
{
  SxmlNode	*node;

  if((node = (SxmlNode *) malloc( sizeof(SxmlNode))))
    {
      SxmlNumberOfNodes++;
    }
  else 
    {
	ExceptSetError("SxmlNode","MA", "memory allocation failed","","",2);
	node=NULL;
    }
  return (node);
}

void SxmlNodeBasicFree(n1)
     SxmlNode *n1;
{
  if ((DilibIsTestMode())
      && SxmlPurifyMode)
    {
      SxmlNumberOfFreeNodes++;
      free(n1);
    }
  else
    {
      SxmlNextSibling(n1)=SxmlNodesFreeList;
      SxmlNodesFreeList=n1;
    }
}

SxmlNode	*SxmlNodeCreate(char nType)
{
  SxmlNode	*node;

  if(SxmlFirstCall)SxmlKernelInit();

  if (SxmlNodesFreeList)
    {
      node=SxmlNodesFreeList;
      SxmlNodesFreeList=SxmlNextSibling(node);
    }
  else
    {
      node=SxmlNodeBasicCreate();
    }
  memset(node, '\0', sizeof(SxmlNode));
  SxmlSetNodeType(node,nType);
  SxmlSetDilibType(node,'X');
  return (node);
}

SxmlNode *SxmlRemoveChild(SxmlNode *ch1)
{
  SxmlNode *par1;  /* parent node */
  SxmlNode *pre1;  /* previous node */
  SxmlNode *nex1;  /* next node */


  if(!(par1=SxmlParent(ch1)))return ch1;
  if ((SxmlNodeType(ch1))==XML_NODE_LIST_ATTRIBUTES)
    {
      par1->attributes=NULL;
      return ch1;
    }
  pre1=SxmlPreviousSibling(ch1);
  nex1=SxmlNextSibling(ch1);
  if ( pre1 && nex1)
    {
      SxmlSetNextSibling(pre1,nex1);
      SxmlSetPreviousSibling(nex1,pre1);
    }
  else if (pre1)
    {
      SxmlSetNextSibling(pre1,NULL);
      SxmlSetLastChild(par1,pre1);
    }
  else if (nex1)
    {
      SxmlSetPreviousSibling(nex1,NULL);
      SxmlSetFirstChild(par1,nex1);
    }
  else
    {
      SxmlSetFirstChild(par1,NULL);
      SxmlSetLastChild(par1,NULL);
    }
  SxmlSetParent(ch1,NULL);
  SxmlSetNextSibling(ch1,NULL);
  SxmlSetPreviousSibling(ch1,NULL);
  
  return ch1;
}

void  SxmlFreeChildren( SxmlNode *node)
{
  if(node)
    {
      SxmlNode *c1;
      if((c1=SxmlFirstChild(node)))
	{
	  SxmlNode *c2;
	  do
	    {
	      c2=SxmlNextSibling(c1);
	      SxmlFreeContent(c1);
	      SxmlNodeBasicFree(c1);
	    }while ((c1=c2));
	  SxmlSetFirstChild(node,NULL);
	  SxmlSetLastChild(node,NULL);
	}
    }
}

void    SxmlFreeContent(node)
  SxmlNode	*node;
{
  SxmlNode *lAtt;
  if(SxmlNodeValueToFree(node))
    {
      if(SxmlNodeType(node)==XML_NODE_CONTAINER)
	SxmlContainerValueFree(node);
      else free(SxmlNodeValue(node));
      SxmlSetNodeValueFreed(node);
    }
  if(SxmlNodeNameToFree(node)) free(SxmlNodeName(node));
  if(SxmlFirstChild(node)) SxmlFreeChildren(node);
  if ((lAtt=SxmlGetListAttributes(node))) SxmlFree(lAtt);
}

void SxmlFree(node)
  SxmlNode	*node;
{
  if (!node)return;
  if(SxmlNodeType(node)==XML_NODE_DILIB)
    {
      SgmlFree(node);
      return;
    }
  SxmlRemoveChild(node);
  SxmlFreeContent(node);
  SxmlNodeBasicFree(node);
}

SxmlNode *SxmlReplaceName(SxmlNode *x1, char *n1)
{
  char *s1;
  if(SxmlNodeNameToFree(x1))
    free(SxmlNodeName(x1));
  SxmlSetNodeNameToFree(x1);
  if ((s1=strdup(n1)))
    SxmlSetNodeName(x1,s1);
  else ExceptSetError("SxmlNode","MA", "memory allocation failed","","",2);
  return x1;
}

SxmlNode *SxmlReplaceValue(SxmlNode *x1, char *n1)
{
  char *s1;
  if(SxmlNodeValueToFree(x1))
    free(SxmlNodeValue(x1));
  SxmlSetNodeValueToFree(x1);
  if ((s1=strdup(n1)))
    SxmlSetNodeValue(x1,s1);
  else ExceptSetError("SxmlNode","MA", "memory allocation failed","","",2);
  return x1;
}

int SxmlLength(x1)
     SxmlNode *x1;
{
  int l1;
  SxmlNode *x2;
  switch(SxmlNodeType(x1))
    {
    case XML_NODE_TEXT:
      l1=strlen(SxmlNodeValue(x1));
      break;
    default:
      l1=0;
      SxmlReset(x1);
      while((x2=SxmlNextNode(x1)))l1++;
      break;
    }
  return l1;
}

/*
int SxmlLenght(SxmlNode *x1)  deprecated 
{
  return SxmlLength(x1);
}
*/

int SxmlRank(SxmlNode *x1)
{
  SxmlNode *p1;
  int r;
  p1=SxmlPreviousSibling(x1);
  if (!p1)return 1;
  r=1;
  while(p1)
    {
      r++;
      p1=SxmlPreviousSibling(p1);
    }
  return r;
}

void SxmlInternalDump()
{
  
  printf("\n======================== XML Dump  ====================\n");
  if(SxmlPurifyMode)printf("   #nodes : %d (total) : %d (free)\n",SxmlNumberOfNodes, SxmlNumberOfFreeNodes );

else  printf("   #nodes : %d (total) : %d (free list)\n",SxmlNumberOfNodes,SxmlNodesFreeListLenght() );
  printf("-----------------------------------------------------\n");
}

SxmlNode *SxmlReplaceChild(x1,x2)
     SxmlNode *x1;
     SxmlNode *x2;
{
  SxmlNode *f1;
  SxmlNode *p1;
  SxmlNode *n1;
  if ((f1=SxmlParent(x2)))
    SxmlRemoveChild(x2);
  if ((f1=SxmlParent(x1)))
    {
      if ((p1=SxmlPreviousSibling(x1)))
        {
          SxmlRemoveChild(x1);
          SxmlInsertAfter(p1,x2);
          return x2;
        }
      if ((n1=SxmlNextSibling(x1)))
        {
          SxmlRemoveChild(x1);
          SxmlInsertBefore(n1,x2);
          return x2;
        }
      SxmlRemoveChild(x1);
      SxmlAppendChild(f1,x2);
      return x2;
    }
  return x2;
}

