package org.apache.commons.collections;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * An implementation of {@link HashMap} that is backed by a pair of {@link
 * ArrayList}s. Insertion order is maintained - thus
 * First-In-First-Out.  The entrySet and keySet methods return
 * FIFOSets, also to maintain insertion order.
 *
 * I admittedly don't know how to implement a real HashMap,
 * so this one ignores loadFactor.
 *
 * @author Lance Lavandowska
 **/
public class FIFOMap extends HashMap
{
	ArrayList keySet;
	ArrayList entrySet;
	
	public FIFOMap()
	{
		initializeSets();
	}
	
	public FIFOMap(int initialCapacity)
	{
		initializeSets(initialCapacity);
		
	}
	
	public FIFOMap(int initialCapacity, float loadFactor)
	{
		initializeSets(initialCapacity);
	}
	
	public FIFOMap(Map t)
	{
		initializeSets();

		keySet.addAll(t.keySet());
		entrySet.addAll(t.entrySet());
	}
	
	private void initializeSets()
	{
		initializeSets(0);
	}
	
	private void initializeSets(int initialCapacity)
	{
		keySet = new ArrayList(initialCapacity);
		entrySet = new ArrayList(initialCapacity);
	}
	
	
	public void clear()
	{
		keySet.clear();
		entrySet.clear();
	}
	
	public Object clone()
	{
		return new FIFOMap(this);
	}
	
	public boolean containsKey(Object key)
	{
		return keySet.contains(key);
	}
	
	public boolean containsValue(Object value)
	{
		return entrySet.contains(value);
	}
	
	public Set entrySet()
	{
		return new FIFOSet(entrySet);
	}
	
	public Object get(Object key)
	{
		int keyIndex = keySet.indexOf(key);
		return entrySet.get(keyIndex);
	}
	
	public boolean isEmpty()
	{
		return (keySet.isEmpty() && entrySet.isEmpty());
	}
	
	public Set keySet()
	{
		return new FIFOSet(keySet);
	}
	
	public Object put(Object key, Object value)
	{
		Object previousValue = null;
		int keyIndex = keySet.indexOf(key);
		if (keyIndex > -1)
		{
			previousValue = entrySet.get(keyIndex);
			
			keySet.remove(keyIndex);
			entrySet.remove(keyIndex);
		}
		
		keySet.add(key);
		entrySet.add(value);
		
		return previousValue;
	}
	
	public void putAll(Map t)
	{
		Object key = null;
		Object value = null;
		Iterator i = t.entrySet().iterator();
		while (i.hasNext())
		{
			key = i.next();
			value = t.get(key);
			
			this.put(key, value);
		}
		
	}
	
	public Object remove(Object key)
	{
		Object previousValue = null;
		int keyIndex = keySet.indexOf(key);
		if (keyIndex > -1)
		{
			previousValue = entrySet.get(keyIndex);
			
			keySet.remove(keyIndex);
			entrySet.remove(keyIndex);
		}
		
		return previousValue;
	}
	
	public int size()
	{
		return keySet.size();
	}
	
	public Collection values()
	{
		return (Collection) entrySet;
	}
	
}