package examples.xml.biztalk;

import java.io.Reader;
import java.io.StringReader;
import java.io.IOException;
import org.w3c.dom.*;
import weblogic.xml.dom.DOMParser;
import weblogic.xml.dom.DOMParserException;
import org.xml.sax.SAXParseException;

/**
 * A Biztalk document that has been received by a 
 * Biztalk Server. Implements examples.xml.biztalk.IncomingMessage 
 * and includes the ability to parse the document using a 
 * DOM parser.
 *
 * @author Copyright (c) 2000 by BEA Systems, Inc. All Rights Reserved.
 */
public class DOMIncomingMessage implements IncomingMessage {

  private static final String NODE_BIZTALK = "biztalk_1";
  private static final String NODE_HEADER = "header";
  private static final String NODE_DELIVERY = "delivery";
  private static final String NODE_BODY    = "body";
  private static final String NODE_FROM    = "from";
  private static final String NODE_TO      = "to";

  private static final String NODE_PROCESS = "process";
  private static final String NODE_ADDRESS = "address";
  private static final String ATTRIBUTE_XMLNS = "xmlns";
  private static final String NODE_HANDLE = "handle";
  private static final String NODE_REFERENCE_ID = "referenceID";

  private transient Node bizNode=null;
  private transient Node docNode=null;
  private transient Node toNode=null;
  private transient Node fromNode=null;
  private String bizDoc=null;


  public DOMIncomingMessage(String doc) {
    bizDoc = doc;
  }

  private void parsedoc() throws BizException {
    Reader r = new StringReader(bizDoc);
    DOMParser parser = DOMParser.getDOMParser("com.sun.xml.parser.Parser");
    try {
      docNode = parser.getDocument(r);
      bizNode = docNode.getFirstChild();
    } catch (IOException e) {
      throw new BizException(e.getMessage());
    } catch (DOMParserException e) {
      throw new BizException(e.getMessage());
    }
  }

  // return child of top node
  private Node findNode(String name) {
    NodeList nl = bizNode.getChildNodes();
    for (int i = nl.getLength(); --i >= 0; ) {
      Node n = nl.item(i);
      if (n.getNodeName().equals(name)) return n;
    }
    return null;
  }

  //return child of nd node
  private Node findNode(Node nd, String name) {
    NodeList nl = nd.getChildNodes();
    if (nl != null) {
      for (int i = nl.getLength(); --i >= 0; ) {
        Node n = nl.item(i);
        if (n.getNodeName().equals(name)) return n;
      }
    }
    return null;
  }

  public String getXML() throws BizException { 
    if (bizDoc == null) throw new BizException("Empty XML string");
    return bizDoc; 
  }

