// Copyright (c) Keith D Gregory, all rights reserved
package com.kdgregory.example.xml.xpath;

import java.io.StringReader;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import javax.xml.xpath.XPathFunctionResolver;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import org.xml.sax.InputSource;

import net.sf.practicalxml.xpath.SimpleNamespaceResolver;


public class FunctionExample
{
    private static class Uppercase implements XPathFunction
    {
        @Override
        @SuppressWarnings("rawtypes")
        public Object evaluate(List args) throws XPathFunctionException
        {
            Object arg = args.iterator().next();
            if (arg instanceof NodeList)
            {
                NodeList nodes = (NodeList)arg;
                if (nodes.getLength() == 0)
                    return "";
                else
                    return nodes.item(0).getTextContent().toUpperCase();
            }
            else if (arg instanceof String)
            {
                return ((String)arg).toUpperCase();
            }
            else
                throw new XPathFunctionException("invalid argument: " + arg);
        }
    }

    public static void main(String[] argv) throws Exception
    {
        String xml = "<foo>"
                   + "    <bar name='argle'>"
                   +          "Argle"
                   + "    </bar>"
                   + "    <bar name='bargle'>"
                   +          "Bargle"
                   + "        <baz>Baz</baz>"
                   + "    </bar>"
                   + "</foo>";

        Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(xml)));

        XPath xpath = XPathFactory.newInstance().newXPath();
        xpath.setNamespaceContext(new SimpleNamespaceResolver("fn", "urn:x-com.kdgregory.example.xpath.functions"));
        xpath.setXPathFunctionResolver(new XPathFunctionResolver()
        {
            private QName myFunctionName = new QName("urn:x-com.kdgregory.example.xpath.functions", "uppercase");
            private XPathFunction myFunction = new Uppercase();

            @Override
            public XPathFunction resolveFunction(QName functionName, int arity)
            {
                if (functionName.equals(myFunctionName) && (arity == 1))
                    return myFunction;
                else
                    return null;
            }
        });

        String result1 = xpath.evaluate("fn:uppercase(//baz)", dom);
        System.out.println("uppercased selection: \"" + result1 + "\"");

        String result2 = xpath.evaluate("//bar[fn:uppercase(@name)='BARGLE']", dom);
        System.out.println("uppercased node test: \"" + result2 + "\"");
    }
}
