/*
 * Copyright 1999 AT&T Labs -- Research
 * By receiving and using the code that follows, the user acknowledges
 * and agrees to keep the code confidential and use the code solely for
 * non-commercial research. The user further acknowledges and agrees that
 * the  code is not an official product of AT&T Corp., and is provided
 * on an "as is"  basis with no warranty, either express or implied, including
 * but not limited to implied warranties of merchantability and fitness
 * for a particular purpose, and any warranties of noninfringement.
 * The user shall use reasonable efforts to provide AT&T Laboratories
 * with reports of any errors, defects or suggestions for change and
 * improvements to the code.
 */

// this file implements output to MSXML

#include "stdafx.h"

#ifdef WIN32
#ifdef HAVE_MSXML

MSXMLOutput::MSXMLOutput()
{
	Init(XMLINDENT_NONE);
}

MSXMLOutput::~MSXMLOutput()
{
}

char MSXMLOutput::myCreateFile(char *fname)
{
	HRESULT hr;

	filename = fname;

	hr = documentPtr.CreateInstance("msxml2.domDocument.4.0", NULL, CLSCTX_INPROC);
	curelemnum = 0;
	curelems = new bla[MAXELEMS];
	curelems[curelemnum].node = documentPtr;//->GetdocumentElement();
	for (int i=1; i<MAXELEMS; i++) {
		curelems[i].node = NULL;
	}

	return SUCCEEDED(hr);
}

void MSXMLOutput::CloseFile()
{
	HRESULT hr;

	_variant_t varString = _bstr_t(filename);
	if(!SUCCEEDED(hr = documentPtr->save(varString))) {
		/* error! */
		int j=0;
	}

	for (int i=1; i<=curelemnum; i++) {
		curelems[i].node = NULL;
	}
	trydel (curelems);
}

void MSXMLOutput::Init(unsigned char myindentation,unsigned char myvaluespacing,unsigned char mycoldelta)
{
   x.status = XMLOUTPUT_INIT;
   x.isinattrib = FALSE;

   //x.valuespacing=myvaluespacing;
   //curcol=0;
   //coldelta=mycoldelta;
   //x.indentation=myindentation;
}

#if 0
void MSXMLOutput::GotoNextLine(char moveright)
{
   switch(x.indentation)
   {
   case XMLINDENT_SPACES:
   case XMLINDENT_TABS:
   {
      //theoutput->StoreNewline();

		if(moveright==0) {
         curcol-=coldelta;
		}
		if(x.indentation==XMLINDENT_SPACES) {
         //mymemset(theoutput->GetDataPtr(curcol),' ',curcol);
		} else {
         //mymemset(theoutput->GetDataPtr(curcol),'\t',curcol);
		}
		if(moveright) {
         curcol+=coldelta;
		}
      break;
   }
/*
   case XMLINDENT_WRAP:
      if(GetColPos()>=coldelta)
         StoreNewline();
*/
   }
}
#endif

void MSXMLOutput::startElement(char *str,int len)
{
	MSXML2::IXMLDOMNodePtr newelem = NULL;
	BSTR strB = NULL;
	HRESULT hr;
	int bstrlen = 0;

	if (curelemnum == MAXELEMS) {
		throw new XMillException(XMILL_ERR_PARSE, "tree too deep!");
	}
   switch(x.status)
   {
		case XMLOUTPUT_OPENLABEL:
			if (curelems[++curelemnum].node == NULL) {
				throw new XMillException(XMILL_ERR_PARSE, "no down MXSML node!");
			}
			break;

		case XMLOUTPUT_OPENATTRIB:
			throw new XMillException(XMILL_ERR_PARSE, "Cannot start element within attribute!");

		case XMLOUTPUT_AFTERENDLABEL:
		case XMLOUTPUT_AFTERDATA:
			//GotoNextLine(1);
			break;

		case XMLOUTPUT_INIT:
			//curcol+=coldelta;
			break;
   }

	//theoutput->StoreChar('<');
   //theoutput->StoreData(str,len);

	/* create new node */
   bstrlen = MultiByteToWideChar(CP_ACP, 0, str, len, strB, 0);
	strB = new wchar_t[bstrlen+1];
   MultiByteToWideChar(CP_ACP, 0, str, len, strB, bstrlen);
	strB[bstrlen] = '\0';
	if ((newelem = documentPtr->createElement(strB)) == NULL) {
		//error handling
	}

	/* insert new node into parent node */
	if (!SUCCEEDED(hr = curelems[curelemnum].node->appendChild(newelem))) {
		//error handling
	}
	curelems[curelemnum+1].node = newelem;

	/* next state */
   x.status=XMLOUTPUT_OPENLABEL;

   //x.attribwhitespace=0;
}

