package org.apache.tools.ant.taskdefs.optional.xpath;

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

import junit.framework.*;

import org.w3c.dom.*;
import org.w3c.dom.traversal.NodeIterator;

import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;

import org.apache.xpath.XPathAPI;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;


public class TestXPath extends TestCase {
    
    protected XPath task;
    
    private static class XPathDecorator extends XPath {
        XPathDecorator(Project project){
            this.project = project;
        }
    }
    
    protected File inputFile;
    
    protected final static String XML_CONTENT =
    "<root>" +
    "<e1><e2 a=\"data\"/></e1>" +
    "<e1><e2 a=\"data\"/></e1>" +
    "<e1><e2 a=\"data\"/></e1>" +
    "<e1 b=\"attr\"/>" +
    "</root>";
    
    public TestXPath(String name){
        super(name);
    }
    
    protected void setUp() throws Exception {
        task = new XPathDecorator(new Project());
        inputFile = File.createTempFile("xpath-test", ".xml");
        System.out.println("Logging to " + inputFile);
        FileOutputStream fos = new FileOutputStream(inputFile);
        fos.write(XML_CONTENT.getBytes());
        fos.flush();
        fos.close();
        //inputFile.deleteOnExit();
    }
    
    protected void tearDown() throws Exception {
        //inputFile.delete();
    }
    
    protected void executeDirect(File file, File tofile, String xpath, String value) throws BuildException {
        task.setFile(file);
        task.setToFile(tofile);
        task.setSelect(xpath);
        task.setValue(value);
        task.execute();
    }

    protected void executeApplies(File file, File tofile) throws BuildException {
        task.setFile(file);
        task.setToFile(tofile);
        task.execute();
    }
    
    public void testInvalidSetup() throws Exception {
        try {
            executeDirect(null, null, null, null);
            fail("Should failed");
        } catch (BuildException e){
        }
    }
        
    public void testMultipleReplace() throws Exception {
        executeDirect(inputFile, null, "/root/e1/e2/@a", "replaced");
        assert(inputFile, "/root/e1/e2/@a", "replaced");
    }

    public void testSingleReplace() throws Exception {
        executeDirect(inputFile, null, "/root/e1/@b", "replaced");
        assert(inputFile, "/root/e1/@b", "replaced");
    }

    public void testApply() throws Exception {        
        XPath.Apply apply = new XPath.Apply();
        apply.setSelect("/root/e1/e2/@a");
        apply.setValue("replaced");
        task.addApply(apply);
        apply = new XPath.Apply();
        apply.setSelect("/root/e1/@b");
        apply.setValue("replaced");
        task.addApply(apply);
        executeApplies(inputFile, null);
        Document dom = parse(inputFile);
        assert(dom, "/root/e1/e2/@a", "replaced");
        assert(dom, "/root/e1/@b", "replaced");
    }

    protected void assert(Document doc, String xpath, String value) throws Exception {
        // iterate over all nodes in XPath and set the value
        NodeIterator nl = XPathAPI.selectNodeIterator(doc, xpath);
        int i = 0;
        Node n;
        while ((n = nl.nextNode())!= null) {
            assertEquals(value, n.getNodeValue() );
        }        
    }
    
    public static Document parse(File file) throws Exception {
        // parse the XML file as a DOM
        FileInputStream fis = new FileInputStream(file);
        InputSource in = new InputSource(fis);
        DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
        Document doc = dfactory.newDocumentBuilder().parse(in);
        fis.close();
        return doc;
    }
    
    protected void assert(File file, String xpath, String value) throws Exception {
        Document doc = parse(file);
        assert(doc, xpath, value);
    }

}