// XmlDocument.cpp: implementation of the CXmlDocument class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "XmlDocument.h"
#include "FileFind.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// CXmlDocument Construction/Destruction
//////////////////////////////////////////////////////////////////////

CXmlDocument::CXmlDocument()
{
  HRESULT  hr=m_XmlDoc.CoCreateInstance(CLSID_DOMDocument);//CLSID_DOMDocument
  if(hr!=S_OK)
  {
    m_XmlDoc=NULL;
    if(hr==REGDB_E_CLASSNOTREG)
      MYTRACE(_T("A specified class is not registered in the registration database."));
    else if(hr==CLASS_E_NOAGGREGATION)
      MYTRACE(_T("This class cannot be created as part of an aggregate. "));
  }
}

CXmlDocument::~CXmlDocument()
{
  m_XmlDoc.Release();
}

BOOL CXmlDocument::Load(const CString & path)
{
  if(m_XmlDoc==NULL)
    return FALSE;

  #ifdef DEBUG
  WIN32_FIND_DATA fd;
  if(INVALID_HANDLE_VALUE == FindFirstFile(path,&fd))
  {
    MYTRACE(MT::LEVEL_WARNING,L"Xml File not exist: [%s]",path);
    return FALSE;
  }
  #endif

  VARIANT_BOOL bSuccess=false;
  CComVariant filePath=path;
  
  if(FAILED(m_XmlDoc->load(filePath, &bSuccess)) || bSuccess==false)
  {
    MYTRACE(MT::LEVEL_ERROR,L"Load Xml Failed [%s]",filePath.bstrVal);
    return FALSE;
  }  
  m_FilePath=path;
  MYTRACE(L"Load Xml Okay [%s]",filePath.bstrVal);  
  return TRUE;
}

BOOL CXmlDocument::Save()
{
  return SaveAs(m_FilePath);
}

BOOL CXmlDocument::SaveAs(CString & path)
{
  if(m_XmlDoc==NULL)
    return FALSE;
  CComVariant filePath=path;

  if(S_OK == (m_XmlDoc->save(filePath)))
  {
    m_FilePath=path;
    return TRUE;
  }
  else
  {
    return FALSE;
  }
}

BOOL CXmlDocument::SelectNode(CString queryString,CXmlNode* node)
{
  if(m_XmlDoc==NULL)
    return FALSE;
  CComBSTR str(queryString);
  HRESULT hr=m_XmlDoc->selectSingleNode(str,&node->m_XmlNode);
  str.Empty();
  return S_OK == hr;
}

BOOL CXmlDocument::SelectNodes(CString queryString,CXmlNodeList* nodeList)
{
  if(m_XmlDoc==NULL)
    return FALSE;
  CComBSTR str(queryString);
  HRESULT hr=m_XmlDoc->selectNodes(str,&nodeList->m_XmlNodeList);
  str.Empty();
  return S_OK == hr;
}

BOOL CXmlDocument::CreateAttribute(CXmlNode *parentNode,CXmlNode * attrNode,CString attrName)
{
  if(m_XmlDoc==NULL)
    return FALSE;
  BOOL bResult;
  CComPtr<IXMLDOMNamedNodeMap>  xmlNamedNodeMap;
  CComPtr<IXMLDOMAttribute> xmlAttr;
  CComBSTR name=attrName;
  if(S_OK == (m_XmlDoc->createAttribute(name,&xmlAttr)))
  {
    if(FAILED(parentNode->m_XmlNode->get_attributes(&xmlNamedNodeMap)))
      bResult=FALSE;
    else
      bResult=(S_OK==(xmlNamedNodeMap->setNamedItem(xmlAttr,&attrNode->m_XmlNode)));
  }
  else
  {
    bResult=FALSE;
  }
  xmlNamedNodeMap.Release();
  xmlAttr.Release();
  name.Empty();
  return bResult;
}

BOOL CXmlDocument::CreateNode(CString nodeName,CXmlNode *node)
{
  if(m_XmlDoc==NULL)
    return FALSE;
  CComVariant type=NODE_ELEMENT;
  CComBSTR name=nodeName;
  CComBSTR uri="";
  HRESULT hr=m_XmlDoc->createNode(type,name,uri,&node->m_XmlNode);
  name.Empty();
  uri.Empty();
  return S_OK == hr;
}

