/*******************************************************************************
* Copyright (c)                                                                *
*           2005   Tristan Allwood,                                            *
*           2005   Daniel Burke,                                               *
*           2005   Marc Hull,                                                  *
*           2005   Ekaterina Itskova,                                          *
*           2005   Steve Zymler                                                *
*                                                                              *
* Permission is hereby granted, free of charge, to any person obtaining a      *
* copy of this software and associated documentation files (the                *
* "Software"), to deal in the Software without restriction, including          *
* without limitation the rights to use, copy, modify, merge, publish,          *
* distribute, sublicense, and/or sell copies of the Software, and to           *
* permit persons to whom the Software is furnished to do so, subject to        *
* the following conditions:                                                    *
*                                                                              *
* The above copyright notice and this permission notice shall be included      *
* in all copies or substantial portions of the Software.                       *
*                                                                              *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS      *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF                   *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.       *
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY         *
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,         *
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE            *
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                       *
*******************************************************************************/
/*
 * Created on 29-Oct-2004
 *
 */
package uk.ac.ic.doc.kevlar.publicUtil.dom;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

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

import uk.ac.ic.doc.kevlar.hial.XMLLoadingException;
import uk.ac.ic.doc.kevlar.publicUtil.strings.StringUtil;

/**
 * @author Daniel Burke
 *
 */
public class XMLUtil<T> implements Iterable<T> {
	
	private NodeList list;
	public XMLUtil(NodeList list) 
	{
		this.list = list;
	}
	
    public static Element stream2Elem(InputStream xmlStream) throws XMLLoadingException, IOException
    {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

       try {
            //TODO : Plugin validation code here
            DocumentBuilder db = factory.newDocumentBuilder();
            Document d = db.parse(xmlStream);

            return d.getDocumentElement();
        }
        catch(IOException io)
        {
            throw io;
        }
        catch(Exception e)
        {
            throw new XMLLoadingException(e);
        }
    }
	

    public static Element string2Elem(String xmlString) throws XMLLoadingException
    {
        ByteArrayInputStream reader = new ByteArrayInputStream(xmlString.getBytes());
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

       try {
            //TODO : Plugin validation code here
            DocumentBuilder db = factory.newDocumentBuilder();
            Document d = db.parse(reader);

            return d.getDocumentElement();
        }
        catch(Exception e)
        {
            throw new XMLLoadingException(e);
        }
    }
	
	public static void putElement(StringBuilder buf, String tag, String contents, int depth)
	{
		buf.append(StringUtil.repeat("\t", depth));
		if(contents != null)
		{
			buf.append("<").append(tag).append(">").append(contents);
			buf.append("</").append(tag).append(">").append(StringUtil.NEWLINE);
		}
		else
		{
			buf.append("<").append(tag).append(" />").append(StringUtil.NEWLINE);
		}
	}
	
	public static int putOpenElem(StringBuilder buf, String tag, int depth)
	{
		buf.append(StringUtil.repeat("\t", depth));
		buf.append("<").append(tag).append(">").append(StringUtil.NEWLINE);
		depth++;
		return depth;
	}
	
	public static int putCloseElem(StringBuilder buf, String tag, int depth)
	{
		depth--;
		buf.append(StringUtil.repeat("\t", depth));
		buf.append("</").append(tag).append(">").append(StringUtil.NEWLINE);
		return depth;
	}

	public static String getInnerContent(Element parent)
	{
		NodeList children = parent.getChildNodes();
		
		StringBuilder text = new StringBuilder(100);
		for(int index = 0 ; index < children.getLength() ; index++)
		{
			text.append(children.item(index).getTextContent());
		}
		
		return text.toString();
	}
	
	public static String yankText(Element parent, String tag)
	{
		Element current = parent;
		
		NodeList elems = current.getElementsByTagName(tag);
		if(elems.getLength() == 0)
		{
		    return null;
		}
		current = (Element)elems.item(0);
	
		return getInnerContent(current);
	}
	
	public static String yankText(Element parent, String firstTag, String secondTag)
	{
		Element current = parent;
		
		NodeList elems = current.getElementsByTagName(firstTag);
		if(elems.getLength() == 0)
		{
		    return null;
		}
		current = (Element)elems.item(0);
		
		elems = current.getElementsByTagName(secondTag);
		if(elems.getLength() == 0)
		{
		    return null;
		}
		current = (Element)elems.item(0);
		
		return getInnerContent(current);
	}
	
	public static Element yankElement(Element parent, String tag)
	{
		Element current = parent;
		
		NodeList elems = current.getElementsByTagName(tag);
		if(elems.getLength() == 0)
		{
		    return null;
		}
		current = (Element)elems.item(0);
	
		return current;
	}
	
	public static Element yankElement(Element parent, String firstTag, String secondTag)
	{
		Element current = parent;
		
		NodeList elems = current.getElementsByTagName(firstTag);
		if(elems.getLength() == 0)
		{
		    return null;
		}
		current = (Element)elems.item(0);
		
		elems = current.getElementsByTagName(secondTag);
		if(elems.getLength() == 0)
		{
		    return null;
		}
		current = (Element)elems.item(0);
		
		return current;
	}
	
	public Iterator<T> iterator()
	{
		return new NodeListIterator<T>(list);
	}
	
	public static Iterable<Node> getNodeIterator(NodeList list)
	{
		return new XMLUtil<Node>(list);
	}
	
	
	
	public static Iterable<Element> getElementIterator(NodeList list)
	{
		return new XMLUtil<Element>(list);
	}
	
	static private class NodeListIterator<T> implements Iterator<T>
	{
		private int index = 0;
		private int length;
		private NodeList list;
		
		public NodeListIterator(NodeList list)
		{
			this.list = list;
			length = list.getLength();
		}
		
		public boolean hasNext()
		{
			return index < length;
		}
		
		public T next()
		{
			index++;
			return (T)list.item(index - 1);
		}
		
		public void remove()
		{
			throw new UnsupportedOperationException();
		}
	}
}
