// @(#)root/xml:$Name:  $:$Id: TXMLEngine.cxx,v 1.9 2004/06/29 14:45:38 brun Exp $
// Author: Sergey Linev  10.05.2004

/*************************************************************************
 * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//________________________________________________________________________
//
//  The aim of TXMLEngine class is to provide interface to libxml2 library.
//  It defines only used in ROOT functions of libxml2
//  There is a problem to parse libxml2 include files through CINT, 
//  therefore several wrappers for libxml2 types are defined.
//  More information about libxml2 itself can be found in http://xmlsoft.org
//________________________________________________________________________


#include "TXMLEngine.h"

#include "Riostream.h"
#include "libxml/tree.h"

ClassImp(TXMLEngine);


#if (_MSC_VER == 1200) && (WINVER < 0x0500) 
extern "C" long _ftol( double ); //defined by VC6 C libs 
extern "C" long _ftol2( double dblSource ) { return _ftol( dblSource ); } 
#endif

//______________________________________________________________________________
TXMLEngine::TXMLEngine() 
{
   
}

//______________________________________________________________________________
TXMLEngine::~TXMLEngine() 
{
}

//______________________________________________________________________________
Bool_t TXMLEngine::HasAttr(xmlNodePointer node, const char* name) {

   if ((node==0) || (name==0)) return kFALSE;
   return xmlHasProp((xmlNodePtr) node, (const xmlChar*) name) != 0;
}

//______________________________________________________________________________
const char* TXMLEngine::GetAttr(xmlNodePointer node, const char* name) {
   if (node==0) return 0;
   xmlChar* prop = xmlGetProp((xmlNodePtr) node, (const xmlChar*) name);
   if (prop) {
      fStrBuf = (const char*) prop;
      xmlFree(prop);
      return fStrBuf.Data();
   }
   return 0;
}

//______________________________________________________________________________
Int_t TXMLEngine::GetIntAttr(xmlNodePointer node, const char* name) {
   if (node==0) return 0;
   
   Int_t res = 0;
   
   xmlChar* prop = xmlGetProp((xmlNodePtr) node, (const xmlChar*) name);
   if (prop) {
      sscanf((const char*) prop,"%d", &res);
      xmlFree(prop);
   }
   return res;
}

//______________________________________________________________________________
xmlAttrPointer TXMLEngine::NewAttr(xmlNodePointer node,
                                   xmlNsPointer ns,
                                   const char* name,
                                   const char* value) {
   if (ns==0)
      return (xmlAttrPointer) xmlNewProp((xmlNodePtr) node,
                                         (const xmlChar*) name,
                                         (const xmlChar*) value);
   else
      return (xmlAttrPointer) xmlNewNsProp((xmlNodePtr) node,
                                           (xmlNsPtr) ns,
                                           (const xmlChar*) name,
                                           (const xmlChar*) value);
}

//______________________________________________________________________________
xmlAttrPointer TXMLEngine::NewIntAttr(xmlNodePointer node,
                                      const char* name,
                                      Int_t value)
{
  char sbuf[30];
  sprintf(sbuf,"%d",value);
  return NewAttr(node, 0, name, sbuf);
}                                      

//______________________________________________________________________________
void TXMLEngine::FreeAttr(xmlNodePointer node, const char* name) 
{
   if ((node==0) || (name==0)) return;
   xmlAttrPtr attr = xmlHasProp((xmlNodePtr) node, (const xmlChar*) name);
   if (attr!=0) xmlRemoveProp(attr);
}


//______________________________________________________________________________
xmlNodePointer TXMLEngine::NewChild(xmlNodePointer parent,
                                    xmlNsPointer ns,
                                    const char* name,
                                    const char* content) {
   xmlNodePointer node = xmlNewNode((xmlNsPtr) ns, (const xmlChar*) name);
   if (parent!=0)
     xmlAddChild((xmlNodePtr) parent, (xmlNodePtr) node);
   if (content!=0)
     xmlNodeAddContent((xmlNodePtr) node, (const xmlChar*) content);
   return node;
}

//______________________________________________________________________________
xmlNsPointer TXMLEngine::NewNS(xmlNodePointer node,
                               const char* reference,
                               const char* name) {
   return (xmlNsPointer) xmlNewNs((xmlNodePtr) node, (const xmlChar*) reference, (const xmlChar*) name);
}

//______________________________________________________________________________
void TXMLEngine::AddChild(xmlNodePointer parent, xmlNodePointer child) {
   xmlAddChild((xmlNodePtr) parent, (xmlNodePtr) child);
}

//______________________________________________________________________________
void TXMLEngine::UnlinkNode(xmlNodePointer node) {
   if (node!=0)  
     xmlUnlinkNode((xmlNodePtr) node);
}

//______________________________________________________________________________
void TXMLEngine::FreeNode(xmlNodePointer node) {
   xmlFreeNode((xmlNodePtr) node);
}

//______________________________________________________________________________
void TXMLEngine::UnlinkFreeNode(xmlNodePointer node) 
{
   UnlinkNode(node); 
   FreeNode(node);
}

//______________________________________________________________________________
const char* TXMLEngine::GetNodeName(xmlNodePointer node) {
   if (node==0) return 0;
   return (const char*) ((xmlNodePtr) node)->name;
}

//______________________________________________________________________________
const char* TXMLEngine::GetNodeContent(xmlNodePointer node) {
   if (node==0) return 0;
   xmlChar* cont = xmlNodeGetContent((xmlNodePtr) node);
   if (cont) {
      fStrBuf = (const char*) cont;
      xmlFree(cont);
      return fStrBuf.Data();
   }
   return 0;
}

//______________________________________________________________________________
xmlNodePointer TXMLEngine::GetChild(xmlNodePointer node) {
   if (node==0) return 0;
   return ((xmlNodePtr) node)->xmlChildrenNode;
}

//______________________________________________________________________________
xmlNodePointer TXMLEngine::GetParent(xmlNodePointer node) {
   if (node==0) return 0;
   return ((xmlNodePtr) node)->parent;
}

//______________________________________________________________________________
xmlNodePointer TXMLEngine::GetNext(xmlNodePointer node) {
   if (node==0) return 0;
   return ((xmlNodePtr) node)->next;
}

//______________________________________________________________________________
Bool_t TXMLEngine::IsEmptyNode(xmlNodePointer node) 
{
// checks if provided node is empty
  if (node==0) return kTRUE;
  return xmlIsBlankNode((xmlNodePtr) node);
}

//______________________________________________________________________________
void TXMLEngine::CleanNode(xmlNodePointer node) {
   if (node==0) return;
   xmlNodePointer child = GetChild(node);
   while (child!=0) {
      xmlNodePointer next = GetNext(child);
      UnlinkNode(child);
      FreeNode(child);
      child = next;
   }
}

//______________________________________________________________________________
void TXMLEngine::ShiftToNext(xmlNodePointer &node, Bool_t skipempty) {
   if (node==0) return;
   node = ((xmlNodePtr) node)->next;

   if (skipempty) 
     SkipEmpty(node);
}

//______________________________________________________________________________
void TXMLEngine::SkipEmpty(xmlNodePointer &node) {
   while (node && IsEmptyNode(node))
     node = ((xmlNodePtr) node) ->next;
}

//______________________________________________________________________________
xmlDocPointer TXMLEngine::NewDoc(const char* version) {
   return xmlNewDoc((const xmlChar*)version);
}

//______________________________________________________________________________
void TXMLEngine::AssignDtd(xmlDocPointer doc, const char* dtdname, const char* rootname) {
   xmlCreateIntSubset((xmlDocPtr) doc,
                      (const xmlChar*) rootname,
                      (const xmlChar*) "-//CERN//ROOT//v 1.0//EN",
                      (const xmlChar*) dtdname);
}

//______________________________________________________________________________
void TXMLEngine::FreeDoc(xmlDocPointer doc) {
   xmlFreeDoc((xmlDocPtr) doc);
}

//______________________________________________________________________________
void TXMLEngine::SaveDoc(xmlDocPointer doc, const char* filename, Int_t layout) {
   xmlSaveFormatFile(filename, (xmlDocPtr) doc, layout);
}

//______________________________________________________________________________
void TXMLEngine::DocSetRootElement(xmlDocPointer doc, xmlNodePointer node) {
   xmlDocSetRootElement((xmlDocPtr) doc, (xmlNodePtr) node);
}

//______________________________________________________________________________
xmlNodePointer TXMLEngine::DocGetRootElement(xmlDocPointer doc) {
   return (xmlNodePointer) xmlDocGetRootElement((xmlDocPtr) doc);
}

//______________________________________________________________________________
xmlDocPointer TXMLEngine::ParseFile(const char* filename) {
   return (xmlDocPointer) xmlParseFile(filename);
}

//______________________________________________________________________________
Bool_t TXMLEngine::ValidateDocument(xmlDocPointer doc, Bool_t doout) {
	xmlValidCtxt cvp;
	cvp.userData = doout ? (void *) stderr : 0;
//	cvp.error    = doout ? (xmlValidityErrorFunc) fprintf : 0;
//	cvp.warning  = doout ? (xmlValidityWarningFunc) fprintf : 0;
// debug output excluded to solve problem for Solaris compilation
	cvp.error    = 0;
	cvp.warning  = 0;

    xmlDocPtr docptr = (xmlDocPtr) doc;

    int res = xmlValidateDocument(&cvp, docptr);

    if ((docptr->intSubset!=0) || (docptr->extSubset!=0)) {
       xmlDtdPtr i = docptr->intSubset;
       xmlDtdPtr e = docptr->extSubset;
       if (i==e) e = 0;
       if (e!=0) {
         xmlUnlinkNode((xmlNodePtr) docptr->extSubset);
         docptr->extSubset = 0;
         xmlFreeDtd(e);
       }
       if (i!=0) {
         xmlUnlinkNode((xmlNodePtr) docptr->intSubset);
         docptr->intSubset = 0;
         xmlFreeDtd(i);
       }
    }

    if (doout)
      if (res==1) cout << "Validation done" << endl;
             else cout << "Validation failed" << endl;

    return (res == 1);
}


