/***********************************************************************
*
*      Projet  : DilibPro
*      Module  : Sgml
*      Fichier : SgmlCopy.c
*      Auteur  : J. Ducloy
*      Origine : J. Ducloy + V. Warth
*
*      Derniere mise a jour Décembre 96
*
*      $Id: SgmlCopy.c,v 1.3 2005/06/22 13:24:25 parmentf Exp $
*
************************************************************************
*
* Copyright (c) 1994 CNRS/CRIN & INRIA Lorraine
* 
************************************************************************/

#include "SgmlNodePrivate.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>



/**************************************************************************

      SgmlCopy (noeud)
           duplication d'un sous-arbre Sgml


**************************************************************************/
SgmlNode *SgmlCopy (SgmlNode *InputNode)
{
  SgmlNode *OutputNode;
  SgmlNode *fils;
  SgmlNode *ListeAttributs;

  if (!InputNode)return(NULL);

  switch (SgmlType(InputNode))
    {
    case 'A' : 
      OutputNode = SgmlCreateAtt(
				 SgmlAttId(InputNode), 
				 SgmlAttVal(InputNode)
				 );
      break;
      
    case 'M' :
      OutputNode = SgmlCreateMark(SgmlTag(InputNode));
      
      if ((ListeAttributs = SgmlAttList(InputNode))) 
	{
	  SgmlAttList(OutputNode)=SgmlCopy(ListeAttributs);
	  SgmlFather(SgmlAttList(OutputNode))=OutputNode;
	};
      
      if ((fils=SgmlFirst(InputNode)))
	{
	  SgmlAddLast (OutputNode, (SgmlCopy(fils)));
	  while((fils=SgmlNext(fils)))
	    {
	      SgmlAddLast (OutputNode, (SgmlCopy(fils)));
	    };
	};
      break;
      
    case 'L':
      OutputNode = SgmlCreateAttList();
      if ((fils=SgmlFirst(InputNode)))
	{
	  SgmlAddLast (OutputNode, (SgmlCopy(fils)));
	  while((fils=SgmlNext(fils)))
	    {
	      SgmlAddLast (OutputNode, (SgmlCopy(fils)));
	    };
	};
      break;
      
    case 'D':
    case 'C':
      OutputNode = SgmlCreateData();
      SgmlPutData(OutputNode, SgmlDataString(InputNode));
      break;

    };

  if (SgmlNodeFormatToFree(InputNode))
    {
      SgmlNodeFormatToFree(OutputNode)=1;
      SgmlNodeFormat(OutputNode)=malloc(strlen(SgmlNodeFormat(InputNode)+1));
      strcpy (SgmlNodeFormat(OutputNode),SgmlNodeFormat(InputNode));
    }
  else SgmlNodeFormat(OutputNode)=SgmlNodeFormat(InputNode);

  OutputNode->subType=InputNode->subType;
  OutputNode->cusType=InputNode->cusType;
  OutputNode->cusSubType=InputNode->cusSubType;
  OutputNode->cus1=InputNode->cus1;
  /*
  OutputNode->cus2=InputNode->cus2;
  OutputNode->cus3=InputNode->cus3;
  */

  return ( OutputNode) ;
}

/***************************************************************************
***************************************************************************/

SgmlNode *SgmlCopyChildren(SgmlNode *n1, SgmlNode *n2)
{
  SgmlNode *n3;
  if ((n3=SgmlFirst(n2)))
    {
      do
	{
	  SgmlAddSon(n1, SgmlCopy(n3));
	}while((n3=SgmlNext(n3)));
    }
  return n1;
}


/****************************************************************************** 
 *                              SgmlCut
 *
 * - Fonction récursive qui isole un sous-arbre
 *
 * - Les paramètres :
 *		- noeud : pointeur sur la structure
 *	
 *

 ******************************************************************************/
SgmlNode   *SgmlCut(SgmlNode *Noeud)
{
      SgmlNode *pere;
      SgmlNode *FrereSuivant;
      SgmlNode *FrerePrecedant;

      
   if(!Noeud) return (NULL);

   pere = SgmlFather(Noeud);

   if(SgmlType(Noeud)=='L') 
        { if(pere) {SgmlAttList(pere)=NULL; SgmlFather(Noeud)=NULL;};
          return (Noeud);
        };

   FrereSuivant = SgmlNext(Noeud);
   FrerePrecedant = SgmlPrevious(Noeud);

      if (!pere) return (Noeud); /* en toute rigueur on devrait mieux traiter ce cas */
      else {
           SgmlFather(Noeud)=NULL; 
           SgmlNext(Noeud)=NULL;
           SgmlPrevious(Noeud)=NULL;
 
           if (!FrerePrecedant)  /* le noeud est le premier fils */
              {
               
               if (!FrereSuivant)  /* le noeud est fils unique  */
                  {
                   SgmlFirst(pere)=NULL;
                   SgmlLast(pere) =NULL;
                  }
               else           /* vrai premier fils  */
                  {
                  SgmlFirst(pere)= FrereSuivant;
                  SgmlPrevious(FrereSuivant)=NULL;
                  } /* else */
              } /* if FP  */
           else               /* le noeud a un grand-frere  */
              {
               if (!FrereSuivant) /* vrai dernier fils */
                  {
                   SgmlLast (pere)= FrerePrecedant;
                   SgmlNext(FrerePrecedant)=NULL;
                  }
               else             /*  vrai cadet  */
                  {
                   SgmlNext(FrerePrecedant)=FrereSuivant;
                   SgmlPrevious(FrereSuivant) = FrerePrecedant;
                  }
              } /* else FP */    
        
        } /* else !pere */
   return (Noeud);
}

