/*
 * <copyright>
 *  Copyright (c) Hyperwave GmbH 2010
 * </copyright>
 *
 * <file>
 *  Name:       AbstractXMLWrapper.js
 *  Created:    Apr 27, 2007
 *  $Id: $
 * </file>
 */

//----------------------------------------------------------------------
/**
 * Abstract class specifying an interface for modifying an XML file.
 * <p><b>
 * Note: Whenever changing the interface of this class be sure to also adapt
 * class <code>com.hyperwave.wcm.csjs.decorators.WrapperAbstractDecorator</code>
 * since decorators for XMLWrappers exist!
 * </b></p>
 * @see com.hyperwave.wcm.csjs.decorators.WrapperAbstractDecorator
 */
// <JSClass Name="com.hyperwave.xml.AbstractXMLWrapper">
defineClass ( "com.hyperwave.xml.AbstractXMLWrapper",
              function ( class$ )
{
  /**
   * Creates an instance of an XMLWrapper. Do not directly instantiate,
   * this is an abstract class only specifying the interface.
   *
   * @param theParam: string: the URI specifying the XML file to process
   */
  class$.constructor = function( theParam )
  {
    if ( theParam == "__proto__")
      return;

    this.xmlUrl_ = theParam;
    this.xmlDoc_ = null;
    
    this.errorXmlUrl_ = null;
    this.errorXslUrl_ = null;
  }

  /**
   * Specifies the doctype the browsers need to recognize and allow XHTML entities
   * within XML files (e.g. &amp;nbsp;).
   */
  class$.static_.XHTML_DOCTYPE = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';

  /**
   * Specifies the ID of the wrapper elment the template designer has to use to embed the
   * transformed content and for "scoping" CSS.
   */
  class$.static_.WRAPPER_ID = "wrapper";

  /**
   * Specifies the constant of node type element (defined by DOM for Node.nodeType property)
   */
  class$.static_.ELEMENT_NODE_TYPE = 1;

  /**
   * XSL template cache
   */
  class$.static_.xslCache_ = {};
  
  class$.setErrorXmlUrl = function(url) {
    this.errorXmlUrl_ = url;
  }
  
  class$.setErrorXslUrl = function(url) {
    this.errorXslUrl_ = url;
  }

  /**
   * Replaces the content of the node supplied via its XPath. Default implementations
   * can simply return true after the update took place. More intelligent
   * implementations may differ whether the value actually changed or not and only
   * update in case a modification was actually made.
   *
   * @param anXPath: string: the XPath of the node to replace
   * @param theValue: string: the XML content of the modified node as string
   * @return boolean: true if the node was actually updated.
   */
  class$.updateNode = function( theXPath, theValue ){
    throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract method updateNOde!";
  }

  /**
   * Transforms the attached XML file using the specified XSLT template and
   * returns the result as <code>com.hyperwave.xml.AbstractXMLWrapper</code> object.
   *
   * @param xslURI: string: the URI specifying the XSLT template used to transform.
   * @return com.hyperwave.xml.AbstractXMLWrapper: the result of the XML transformation
   *   wrappped in an XML wrapper.
   */
  class$.transform = function( xslURI ){
    throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract method transform!";
  }

  /**
   * Transforms the attached XML file using the specified XSLT template and
   * returns the result as string. Actually the result is not the whole HTML
   * page but only the contents of the "wrapper" element. This behaviour is
   * part of the Interface for template designers.
   *
   * @param xslURI: string: the URI specifying the XSLT template used to transform.
   * @return string: the string representation of the transformed XML file (content
   *   of the "wrapper" element).
   */
  class$.transformToString = function( xslURI ){
    throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract method transformToString!";
  }

  /**
   * Returns the XML of the associated file as string.
   * @return string: the string representation of the associated XML file.
   */
  class$.getXML = function( ){
    throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract method getXML!";
  }

  /**
   * Browser specific handling of XSL templates including caching.
   */
  class$.static_._getXSL = function( xslURI ){
    throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract private method _getXSL!";
  }

  /**
   * Kind of a placeholder function to provide a handle for saving the modified
   * XML back to the server. Concrete Implementations may override this method in
   * case they know themselves how to store the XML back to the server (database).
   * <p>
   * The WCM application uses the decorator pattern instead to implement the
   * saving logic independently from the browser-specific wrapper classes.
   *
   * @param theCallback: function: the callback which is called after committing is
   *   finished to support asynchronously saving to the server.
   */
  class$.commit = function( theCallback ) {
    if(typeof theCallback == "function")
      theCallback({}, {success:true, errorMessage:""});
  }

  /**
   * Returns a reference to the internal XML DOM.
   * @return Document: a reference to the internally used DOM representation.
   */
  class$.getXMLDocument = function() {
    return this.xmlDoc_;
  }

  /**
   * Sets the internal XML DOM.
   * @param xmlDoc: Document: the DOM representation that should be used.
   */
  class$.setXMLDocument = function(xmlDoc) {
    this.xmlDoc_ = xmlDoc;
  }

  /**
   * Retrieves the DOM Node from the given XPath.
   * @param anXPath: string: the XPath of the node to retrieve
   * @return Node: the desired DOM node.
   */
  class$.getNode = function( anXPath ) {
    throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract method getNode!";
  }

  /**
   * Inserts a new DOM Node to the given parent with the given value as
   * the tag to insert.
   * @param theParentXPath: string: the XPath of the node to retrieve
   * @param theValue: string: the XML representation of the new node as string
   * @return String: The XPath of the inserted node.
   */
  class$.insertNode = function( theParentXPath, theValue ) {
    throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract method insertNode!";
  }

  /**
   * Replaces the DOM Node at the given XPath with the given value as
   * the tag to insert.
   * @param anXPath: string: the XPath of the node to replace
   * @param theValue: string: the XML representation of the new node as string
   */
  class$.replaceNode = function( anXPath, theValue ) {
    throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract method replaceNode!";
  }

  /**
   * Deletes the DOM Nodes at the given XPaths.
   * @param anXPathArray: string[]: the XPath of the nodes to delete as array of strings
   */
  class$.deleteNodes = function( anXPathArray ) {
    throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract method deleteNode!";
  }

  /**
   * Updates the Attribute of a node at a given XPath.
   * @param anXPath: string: the XPath of the node attribute to replace.
   * @param theValue: string: the new value of the attribute.
   * @return boolean: true if the node was actually updated.
   */
  class$.updateAttribute = function( theXPath, theValue ) {
    throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract method updateAttribute!";
  }

  /**
   * Returns the elements of xPath of the transformed document.
   * @return Array: a list of elements.
   */
  class$.getTransformedElements = function( xslURI, xPath ) {
    throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract method getTransformedElements!";
  }

  /**
   * Returns the script elements of the document provided.
   * FIXME: this methos shouldn't be part of the wrapper since it
   * presumes (x)html as the result of the transformation!
   * @return Array: a list of elements.
   */
  class$.getTransformedScripts = function( theDoc, fromWholeDocument ){
     throw "com.hyperwave.xml.AbstractXMLWrapper: Call of abstract method getTransformedScripts!";
  }

  /**
   * Returns the number of previous siblinks of same node type + 1 or 0 (if none),
   * used to i.e. calculate the XPath for an element when the XPath of
   * the parent is known.
   * @param theNode: Node: The node to process.
   * @return integer: The number of siblings of same nodeType.
   */
  class$.getSiblingsIndex = function( theNode ) {
    var count = 1;
    var sibling = theNode.previousSibling;
    while (sibling) {
      if(sibling.nodeType == 1 &&
        sibling.nodeName == theNode.nodeName) {
        count++;
      }
      sibling = sibling.previousSibling;
    };
    return count == 1 ? 0 : count;
  }

  /**
   * Returns all child nodes (ELEMENT_NODE) of given xpath object
   *
   * @param theNode: Node: The node to process.
   * @return Array: array of child nodes or empty array
   */

  class$.getChildNodes = function( theXPath ) {
    var chld = new Array();
    var par = this.getNode(theXPath)
    if (par && par.hasChildNodes()) {
      for (var c = 0; c < par.childNodes.length; c++) {
        if (par.childNodes[c].nodeType == com.hyperwave.xml.AbstractXMLWrapper.static_.ELEMENT_NODE_TYPE) {
          chld.push(par.childNodes[c]);
        }
      }
    }
    return chld;
  }

  /**
   * Moves the given node before the given next sibling
   *
   * @param theNode: Node: The node to move.
   * @param theNextSiblingNode: Node: The node which should be next to the moved one
   */
  class$.moveNode = function (theNode, theNextSiblingNode) {
    var parent_node = theNode.parentNode;
    parent_node.insertBefore(theNode, theNextSiblingNode);
  }

});
// </JSClass>

