/****************************************************************************
*
*      Projet  : DilibPro
*      Module  : Sxml
*      Fichier : SxmlDocument.c
*      Auteur  : J. Ducloy
*
*      Derniere mise a jour Decembre 2000
*
************************************************************************
* 
*     Copyrigth (C) 2001 CNRS INIST
*
****************************************************************************/
/**************************************************

  parties sensibles
  Les fonctions :
        SxmlDocumentCreateFromReader()
        SxmlDocumentUnparsedCreateFromReader()
  Contraintes :
        2 modes, parsing complet
                         sommaire (pour Xhfd)

 **************************************************/
#include "BufferParserXml.h"
#include "SxmlNode.h"
#include "Except.h"
#include <ctype.h>

#define SxmlDocumentReaderSetWaitingNewLine(x)   (x->nodeSpecific=1)
#define SxmlDocumentReaderResetWaitingNewLine(x) (x->nodeSpecific=0)
#define SxmlDocumentReaderWaitingNewLine(x)      (x->nodeSpecific)

/*  pour gérer <? ... ?><doc>... 
#define SxmlDocumentReaderSetWaitingDocument(x)   (x->nodeSpecific1=1)
#define SxmlDocumentReaderResetWaitingDocument(x) (x->nodeSpecific1=0)
#define SxmlDocumentReaderWaitingDocument(x)      (x->nodeSpecific1)
*/

SxmlNode *SxmlInputDocument=NULL;
SxmlNode *SxmlInputDocumentElement=NULL;

SxmlNode *SxmlDocumentCreate(str)
     char *str;
{
  SxmlNode *d1;
  char *strD;
  if(!(strD=strdup(str)))
    {
      ExceptSetError("SxmlNode","MA", "memory allocation failed","","",2);
    }
  d1=SxmlNodeCreate(XML_NODE_DOCUMENT);
  SxmlSetNodeName(d1,strD);
  SxmlSetNodeNameToFree(d1);
  return d1;
}

SxmlNode *SxmlDocumentCreateFromElement(e1)
     SxmlNode *e1;
{
  SxmlNode *d1;
  if((SxmlParsed(e1)))
    {
      if(SxmlIsElement(e1))
	d1=SxmlDocumentCreate(SxmlNodeName(e1));
      else d1=SxmlDocumentFragmentCreate();
    }
  else 
    {
      char *v1;
      v1=SxmlNodeValue(e1);
      if((v1[0]=='<')
	 &&(isalpha((int)v1[1])))
	d1=SxmlDocumentCreate("#document");
      else d1=SxmlDocumentFragmentCreate();
      SxmlSetUnparsed(d1);
    } 
  SxmlAppendChild(d1,e1);
  return d1;
}

SxmlNode *SxmlDocumentParse(d1)
     SxmlNode *d1;
{
  SxmlNode *elem;

  switch(SxmlNodeType(d1))
    {
    case XML_NODE_DOCUMENT:
      elem=SxmlFromString(SxmlNodeValue(SxmlFirstChild(d1)));
      SxmlFree(SxmlFirstChild(d1));
      SxmlAppendChild(d1,elem);
      SxmlReplaceName(d1,SxmlNodeName(elem));
      SxmlSetParsed(d1);
      break;
    case XML_NODE_DOCUMENT_FRAGMENT:
      SxmlReset(d1);
      while((elem=SxmlNextNode(d1)))
	{
	  SxmlInsertBefore(elem,SxmlFromString(SxmlNodeValue(elem)));
	  SxmlFree(elem);
	}
      break;
    default:
      ExceptSetError("SxmlDocument","NY","Not Yet Implemented","","",2);
      break; 
    }
  return d1;
}

void SxmlDocumentFilePrint(d1,f1)
     SxmlNode *d1;
     FILE *f1;
{
  SxmlNode *e1;
  SxmlReset(d1);
  while((e1=SxmlNextNode(d1)))SxmlFilePrint(e1,f1);
}

