/* Copyright (c) 2002, Oracle Corportation. All rights reserved */
package oracle.portal.provider.v2.webservice;

import java.io.InputStream; 
import java.io.Reader;
import java.io.StringReader;
import java.io.ByteArrayInputStream;
import java.io.IOException; 
import java.io.ByteArrayOutputStream; 
import java.net.URL; 
import java.net.URLConnection;
import org.w3c.dom.Document; 
import org.w3c.dom.NamedNodeMap; 
import org.w3c.dom.Element; 
import org.w3c.dom.NodeList; 
import org.w3c.dom.Node; 
import org.w3c.tidy.Tidy;
import org.xml.sax.SAXException;
import oracle.portal.utils.xml.v2.XMLUtil;
import oracle.xml.parser.v2.XMLDocument; 

/**
 * <code>HTMLStringWebServiceRenderer</code> is a specialized {@link
 * RPCWebServiceRenderer} for invoking 'RPC style' webservices that return HTML 
 * as a string. The HTML strings are parsed into XML using JTidy classes. The 
 * resultant XHTML is added to the response.
 * <code>HTMLStringWebServiceRenderer</code> extends 
 * <code>oracle.portal.provider.v2.webservice.RPCWebServiceRenderer</code>.
**/

public class HTMLStringWebServiceRenderer extends RPCWebServiceRenderer
{

    // Assume the response strings contains HTML.
    
    protected void expandResult (Document doc, Element el, Object result)
    {
        // Let the superclass handle all non-string results.
        if (result == null || !(result instanceof String))
        {
            super.expandResult(doc, el, result);
        }
        else
        {
            try
            {
                // Get a UTF-8 inputstream from the result.
                InputStream in = 
                    new ByteArrayInputStream(((String)result).getBytes("UTF8"));

                // Parse it into a DOM structure
                Tidy tidy = new Tidy(); 
                tidy.setMakeClean(true); 
                tidy.setBreakBeforeBR(true); 
                tidy.setShowWarnings(false); 
                tidy.setOnlyErrors(false); 
                tidy.setQuoteAmpersand(true); 
                tidy.setQuoteNbsp(true); 
                tidy.setQuoteMarks(true); 
                tidy.setWrapScriptlets(true); 
                tidy.setWrapAsp(true); 
                tidy.setQuiet(true); 
                Document tidiedHTMLDoc = tidy.parseDOM(in, null);
                cloneXMLFragment(tidiedHTMLDoc.getDocumentElement(), el);
            }
            catch(IOException ie)
            {
                // If we can't parse the String as XML, let the superclass treat
                // it as a normal string.
                super.expandResult(doc, el, result); 
            }            
        }
    }
    
     //cloneXMLFragment is used to cloneXMLFragment containing XHTML for the 
     // passed HTML.

    private void cloneXMLFragment(Node node, Node curTarget)
    { 
        if (node == null) return; 
        Document d = curTarget instanceof Document ? (Document) curTarget : 
            curTarget.getOwnerDocument(); 
        int type = node.getNodeType(); 

        switch (type) { 
            
            // If we get the root node of the document, start the recursion
            // by calling build the Doc Element
            
        case Node.DOCUMENT_NODE: 
            cloneXMLFragment(((Document) node).getDocumentElement(), d); 
            break; 
            
            // If we get an Element in the JTidy DOM, create Element in Oracle 
            // DOM and append it to the current target node as a child. Also 
            // build Oracle DOM attribute nodes for each attrib of the JTidy DOM 
            // Element.
            
        case Node.ELEMENT_NODE: 
            Element e = d.createElement(node.getNodeName()); 
            NamedNodeMap attrs = node.getAttributes(); 

            for (int i = 0; i < attrs.getLength(); i++) { 
                e.setAttribute(attrs.item(i).getNodeName(), 
                    attrs.item(i).getNodeValue()); 
            } 
            curTarget.appendChild(e); 
            NodeList children = node.getChildNodes(); 
            
            // Recurse to build any children.
            
            if (children != null) { 
                int len = children.getLength(); 

                for (int i = 0; i < len; i++) { 
                    cloneXMLFragment(children.item(i), e); 
                } 
            } 
            break; 
            
            // If we get a Text Node in the JTidy DOM, create Text Node in Oracle
            // DOM and append it to the current target node as a child
            
        case Node.TEXT_NODE: 
            curTarget.appendChild(d.createTextNode(node.getNodeValue())); 
            break; 
        } 
    }
}