/**
  * ModifXmlPrices.java
  * @author Thomas Rowland
  * @version 02-08-03
  */

package xml;

import java.io.*;
import futils.*;
import javax.xml.parsers.*; // JAXP api
import org.w3c.dom.*;       // DOM api
import org.xml.sax.*;       // for SAX exceptions


/*
 * DomParser program for Product.xml.
 * This program parses the XML file, increases
 * the <UnitPrice> element values for each <Product>, and 
 * writes the modified XML out to a new file "NewProduct.xml".
 * This program uses the DOM Level 2 api and JAXP 1.2. 
 */
public class ModifXmlPrices {
    // Node type constants
    static final int ELEMENT_NODE   = 1;
    static final int TEXT_NODE      = 3;
    static final int DOCUMENT_NODE  = 9;
    
    static float incr = 0;
    static BufferedWriter out = null;

    public static void main (String[] args) 
            throws IOException {
        System.out.println("Enter percent price increase: ");
        BufferedReader in = new BufferedReader( 
                            new InputStreamReader(System.in));
        incr = new Float(in.readLine()).floatValue() * .01f;
        
        File inFile = Futil.getReadFile("select an XML file");
        File outFile = new File(inFile.getParent() + "\\NewProduct.xml");
        out = new BufferedWriter(new FileWriter(outFile));   

        parse("file:" + inFile.getAbsolutePath());
        out.flush();
        out.close();
    }


    /**
     *  Parses an xml file 
     */
    private static void parse (String uri) 
            throws IOException {
        
        // First get the factory    
        DocumentBuilderFactory dbf = 
        DocumentBuilderFactory.newInstance();
        try {
            //dbf.setValidating(true);
            
            // Get the DocumentBuilder
            DocumentBuilder db = dbf.newDocumentBuilder();
            
            // Set an error handler
            db.setErrorHandler(new MyErrorHandler());           
            
            // Parse the file and get back a DOM Document
            Document doc = db.parse(uri);
            
            // Get the root element from the DOM Document
            Element root = doc.getDocumentElement();
            
            // Now we can traverse the Document and print out results
            traverse(root);
            printNode(doc);
        } 
        catch (ParserConfigurationException e) {
            // Factory unable to create parser.
            System.out.println(
                "** ParserConfigurationException\n" 
                + e.getMessage());
        }
        catch (SAXException e) {
            // Parsing error.
            System.out.println(
                "** SAXException\n" 
                + e.getMessage());
            // Get wrapped exception
            Exception ex = e.getException();
            if (ex != null)
                ex.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        }       
    }
    
    
    /**
     * Recursive method which traverses an Element
     * and searches for the <UnitPrice> element.
     */
    private static void traverse (Node elem) {
        try {
            if (elem.hasChildNodes()) {
                NodeList children = elem.getChildNodes();
                int length = children.getLength();
                
                for (int i=0; i<length; i++) {
                    Node n = children.item(i);
                    String name = n.getNodeName();
                    
                    if (n.getNodeType() == ELEMENT_NODE) {
                        traverse(n);    //recurse
                    }
                    else
                    if (n.getNodeType() == TEXT_NODE) {
                        String pname = n.getParentNode().getNodeName();
                        if (pname.equals("UnitPrice")) {
                            String price = n.getNodeValue();
                            System.out.println(pname + " = " + price);
                            float f = (new Float(price).floatValue()) * (1 + incr);
                            int newPrice = new Float(f).intValue();
                            
                            n.setNodeValue(String.valueOf(newPrice));
                            System.out.println("new value of " + pname + 
                                " = " + n.getNodeValue() + "\n");
                            return;
                        }
                    }
                }
                return;
            }
        }
        catch (DOMException e) {
            System.out.println ("*** DOMException\n"
                                + e.getMessage());
        }
    }
    
    
    /*
     * Recursive method which prints out a DOM element
     */
    private static void printNode(Node node) 
        throws IOException {
        switch (node.getNodeType()) {
            case Node.DOCUMENT_NODE:
                out.write("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"" 
                    + "standalone=\"yes\"?>\n\n");
                
                Document doc = (Document)node;                
                
                out.write ("<!DOCTYPE " 
                    + doc.getDocumentElement().getNodeName() 
                    + " [" + doc.getDoctype().getInternalSubset()
                    + "]>\n");
                                        
                // recurse on each child
                NodeList nodes = node.getChildNodes();
                if (nodes != null) {
                    for (int i=0; i<nodes.getLength(); i++) {
                        printNode(nodes.item(i));
                    }
                }
                break;
                
            case Node.ELEMENT_NODE:
                String name = node.getNodeName();
                out.write("<" + name);
                NamedNodeMap attributes = node.getAttributes();
                for (int i=0; i<attributes.getLength(); i++) {
                    Node attr = attributes.item(i);
                    out.write(" " + attr.getNodeName() +
                                     "=\"" + attr.getNodeValue() +
                                     "\"");
                    out.newLine();
                }
                
                out.write(">");
                
                // recurse on each child
                NodeList children = node.getChildNodes();
                
                if (children != null) {
                    for (int i=0; i<children.getLength(); i++)
                        printNode(children.item(i));
                }
                
                out.write("</" + name + ">");                

            case Node.TEXT_NODE:
                String val = node.getNodeValue();
                if (val != null)
                    out.write(val);
                break;
        }
    }


    /*
     * Error Handler to report validation errors and warnings.
     */
    private static class MyErrorHandler implements ErrorHandler {

        /*
         * Returns a string describing parse exception details
         */
        private String getParseExceptionInfo(SAXParseException spe) {
            String systemId = spe.getSystemId();
            if (systemId == null) {
                systemId = "null";
            }
            String info = "URI=" + systemId +
                "\nLine=" + spe.getLineNumber() +
                "\n" + spe.getMessage();
            return info;
        }

        /* 
         * The following methods are standard SAX ErrorHandler 
         * methods used by DOM
         */
        public void warning(SAXParseException spe) throws SAXException {
            System.out.println("Warning: " + getParseExceptionInfo(spe));
        }
        
        public void error(SAXParseException spe) throws SAXException {
            String message = "Error: " + getParseExceptionInfo(spe);
            throw new SAXException(message);
        }

        public void fatalError(SAXParseException spe) throws SAXException {
            String message = "Fatal Error: " + getParseExceptionInfo(spe);
            throw new SAXException(message);
        }
    }//

}//