  public String getType() throws BizException {
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) throw new BizException("Parse failure");
    Node nd = findNode(NODE_BODY);
    if (nd != null) {
      NodeList nl = nd.getChildNodes();
      if (nl != null) {
	int cnt = nl.getLength();
	for (int i=0;i<cnt;i++) {
	  Node n = nl.item(i);
	  if (n.getNodeType() == Node.ELEMENT_NODE) return n.getNodeName();
	}
	throw new BizException("Invalid payload");
      }
      else {
        throw new BizException ("No payload");
      }
    }
    else {
      throw new BizException("No body");
    }
  }

  public String getNameSpace() throws BizException { 
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    //
    // find the payload start node then return the xmlns attr value
    //
    String ret = null;
    Node tNode = findNode(NODE_BODY);
    if (tNode != null) {
      NodeList tList = tNode.getChildNodes();
      if (tList != null) {
        int cnt = tList.getLength();
	for (int i=0;i<cnt;i++) {
	  Node n = tList.item(i);
	  if (n.getNodeType() == Node.ELEMENT_NODE) {
            NamedNodeMap attrs = tList.item(0).getAttributes();
            if (attrs != null) {
              Node ns = attrs.getNamedItem(ATTRIBUTE_XMLNS);
              if (ns != null) {
                ret =  ns.getNodeValue();
		break;
              }
            }
          }
	}
      }
    }
    return ret;
  }

  public String getBizNameSpace() throws BizException { 
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    //
    // find the biztalk_1 node then return the xmlns attr value
    //
    String ret = null;
    Node bizNode = findNode(NODE_BIZTALK);
    NamedNodeMap attrs = bizNode.getAttributes();
    if (attrs != null) {
      Node ns = attrs.getNamedItem(ATTRIBUTE_XMLNS);
      if (ns != null) {
        ret =  ns.getNodeValue();
      }
    }
    return ret;
  }

  // from block
  private String getFromNodeAttribute(String name) { 
    //
    // returns the value of the 1st(only) child under the named node
    //
    String ret = null;
    // find from node if first time
    //
    if (fromNode == null) {
      Node h = findNode(NODE_HEADER);
      if (h != null) {
	Node d = findNode(h,NODE_DELIVERY);
	if (d != null) {
          fromNode = findNode(d,NODE_FROM);
        }
      }
    }
    if (fromNode != null) {
      Node nd = findNode(fromNode,name);
      if (nd != null) {
        NodeList nl = nd.getChildNodes();
        if ((nl != null) && (nl.getLength() > 0)) {
          ret = nl.item(0).getNodeValue();
        }
      }
    }
    return ret;
  }
  public String getFromAddress() throws BizException {
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    return getFromNodeAttribute(NODE_ADDRESS);
  }
  public String getFromReferenceID() throws BizException {
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    return getFromNodeAttribute(NODE_REFERENCE_ID);
  }
  public String getFromProcess() throws BizException {
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    return getFromNodeAttribute(NODE_PROCESS);
  }
  public String getFromHandle() throws BizException {
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    return getFromNodeAttribute(NODE_HANDLE);
  }

  // to block
  private String getToNodeAttribute(String name) { 
    //
    // returns the value of the 1st(only) child under the named node
    //
    String ret = null;
    // find to node if first time
    //
    if (toNode == null) {
      Node h = findNode(NODE_HEADER);
      if (h != null) {
	Node d = findNode(h,NODE_DELIVERY);
	if (d != null) {
          toNode = findNode(d,NODE_TO);
        }
      }
    }
    if (toNode != null) {
      Node nd = findNode(toNode,name);
      if (nd != null) {
        NodeList nl = nd.getChildNodes();
        if ((nl != null) && (nl.getLength() > 0)) {
          ret = nl.item(0).getNodeValue();
        }
      }
    }
    return ret;
  }
  public String getToAddress() throws BizException {
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    return getToNodeAttribute(NODE_ADDRESS);
  }
  public String getToReferenceID() throws BizException {
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    return getToNodeAttribute(NODE_REFERENCE_ID);
  }
  public String getToProcess() throws BizException {
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    return getToNodeAttribute(NODE_PROCESS);
  }
  public String getToHandle() throws BizException {
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    return getToNodeAttribute(NODE_HANDLE);
  }
  
  // message body
  public String getBodyAsXML() throws BizException { 
    throw new BizException("getBodyAsXML: no implmented");
  }

  /**
   * Returns the DOM Node object repesenting the Body element in the document.
   *
   * @return Node object for Body element
   * @exception BizException  thrown if unable to parse or read document
   */
  public Object getBodyAsObject()throws BizException  
  {
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    return (findNode(NODE_BODY));
  }
    
  /**
   * Returns the DOM Node object repesenting the first element of the payload in the document.
   *
   * @return Node object for payload element
   * @exception BizException  thrown if unable to parse or read document
   */
  public Object getPayloadAsObject() throws BizException { 
    if (bizNode == null) {
       parsedoc();
    }
    if (bizNode == null) return null;
    Node nd = findNode(NODE_BODY);
    if (nd != null) {
      NodeList nl = nd.getChildNodes();
      if (nl != null) {
	int cnt = nl.getLength();
	for (int i=0;i<cnt;i++) {
	  Node n = nl.item(i);
	  if (n.getNodeType() == Node.ELEMENT_NODE) return n;
	}
      }
    }
    return null;
  }

  
  // create a response to this message
  /**
   * Not implemented
   * @exception BizException thrown if unable to parse or read document
   */
  public OutgoingMessage createResponse(String type, String name) throws BizException {
    if (bizNode == null) {
       parsedoc();
    }
    throw new BizException("createResponse: not implemented");
  }
  
}