//////////////////////////////////////////////////////////////////////
// CXmlNode Construction/Destruction
//////////////////////////////////////////////////////////////////////
CXmlNode::CXmlNode()
{
  m_XmlNode=NULL;
}

CXmlNode::CXmlNode(CComPtr<IXMLDOMNode> pXmlNode)
{
  m_XmlNode=pXmlNode;
}

CXmlNode::~CXmlNode()
{
  m_XmlNode.Release();
}

BOOL CXmlNode::SelectNode(CString queryString,CXmlNode* node)
{
  if(m_XmlNode==NULL)
    return FALSE;
  CComBSTR str(queryString);
  HRESULT hr=m_XmlNode->selectSingleNode(str,&node->m_XmlNode);
  str.Empty();
  return S_OK == hr;
}

BOOL CXmlNode::SelectNodes(CString queryString,CXmlNodeList* nodeList)
{
  if(m_XmlNode==NULL)
    return FALSE;
  CComBSTR str(queryString);
  HRESULT hr=m_XmlNode->selectNodes(str,&nodeList->m_XmlNodeList);
  str.Empty();
  return S_OK == hr;
}

CString CXmlNode::GetAttribute(CString attrName)
{
  if(m_XmlNode==NULL)
    return L"";
  BSTR value=L"";
  CComBSTR str(attrName);
  CComPtr<IXMLDOMNode> iNode;
  m_XmlNode->selectSingleNode(str,&iNode);
  if(iNode)
  {  
    iNode->get_text(&value);
  }
  iNode.Release();
  str.Empty();  
  return (CString)value;
}

void CXmlNode::SetAttribute(CString attrName,CString attrValue)
{
  if(m_XmlNode==NULL)
    return;
  CComBSTR str(attrName);
  CComPtr<IXMLDOMNode> iNode;
  m_XmlNode->selectSingleNode(str,&iNode);
  if(iNode)
    iNode->put_text((BSTR)(LPCTSTR)attrValue);
  iNode.Release();
  str.Empty();
}

CString CXmlNode::GetValue()
{
  if(m_XmlNode==NULL)
    return "";
  BSTR value;
  m_XmlNode->get_text(&value);
  return (CString)value;
}

void CXmlNode::SetValue(CString value)
{
  m_XmlNode->put_text((BSTR)(LPCTSTR)value);
}

CString CXmlNode::GetNodeValue(CString nodeName)
{
  CXmlNode node;
  if(SelectNode(nodeName,&node))
  {
    return node.GetValue();
  }
  return "";
}

void CXmlNode::SetNodeValue(CString nodeName,CString value)
{
  CXmlNode node;
  if(SelectNode(nodeName,&node))
  {
    node.SetValue(value);
  }
}

BOOL CXmlNode::AppendChild(CXmlNode * child)
{
  if(m_XmlNode==NULL)
    return FALSE;
  CComPtr<IXMLDOMNode> outNode;
  HRESULT hr=m_XmlNode->appendChild(child->m_XmlNode,&outNode);
  outNode.Release();
  return S_OK==hr;
}

//////////////////////////////////////////////////////////////////////
// CXmlNodeList Construction/Destruction
//////////////////////////////////////////////////////////////////////
CXmlNodeList::CXmlNodeList()
{
  m_XmlNodeList=NULL;
}

CXmlNodeList::CXmlNodeList(CComPtr<IXMLDOMNodeList> pXmlNodeList)
{
  m_XmlNodeList=pXmlNodeList;
}

CXmlNodeList::~CXmlNodeList()
{
  m_XmlNodeList.Release();
}

long CXmlNodeList::GetSize()
{
  if(m_XmlNodeList==NULL)
    return 0;
  long len=0;
  m_XmlNodeList->get_length(&len);
  return len;
}

BOOL CXmlNodeList::GetAt(long i,CXmlNode * node)
{
  if(m_XmlNodeList==NULL)
    return FALSE;
  return S_OK == (m_XmlNodeList->get_item(i,&node->m_XmlNode));
}