/*******************************************************************************
 * Copyright (c) 2005, 2009 Intel Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Andy Kaylor, Intel - Initial implementation
 *
 * $Id: MsgParser.cpp,v 1.25 2009/08/26 14:59:55 jwest Exp $
 *******************************************************************************/ 

#include "CmdExtractor.h"
#include "MsgParser.h"
#include "tptp/TPTPUtils.h"
#include "CXLog.h"

#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMNode.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/dom/DOMImplementationLS.hpp>
#include <xercesc/dom/DOMWriter.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/framework/Wrapper4InputSource.hpp>
#include <xercesc/framework/XMLFormatter.hpp>
#include <xercesc/framework/MemBufFormatTarget.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>

#include <stdio.h>

XERCES_CPP_NAMESPACE_USE

#include "tptp/ParserErrorHandler.h"

#define COMMAND_TAG	"Cmd"

int writeNodeToBuffer( DOMNode* node, char** buffer )
{
	DOMImplementation   *impl = DOMImplementationRegistry::getDOMImplementation(&chNull);
	DOMWriter           *writer = ((DOMImplementationLS*)impl)->createDOMWriter();
    MemBufFormatTarget  *target = new MemBufFormatTarget;
	int                  bufferLen;

	// Set the encoding to EBCDIC from UTF for z-series machines
	#ifdef MVS
		writer->setEncoding(XMLUni::fgIBM1047EncodingString);
	#endif

	writer->writeNode( target, *node );

	bufferLen = target->getLen() + 1;

	*buffer = (char*)tptp_malloc( bufferLen );
	if ( *buffer == NULL )
	{
		return -1;
	}

	strcpy( *buffer, (char *)target->getRawBuffer() );

	delete target;
	writer->release();

	return 0;
}

void initializeParser()
{

}

unsigned int parseMessage( cx_state_data* cx, const char *msg )
{
	try {

		int                  msgLen = strlen(msg);
		MemBufInputSource	*stringInputSrc = new MemBufInputSource((const XMLByte*)msg,
																	msgLen,
																	"parseMessage()",
																	false );

		// Set the encoding to EBCDIC from UTF for z-series machines
		#ifdef MVS
			stringInputSrc->setEncoding(XMLUni::fgIBM1047EncodingString);
		#endif

		Wrapper4InputSource	*inputSrc = new Wrapper4InputSource(stringInputSrc);

		DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(&chNull);
		DOMBuilder        *parser = ((DOMImplementationLS*)impl)->createDOMBuilder(DOMImplementationLS::MODE_SYNCHRONOUS, 0);

		TPTPParserErrorHandler* tptp_dom_err = new TPTPParserErrorHandler();
		parser->setErrorHandler(tptp_dom_err);

		XERCES_CPP_NAMESPACE::DOMDocument *doc = parser->parse( *inputSrc );

		DOMNode *node = doc->getDocumentElement();
		char *nodename = XMLString::transcode(node->getNodeName());
		if (strcmp(nodename, "Cmd") == 0) {
			cx->ac.processCommand( cx->ac.cmo, strlen(msg), msg);
		}
	    else {
			XMLCh* cmdTag = XMLString::transcode(COMMAND_TAG);
			DOMNodeList *nodelist = doc->getElementsByTagName(cmdTag);
			XMLString::release(&cmdTag);

			int nodelength = nodelist->getLength();
	
			for(int i=0; i<nodelength; i++) {
				char*    cmdstr=NULL;

				if ( 0 == writeNodeToBuffer( nodelist->item(i), &cmdstr ) ) {
					cx->ac.processCommand( cx->ac.cmo, strlen(cmdstr), cmdstr );
					tptp_free (cmdstr);
				}
				else {
					TPTP_LOG_ERROR_MSG1( cx, "Unable to allocate buffer for cmd: %s", msg );
				}
			}
		}

		XMLString::release(&nodename);
		delete inputSrc;
		delete tptp_dom_err;
		parser->release();

		return 0;
	} //end try
	
	catch (const DOMException& error)
	{
		if ( error.msg != 0 )
		{
			char *errmesg = XMLString::transcode(error.msg);
			TPTP_LOG_PARSE_MSG1("XML/DOM Exception: %s", errmesg);
			XMLString::release(&errmesg);
		}
		else
		{
			// Can't get the msg string so print the error code.
			TPTP_LOG_PARSE_MSG1("XML/DOM Exception: error code %d", error.code);

		}

		TPTP_LOG_PARSE_MSG1("XML/DOM Exception occurred while parsing Cmd in message \"%s\"", (msg?msg:"null"));
		return -1;
	}
	catch (const XMLException& error)
	{
		char *errmesg = XMLString::transcode(error.getMessage());
		TPTP_LOG_PARSE_MSG2("XML Exception: %s (at line %d)", errmesg, error.getSrcLine());
		XMLString::release(&errmesg);
		TPTP_LOG_PARSE_MSG1("XML Exception occurred while parsing Cmd in message \"%s\"", (msg?msg:"null"));
		return -1;
	}
	catch(...)
	{ 
		TPTP_LOG_PARSE_MSG1("Unexpected exception occurred while parsing Cmd in message \"%s\"", (msg?msg:"null"));
		return -1;
	}
}

