/* 
 * E-XML Library:  For XML, XML-RPC, HTTP, and related.
 * Copyright (C) 2002-2008  Elias Ross
 * 
 * genman@noderunner.net
 * http://noderunner.net/~genman
 * 
 * 1025 NE 73RD ST
 * SEATTLE WA 98115
 * USA
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * $Id$
 */

package net.noderunner.exml;

import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

/**
 * This class translates an <code>Element</code> into a series of calls to a
 * SAX <code>ContentHandler</code> instance.
 */
public class ElementToSAX {

  private ElementToSAX() {
  }

	/**
	 * Calls <code>startElement</code>, <code>endElement</code>,
	 * and <code>characters</code> of this handler for element
	 * events.  Note that the <code>Attributes</code> instance passed in
	 * to the <code>startElement</code> is reused, hence will be no
	 * longer valid once the callback ends. 
	 */
	public static void pipe(Element e, ContentHandler h)
		throws SAXException
	{
		pipe(new EAttributes(), e, h);
	}

	/**
	 * This recycles the same EAttributes instance.
	 */
	private static void pipe(EAttributes attr, Element e, ContentHandler h)
		throws SAXException
	{
		attr.setList(e.getAttributes());
		h.startElement("", e.getName(), e.getName(), attr);
		List<Node> list = e.getChildNodes();
		if (list != null) {
			for (int i = 0; i < list.size(); i++) {
				Node node = list.get(i);
				if (node.getNodeType() == Node.ELEMENT_NODE)
					pipe((Element)node, h);
				if (node.getNodeType() == Node.TEXT_NODE) {
					XmlCharArrayWriter writer = ((CharacterData)node).getWriter();
					h.characters(writer.getBuffer(), 0, writer.size());
				}
			}
		}
		h.endElement("", e.getName(), "");
	}

	static class EAttributes
		implements Attributes
	{
		private List<Attribute> list;
		/**
		 * Construct using a null list.
		 */
		public EAttributes() {
		}
		/**
		 * Sets the underlying list.
		 */
		public void setList(List<Attribute> list) {
			this.list = list;
		}
		public int getIndex(String qName) {
			if (list == null)
				return -1;
			for (int i = 0; i < list.size(); i++) {
				Attribute a = list.get(i);
				if (a.getName().equals(qName))
					return i;
			}
			return -1;
		}
		public int getIndex(String uri, String localPart) {
			return -1;
		}
		public int getLength() {
			if (list == null)
				return 0;
			return list.size();
		}
		public String getLocalName(int index) {
			return "";
		}
		public String getQName(int index) {
			if (list == null)
				return "";
			Attribute a = list.get(index);
			return a.getName();
		}
		public String getType(int index) {
			return "CDATA";
		}
		public String getType(String qName) {
			return "CDATA";
		}
		public String getType(String uri, String localName) {
			return "";
		}
		public String getURI(int index) {
			return "";
		}
		public String getValue(int index) {
			if (list == null)
				return "";
			Attribute a = list.get(index);
			return a.getValue();
		}
		public String getValue(String qName) {
			if (list == null)
				return "";
			Attribute a;
			for (int i = 0; i < list.size(); i++) {
				a = list.get(i);
				if (a.getName().equals(qName))
					return a.getValue();
			}
			return "";
		}
		public String getValue(String uri, String localName) {
			return "";
		}
		@Override
		public String toString() {
			if (list == null)
				return "";
			StringBuffer sb = new StringBuffer(32);
			for (int i = 0; i < list.size(); i++) {
				sb.append(' ').append(list.get(i));
			}
			return sb.toString();
		}
	}

}