void MSXMLOutput::endElement(char *str,int len)
{
   char *ptr = NULL;

   switch(x.status) {
		case XMLOUTPUT_OPENLABEL:
			/*
			ptr=theoutput->GetDataPtr(len+4);
			*(ptr++)='>';
			*(ptr++)='<';
			*(ptr++)='/';
			mymemcpy(ptr,str,len);
			ptr+=len;
			*(ptr++)='>';
			curcol-=coldelta;*/
			x.status=XMLOUTPUT_AFTERENDLABEL;
			return;

		case XMLOUTPUT_AFTERENDLABEL:
			//GotoNextLine(0);
			break;

		case XMLOUTPUT_AFTERDATA:
			//curcol-=coldelta;
			break;

		default:
			throw new XMillException (XMILL_ERR_PARSE, "Invalid end tag");
   }

   /*ptr=theoutput->GetDataPtr(len+3);
   *(ptr++)='<';
   *(ptr++)='/';
   mymemcpy(ptr,str,len);
   ptr+=len;
   *(ptr++)='>';*/
   
   x.status=XMLOUTPUT_AFTERENDLABEL;
}

void MSXMLOutput::endEmptyElement()
{
   //char *ptr;
   if(x.status!=XMLOUTPUT_OPENLABEL)
      // Something is wrong !!
      return;

	/*ptr=theoutput->GetDataPtr(2);
   *(ptr++)='/';
   *(ptr++)='>';*/

   x.status=XMLOUTPUT_AFTERENDLABEL;
   //curcol-=coldelta;
}

void MSXMLOutput::startAttribute(char *str,int len)
{
   register char *ptr;

   if(x.status==XMLOUTPUT_OPENATTRIB)
   {
      ptr=0;//theoutput->GetDataPtr(len+(x.attribwhitespace ? 3 : 4));
      *(ptr++)='"';
   }
   else
   {
      if(x.status!=XMLOUTPUT_OPENLABEL) {
         throw new XMillException(XMILL_ERR_CORRUPT, "Cannot print attribute outside of start element!");
      }
      ptr=0;//theoutput->GetDataPtr(len+(x.attribwhitespace ? 2 : 3));
   }
#if 0
   if(x.attribwhitespace==0)
   {
      *(ptr++)=' ';
      x.attribwhitespace=0;
   }
#endif

   mymemcpy(ptr,str,len);
   ptr+=len;
   *(ptr++)='=';
   *(ptr++)='"';

   x.status=XMLOUTPUT_OPENATTRIB;
}

void MSXMLOutput::endAttribute(char *str, int len)
{
   if(x.status!=XMLOUTPUT_OPENATTRIB)
   {
      throw new XMillException(XMILL_ERR_PARSE, "Could not finish attribute outside of start element!");
   }
//   theoutput->StoreChar('"');
   x.status=XMLOUTPUT_OPENLABEL;
}

/* todo: maintain current string, create text node when leaving this state (e.g. new element node, or end of document) */
void MSXMLOutput::characters(char *str,int len)
{
	MSXML2::IXMLDOMNodePtr newelem = NULL;
	BSTR strB = NULL;
	HRESULT hr;
	int bstrlen = 0;

	/* create new node */
   bstrlen = MultiByteToWideChar(CP_ACP, 0, str, len, strB, 0);
	strB = new wchar_t[bstrlen+1];
   MultiByteToWideChar(CP_ACP, 0, str, len, strB, bstrlen);
	strB[bstrlen] = '\0';
	_bstr_t text(strB);
	if ((newelem = documentPtr->createTextNode(text)) == NULL) {
		//error handling
	}

	/* insert new node into parent node */
	if (!SUCCEEDED(hr = curelems[curelemnum].node->appendChild(newelem))) {
		//error handling
	}

	switch(x.status) {
		case XMLOUTPUT_OPENATTRIB:
			//theoutput->StoreData(str,len);
			return;

		case XMLOUTPUT_OPENLABEL:
			//theoutput->StoreChar('>');

		case XMLOUTPUT_AFTERDATA:
		case XMLOUTPUT_AFTERENDLABEL:
		case XMLOUTPUT_INIT:
			//theoutput->StoreData(str,len);
			break;
   }
   x.status=XMLOUTPUT_AFTERDATA;
}

void MSXMLOutput::whitespaces(char *str,int len)
{
#if 0
   characters(str,len);
#endif
}

void MSXMLOutput::attribWhitespaces(char *str,int len)
{
#if 0
   char *ptr=0;//theoutput->GetDataPtr(len);
   mymemcpy(ptr,str,len);
   x.attribwhitespace=1;
#endif
}

#endif /* HAVE_MSXML */
#endif /* WIN32 */
