<?php
/**
 * dom_xmlrpc_domxml_document wraps a DOM-XML DOM document in the DOM XML-RPC API
 * @package   dom-xmlrpc
 * @copyright (C) 2004 John Heinstein. All rights reserved
 * @license   http://www.gnu.org/copyleft/lesser.html LGPL License
 * @author    John Heinstein <johnkarl@nbnet.nb.ca>
 * @link      http://www.engageinteractive.com/dom_xmlrpc/ DOM XML-RPC Home Page
 *            DOM XML-RPC is Free Software
 **/

if (!defined('DOM_XMLRPC_INCLUDE_PATH'))
{
	define('DOM_XMLRPC_INCLUDE_PATH', (dirname(__FILE__) . "/"));
}

require_once(DOM_XMLRPC_INCLUDE_PATH . 'dom_xmlrpc_constants.php');

/**
 * Wraps a DOM-XML DOM document in the DOM XML-RPC API
 *
 * @package dom-xmlrpc
 * @author  John Heinstein <johnkarl@nbnet.nb.ca>
 */
class dom_xmlrpc_domxml_document
{
	/** @var object A reference to the DOM-XML document */
	var $xmldoc = null;

	/**
	 * Instantiates a DOM-XML Document
	 *
	 * @param string The XML text to be parsed
	 *
	 * @return boolean True if parsing has been successful
	 */
	function parseXML($xmlText)
	{
		//remove whitespace
		$xmlText = eregi_replace('>' . "[[:space:]]+" . '<', '><', $xmlText);

		//parse document
		$this->xmldoc = domxml_open_mem($xmlText);

		if (is_object($this->xmldoc)) $success = true;
		else $success = false;

		return $success;
	} //parseXML

	/**
	 * Returns a reference to the DOM-XML Document
	 * @return object A reference to the DOM-XML Document
	 */
	function getDocument()
	{
		return $this->xmldoc;
	} //getDocument

	/**
	 * Gets the method type
	 * @return string The method type
	 */
	function getMethodType()
	{
		$root = $this->xmldoc->document_element();
		return $root->node_name();
	} //getMethodType

	/**
	 * Gets the method name
	 * @return string The method name
	 */
	function getMethodName()
	{
		if ($this->getMethodType() == DOM_XMLRPC_TYPE_METHODCALL)
		{
			$node = $this->xmldoc->document_element();
			$childNodes = $node->child_nodes();
			$node = $childNodes[0];
			$node = $node->first_child();
			return $node->node_value();
		}
		//else throw exception
	} //getMethodName

	/**
	 * Gets a reference to the method params node
	 * @return object A reference to the method params node
	 */
	function getParams()
	{
		switch ($this->getMethodType())
		{
			case DOM_XMLRPC_TYPE_METHODCALL:
				$node = $this->xmldoc->document_element();
				$childNodes = $node->child_nodes();
				return $childNodes[1];
				break;

			case DOM_XMLRPC_TYPE_METHODRESPONSE:
				if (!$this->isFault())
				{
					$node = $this->xmldoc->document_element();
					return $node->first_child();
				}
				break;
		}
		//else throw exception
	} //getParams

	/**
	 * Gets a reference to the specified param
	 *
	 * @param int The index of the requested param
	 *
	 * @return object A reference to the specified param
	 */
	function getParam($index)
	{
		switch ($this->getMethodType())
		{
			case DOM_XMLRPC_TYPE_METHODCALL:
				$node = $this->xmldoc->document_element();
				$childNodes = $node->child_nodes();
				$node = $childNodes[1];
				$childNodes = $node->child_nodes();
				return $childNodes[$index];
				break;

			case DOM_XMLRPC_TYPE_METHODRESPONSE:
				if (!$this->isFault())
				{
					$node = $this->xmldoc->document_element();
					$node = $node->first_child();
					$childNodes = $node->child_nodes();
					return $childNodes[$index];
				}
				break;
		}
		//else throw exception
	} //getParam

	/**
	 * Gets the number of existing params
	 * @return int The number of existing params
	 */
	function getParamCount()
	{
		switch ($this->getMethodType())
		{
			case DOM_XMLRPC_TYPE_METHODCALL:
				$node = $this->xmldoc->document_element();
				$childNodes = $node->child_nodes();
				$node = $childNodes[1];
				$childNodes = $node->child_nodes();
				return count($childNodes);
				break;

			case DOM_XMLRPC_TYPE_METHODRESPONSE:
				if (!$this->isFault())
				{
					$node = $this->xmldoc->document_element();
					$node = $node->first_child();
					$childNodes = $node->child_nodes();
					return count($childNodes);
				}
				break;
		}
		return -1; //maybe throw an exception?
	} //getParamCount

	/**
	 * Determines whether the method response is a fault
	 * @return boolean True if the method response is a fault
	 */
	function isFault()
	{
		$node = $this->xmldoc->document_element();
		$node = $node->first_child();

		return ($node->node_name() == DOM_XMLRPC_TYPE_FAULT);
	} //isFault

	/**
	 * Returns the fault code, if a fault has occurred
	 * @return int The fault code, if a fault has occurred
	 */
	function getFaultCode()
	{
		if ($this->isFault())
		{
			$node = $this->xmldoc->document_element();
			$node = $node->first_child();
			$node = $node->first_child();
			$faultStruct = $node->first_child();

			$childNodes = $faultStruct->child_nodes();
			$node = $childNodes[0];
			$childNodes = $node->child_nodes();
			$node = $childNodes[1];
			$node = $node->first_child();
			$node = $node->first_child();

			return ($node->node_value());
		}
	} //getFaultCode

	/**
	 * Returns the fault string, if a fault has occurred
	 * @return string The fault string, if a fault has occurred
	 */
	function getFaultString()
	{
		if ($this->isFault())
		{
			$node = $this->xmldoc->document_element();
			$node = $node->first_child();
			$node = $node->first_child();
			$faultStruct = $node->first_child();

			$childNodes = $faultStruct->child_nodes();
			$node = $childNodes[1];
			$childNodes = $node->child_nodes();
			$node = $childNodes[1];
			$node = $node->first_child();
			$node = $node->first_child();

			return ($node->nodeValue);
		}
	} //getFaultString

	/**
	 * Returns the type of the specified param
	 *
	 * @param object A reference to the param to be tested for type
	 *
	 * @return string The type of the param
	 */
	function getParamType($node)
	{
		switch ($node->node_name())
		{
			case DOM_XMLRPC_TYPE_PARAM:
				$node = $node->first_child();
				$node = $node->first_child();
				return $node->node_name();
				break;

			default:
				//throw exception
		}
	} //getParamType

	/**
	 * Returns an unformatted string representation of the document
	 * @return string An unformatted string representation of the document
	 */
	function toString()
	{
		if (func_num_args() > 0)
		{
			$node = func_get_arg(0);
		}
		else
		{
			$node = $this->xmldoc->document_element();
		}

		$str = '';
		$str = @$this->xmldoc->dump_node($node);

		if ($str == '')
		{
			$str = @$node->dump_node($node);
		}

		return $str;
	} //toString

	/**
	 * Returns a string representation of the document, formatted for readability
	 * @return string A string representation of the document, formatted for readability
	 */
	function toNormalizedString()
	{
		//this doesn't actually normalize the string
		//but is here as a precaution, better
		//that generating an error!
		if (func_num_args() > 0)
		{
			return $this->toString(func_get_arg(0));
		}
		return $this->toString();
	} //toNormalizedString

} //dom_xmlrpc_domit_document
