package examples;

import java.io.*;
import java.util.*;
import java.net.*;

import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;

import org.w3c.dom.*;
import org.w3c.dom.traversal.*;
import org.xml.sax.SAXException;

import oracle.xml.parser.v2.*;

import oracle.jsp.parse.OraclePageData;

public class XMLViewTagTLV extends TagLibraryValidator {

   static StringBuffer xmlview;    // normally you would not have statics here
   static XMLDocument  xdoc;       // this is for demo only!

   public XMLViewTagTLV() {
     super();
   }

   public synchronized ValidationMessage[] validate(
            String prefix, String uri, PageData page) {
     Vector validationErrors = new Vector();
     saveInput(page.getInputStream());
     xdoc = createXMLDocmentFromStream(page.getInputStream());
     NodeFilter nf = new TagFilter();
     NodeIterator nodei = 
          xdoc.createNodeIterator(((Node)xdoc.getDocumentElement()),
          NodeFilter.SHOW_ALL, nf, true);
     try {
       XMLNode xn = (XMLNode)nodei.nextNode();
       while (xn != null) {
         if (xn.getLocalName().equals("xmlView")) { // 
           // showAs value is "stream" or "tree"
           if (!checkShowAsValue(xn)) 
             validationErrors.addElement(vmFromString(xn,
                    "Valid values for showAs are stream or tree"));
         }
         xn = (XMLNode)nodei.nextNode();
       }
     } catch (DOMException d) {
             System.err.println(d.getMessage());
     }
     return vmFromVector(validationErrors);
   }

   private XMLDocument createXMLDocmentFromStream(InputStream is){
     try {
       DOMParser parser = new DOMParser();
       parser.setErrorStream(System.out);
       parser.setValidationMode(DOMParser.NONVALIDATING);
       parser.showWarnings(true);
       parser.setPreserveWhitespace(false);
       parser.retainCDATASection(false);
       parser.parse(is);
       return (parser.getDocument());
     } catch (Exception e) {
       // should never get an invalid document from jsp engine
      System.err.println("Exception is " + e.getMessage());
     }
     return null; 
   }

   // constructs a ValidationMessage[] from a ValidationMessage Vector
   static ValidationMessage[] vmFromVector(Vector v) {
     ValidationMessage[] vm = new ValidationMessage[v.size()];
     for (int i = 0; i < vm.length; i++)
       vm[i] = (ValidationMessage) v.get(i);
     return vm;
   }

   // constructs a ValidationMessage from a node and error string
   static ValidationMessage vmFromString(XMLNode node, String message) {
     return new ValidationMessage(getElementId(node), message);
   }

   static String getElementId (XMLNode e) {
     NamedNodeMap nnm = e.getAttributes();
     if (nnm != null) {
       return nnm.getNamedItem("jsp:id").getNodeValue();
     }
     return null;
   }

   boolean checkShowAsValue(XMLNode node){
     Node n;
     String attrval;
     NamedNodeMap nnm = node.getAttributes();
     if (nnm != null) {
       Node attrNode = nnm.getNamedItem("showAs");
       if (attrNode != null ){
         attrval = attrNode.getNodeValue();
         if (!(attrval.equalsIgnoreCase("stream") || 
              attrval.equalsIgnoreCase("tree")))  
           return false;
       }
     }
     return true;      
   }

  static XMLDocument getXMLDocument() {
    return xdoc;
  }

  static StringBuffer getXMLView() {
    return xmlview;
  }

  void saveInput(InputStream is) {
      xmlview = new StringBuffer();
      try {
        byte [] buf = new byte [1024];
        int i;
        while ((i = is.read(buf, 0, buf.length)) != -1 ) {
            xmlview.append(new String (buf, 0, i, "ISO-8859-1" ));
        }
      } catch (IOException io ) {
        System.err.println("unable to get input stream");
      }
  }

}  

// NodeFilter class returns elements to check
class TagFilter implements NodeFilter {
   public short acceptNode(Node node) {
     // specify the tags you want to check
     if ((node.getLocalName() != null) && 
         (node.getLocalName().equals("xmlView"))) {
       return NodeFilter.FILTER_ACCEPT;
     }
     return NodeFilter.FILTER_SKIP; 
   }

}