SxmlNode *SxmlDocumentFragmentCreate()
{
  SxmlNode *d1;
  d1=SxmlNodeCreate(XML_NODE_DOCUMENT_FRAGMENT);
  SxmlSetNodeName(d1,"#documentFragment");
  return d1;
}

void SxmlDocumentFragmentFilePrint(d1,f1)
     SxmlNode *d1;
     FILE *f1;
{
  SxmlNode *e1;
  SxmlReset(d1);
  while((e1=SxmlNextNode(d1)))SxmlFilePrint(e1,f1);
}

SxmlDocumentReader *SxmlDocumentReaderCreate()
{
  SxmlNode *r1;
  BufferParser *b1; 
  r1=SxmlContainerCreate(XML_CONTAINER_BUFFER_PARSER);
  b1=BufferParserCreate();
  SxmlSetNodeName(r1,"#documentReader");
  SxmlSetNodeValue(r1,(char *)b1);
  SxmlSetNodeValueToFree(r1);
  return r1;
}

SxmlDocumentReader *SxmlDocumentReaderOpen(SxmlDocumentReader *x1, char *fn1)
                                                             /* file name */
{
  BufferParser *b1;
  b1=(BufferParser *)SxmlNodeValue(x1);
  SxmlDocumentReaderResetWaitingNewLine(x1);
  /*  SxmlDocumentReaderResetWaitingDocument(x1); */
  if(BufferParserOpen(b1,fn1))return x1;
  else return(NULL);
} 

void SxmlDocumentReaderClose(dr1)
     SxmlNode *dr1;
{
  BufferParserClose((BufferParser *)SxmlNodeValue(dr1));
}

void SxmlDocumentReaderFree(dr1)
     SxmlNode *dr1;
{
  SxmlDocumentReaderClose(dr1);
  SxmlFree(dr1);
}

SxmlNode *SxmlDocumentCreateFromReaderEndUnit(x1,doc1,previousUnit)
     SxmlNode *doc1;
     SxmlNode *previousUnit;
     SxmlNode *x1;
{
  if(!doc1)
    {
      if(!previousUnit)
	/* return NULL; */
	{
	  BufferParser *b1;
	  b1=(BufferParser *)SxmlNodeValue(x1);
	  if(!(BufferParserIsOpen(b1)))return NULL;
	  return SxmlTextCreate("");
	}
      doc1=SxmlDocumentCreateFromElement(previousUnit);
      return doc1;
    }
  if(!previousUnit)return doc1;
  SxmlAppendChild(doc1,previousUnit);
  SxmlSetNodeType(doc1,XML_NODE_DOCUMENT_FRAGMENT);
  return doc1;
}

SxmlNode *SxmlDocumentUnparsedCreateFromReader(x1)
     SxmlNode *x1;
{
  SxmlNode *doc1;
  SxmlNode *previousUnit;
  SxmlNode *xmlUnit;
  BufferParser *b1;
  char *strUnit;

  b1=(BufferParser *)SxmlNodeValue(x1);
  if(!(BufferParserIsOpen(b1)))return NULL;
  if (SxmlDocumentReaderWaitingNewLine(x1))
    {
      SxmlDocumentReaderResetWaitingNewLine(x1);
      return SxmlTextCreate("\n");
    }
  doc1=NULL;
  previousUnit=NULL;
  
  while((strUnit=BufferParserGetXmlUnit(b1)))
    {
      if(strcmp(strUnit,"\t")==0)
	{
	  return SxmlDocumentCreateFromReaderEndUnit(x1,doc1,previousUnit);
	}
      else if (strcmp(strUnit,"\n")==0)
	{
	  doc1=SxmlDocumentCreateFromReaderEndUnit(x1,doc1,previousUnit);
	  SxmlDocumentReaderSetWaitingNewLine(x1);
	  return doc1;
	}
      xmlUnit=SxmlTextCreate(strUnit);
      SxmlSetUnparsed(xmlUnit);
      if(doc1)
	{
	  SxmlAppendChild(doc1,xmlUnit);
	}
      else if (previousUnit)
	{
	  doc1=SxmlDocumentFragmentCreate();
	  SxmlSetUnparsed(doc1);
	  SxmlAppendChild(doc1,previousUnit);
	  SxmlAppendChild(doc1,xmlUnit);
		previousUnit=NULL;
	}
      else previousUnit=xmlUnit;
    }
  /*  end of file without \n */
  BufferParserClose(b1);
  doc1=SxmlDocumentCreateFromReaderEndUnit(x1,doc1,previousUnit);
  return doc1;
}

