/* 
 * 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.xmlrpc;

import java.util.Iterator;
import java.util.Map;

/**
 * An "Adapter" or "Wrapper", constructed over an underlying Map
 * object.  This allows for the java.util package Map to be used.
 * If exceptions should be thrown, it is best to create a different
 * wrapper implementation that throws wrapped exceptions.
 * @author Elias Ross
 * @version 1.0
 */
public class MapAdapter
	implements ParamIterator 
{
	Map map;
	Iterator i;

	/** 
	 * Create a MapAdapter around an Map.
	 * @param i Iterator to wrap.
	 */
	public MapAdapter(Map map) {
		this.map = map;
		i = map.keySet().iterator();
	}

	/**
	 * Returns STRUCT_ITERATOR as its type.
	 */
	public int getIteratorType() {
		return STRUCT_ITERATOR;
	}

	/** 
	 * Calls next() on underlying key iterator for the Map.
	 * @return a StructPair object
	 * @throws XmlRpcException if the current key is not a String object
	 */
	public Object next() 
		throws XmlRpcException
	{
		Object o = i.next();
		if (!(o instanceof String))
			throw new XmlRpcException("Expected a String object, not " + o);
		return new StructPairImpl((String)o, map.get(o));
	}
	
	/** 
	 * Calls hasNext() on underlying Iterator.
	 * @return true if hasNext returned true
	 */
	public boolean hasNext() {
		return i.hasNext();
	}

	/** 
	 * Removes the reference to the underlying Iterator, by setting it
	 * to null.  Then, no more methods can be called on this object.
	 */
	public void close() {
		i = null;
	}

	/**
	 * Creates a Map object out of a ParamIterator.  This method works
	 * only if the ParamIterator is a <code>STRUCT_ITERATOR</code>. 
	 */
	public static Map toMap(ParamIterator pi) 
		throws XmlRpcException
	{
		Map m = new java.util.HashMap();
		while (pi.hasNext()) {
			Object o = pi.next();
			if (o instanceof StructPair) {
				StructPair sp = (StructPair)o;
				Object value = sp.getValue();
				if (value instanceof ParamIterator) {
					ParamIterator sub = (ParamIterator)value;
					if (sub.getIteratorType() == STRUCT_ITERATOR) {
						value = MapAdapter.toMap(sub);
					} else
					if (sub.getIteratorType() == ARRAY_ITERATOR) {
						value = IteratorAdapter.toList(sub);
					}
				}
				m.put(sp.getName(), value);
			}
		}
		pi.close();
		return m;
	}

}