/****************************************************************************** 
 *                              SgmlCutAndFree
 *
 * - Fonction qui isole un sous-arbre et libere l'espace
 *
 * - Les paramètres :
 *		- noeud : pointeur sur la structure
 *	
 *
 * - Module appelant : main()
 *

 ******************************************************************************/
void     SgmlCutAndFree(SgmlNode *noeud)
{
        SgmlCut(noeud);
        SgmlFree(noeud);
}


/****************************************************************************** 
 *                     SgmlInsertTagBeforeGreater
 * - Module appelant : main()
 *
 *  insere le noeud n2 aant le premier noeud strictement superieur
 *  a son Gid
 *
 ******************************************************************************/
SgmlNode  *SgmlInsertTagBeforeGreater(
          SgmlNode *n1,   /* point d'insertion */
          SgmlNode *n2)   /* noeud a inserer   */
{
          char *Gidn1;
          char *Gidn2;
          SgmlNode *Suivant;

          if(!n1)return (NULL);
          if(!n2)return (NULL);

          Gidn1 = SgmlTag (n1);         
          Gidn2 = SgmlTag (n2);

          if (strcmp(Gidn1,Gidn2) > 0) SgmlInsertBefore(n1,n2);
          else {Suivant = SgmlNext(n1);
                   if(!Suivant) SgmlInsertAfter(n1,n2);
                   else SgmlInsertTagBeforeGreater(Suivant, n2);
               }
          return (n2);

}

/****************************************************************************** 
 *                     SgmlAddSonTagBeforeGreater
 * - Module appelant : main()
 *
 *  insere le noeud n2 avant le premier noeud fils strictement superieur
 *  a son Gid
 *
 ******************************************************************************/
SgmlNode  *SgmlAddSonTagBeforeGreater(
          SgmlNode *n1,   /* point d'insertion */
          SgmlNode *n2)   /* noeud a inserer   */
{
          SgmlNode *Fils;

          if(!n1)return (NULL);
          if(!n2)return (NULL);
          Fils = SgmlFirst(n1);
          if (!Fils) SgmlAddLast(n1,n2);
          else SgmlInsertTagBeforeGreater(Fils,n2);

          return (n2);

}

/******************************************************************************
    predicats d'egalite

******************************************************************************/
/*******************************************************************
*        SgmlEqualAtt (n1,n2)
*
*        teste si deux attributs sont egaux
*******************************************************************/
int SgmlEqualAtt (SgmlNode *n1, SgmlNode *n2)
{
    if(!n1) {if(!n2)return (1); else return(0);}
    if(!n2) return(0);
    if (strcmp (SgmlAttId(n1),SgmlAttId(n2))==0)
       { if (strcmp (SgmlAttVal(n1), SgmlAttVal(n2))==0) return (1);
          else return(0);
       }
    else return(0);
}

/*******************************************************************
*        SgmlEqualSubListAtt (n1,n2)
*
*        teste si deux sous-listes d'attributs sont egales
*******************************************************************/
int SgmlEqualSubListAtt (SgmlNode *n1, SgmlNode *n2)
{
    if (n1) {if (SgmlEqualAtt(n1,n2))
                return (SgmlEqualSubListAtt(SgmlNext(n1), SgmlNext(n2)));
                else return(0);
            }
    if(!n2) return(1); else return(0);
}

/***********************************************************************
*   SgmlEqualMark(n1, n2);
*  teste si deux balises (+ attributs) sont identiques
*************************************************************************/

int SgmlEqualMark (SgmlNode *n1, SgmlNode *n2)
{
      SgmlNode *Latt1;
      SgmlNode *Latt2;

      if (strcmp(SgmlTag(n1),SgmlTag(n2))==0)
         {Latt1=SgmlAttList(n1);
          Latt2=SgmlAttList(n2);
          if(Latt1) 
            {if(Latt2)
               return(SgmlEqualSubListAtt(SgmlFirst(Latt1),SgmlFirst(Latt2)));
             else return(0);
            }
          if(Latt2)return(0); else return(1);
         }
     else return(0);
}

/***********************************************************************
*   SgmlEqualSubTree (n1, n2);
*  teste si deux sous-arbres sont identiques
*************************************************************************/

int SgmlEqualSubTree (SgmlNode *n1, SgmlNode *n2)
{
    int type;
    SgmlNode *Fils1;
    SgmlNode *Fils2;

    if (!n1) {if(!n2)return (1) ; else return(0);}
    type = SgmlType(n1);
    if(type != SgmlType(n2))return(0);

    switch (type)
      {
       case 'M' : if (SgmlEqualMark(n1,n2))
                    {Fils1= SgmlFirst(n1);Fils2= SgmlFirst(n2);
                     if(!Fils1){if(Fils2)return(0) ; else return(1);}
                     if (SgmlEqualSubTree(Fils1,Fils2))
                        return(SgmlEqualListSubTree(SgmlNext(Fils1),SgmlNext(Fils2)));
                      else return(0);
                    }
                  else return (0);
       case 'D' : if (strcmp(SgmlDataString(n1),SgmlDataString(n2))==0) return(1);
                  else return (0);
       case 'A' : return (SgmlEqualAtt(n1,n2));
      }
         
    return (0);
}

/***********************************************************************
*   SgmlEqualListSubTree (n1, n2);
*  teste si deux sous-listes sont identiques
*************************************************************************/
int SgmlEqualListSubTree (SgmlNode *n1, SgmlNode *n2)
{
    if(!n1) {if (!n2) return(1); else return(0);}
    if (!n2) return(0);
    if(SgmlEqualSubTree(n1,n2)) 
       return (SgmlEqualListSubTree(SgmlNext(n1),SgmlNext(n2)));
    return(0);
}