SxmlNode *SxmlDocumentCreateFromReader(x1)
     SxmlNode *x1;
{
  SxmlNode *doc1;

  doc1=SxmlDocumentUnparsedCreateFromReader(x1);
  if(!doc1)return NULL;
  if (SxmlIsText(doc1))return doc1;

  SxmlDocumentParse(doc1);
  return doc1;
}

SxmlNode *SxmlDocumentReaderSetFile(x1,f1)
     SxmlNode *x1;
     FILE *f1;
{
  BufferParser *b1;
  b1=(BufferParser *)SxmlNodeValue(x1);
  SxmlDocumentReaderResetWaitingNewLine(x1);
  BufferParserSetFile(b1,f1);
  return x1;
}

SxmlNode *SxmlInputNextDocumentElement()    /* deprecated */
{
  if(SxmlInputNextRecord())
    {
      return (SxmlFirstChild(SxmlLastChild(SxmlInputRecord)));
    }
  return NULL;
}

SxmlElement *SxmlInputGetDocumentElement()
{
  SxmlNode *doc;
  while ((doc=SxmlInputGetRecordLastItem()))
    {
      if (SxmlIsElement(doc)) return doc; 
    }
  return NULL;
}

SxmlNode *SxmlRecordReaderNextDocumentElement(SxmlRecordReader *reader)
{
  SxmlNode *xRecord;
  if ((xRecord=SxmlRecordReaderGets(reader)))
    {
      SxmlNode *lastChild;
      lastChild=(SxmlLastChild(xRecord));
      /* if (!lastChild)return NULL;       to be improved */
      return (SxmlFirstChild(lastChild));
    }
  return NULL;
}


SxmlNode *SxmlFromFile(f1)
     char *f1;
{
  SxmlNode *dr1;
  SxmlNode *doc1;
  SxmlNode *n1;

  dr1=SxmlDocumentReaderCreate();
  if(SxmlDocumentReaderOpen(dr1,f1))
    {
      doc1=SxmlDocumentCreateFromReader(dr1);
      SxmlDocumentReaderFree(dr1);
      if (SxmlIsText(doc1))return doc1;
      n1=SxmlRemoveChild(SxmlFirstChild(doc1));
      SxmlFree(doc1);
      return n1;
    }
  return NULL;
}

SxmlNode *SxmlInputNextElementWithName(name)
     char *name;
{
  SxmlNode *inputRecord;
  while ((inputRecord=SxmlInputNextRecord()))
    {
      SxmlNode *docOrFrag;
      SxmlReset(inputRecord);
      while ((docOrFrag=SxmlNextNode(inputRecord)))
	{
	  SxmlNode *elem;
	  switch(SxmlNodeType(docOrFrag))
	    {
	    case XML_NODE_ELEMENT:
	    case XML_NODE_DOCUMENT:
	    case XML_NODE_DOCUMENT_FRAGMENT:
	      if ((elem=SxmlGetFirstChildByTagName(docOrFrag,name)))
		{
		  if(SxmlNodeType(elem)==XML_NODE_ELEMENT) return elem;
		}
	    default:
	      break;
	    }
	}
    }
  return NULL;
}

