package leaf;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

public class OrderedMap<KeyClass extends Object> implements Iterable<KeyClass>
{
	private static final long serialVersionUID = 1L;

	private Vector<KeyClass> order = new Vector<KeyClass>();

	private HashMap<KeyClass, List<Object>> map = new HashMap<KeyClass, List<Object>>();

	public OrderedMap()
	{
	}

	public OrderedMap(Collection<KeyClass> allPrestadores)
	{
		Iterator<KeyClass> iterator = allPrestadores.iterator();
		while(iterator.hasNext())
		{
			KeyClass value = iterator.next();
			this.putLast( value, value );
		}
	}

	public List<Object> getRow( int row )
	{
		return map.get( order.get( row ) );
	}

	public List<Object> getValues( KeyClass key )
	{
		return map.get( key );
	}

	public int rows()
	{
		return order.size();
	}

	public KeyClass getKeyForValue( Object value )
	{
		for( KeyClass key : map.keySet() )
		{
			List<Object> values = map.get( key );
			if( value.equals( values ) )
			{
				return key;
			}
			else
			{
				for( Object currentValue : values )
				{
					if( currentValue.equals( value ) )
					{
						return key;
					}
				}
			}
		}
		return null;
	}

	/**
	 * returns the length of the biggest column
	 * 
	 * @return
	 */
	public int columns()
	{
		int result = 0;
		for( KeyClass key : order )
		{
			result = map.get( key ).size() > result ? map.get( key ).size() : result;
		}
		return result;
	}

	public List<Object> getColumn( int i )
	{
		List<Object> result = new ArrayList<Object>();
		if( order != null && order.size() > 0 )
		{
			for( KeyClass key : order )
			{
				List<Object> row = map.get( key );
				if( row != null && row.size() > 0 )
				{
					result.add( row.get( 0 ) );
				}
				else
				{
					row.add( null );
				}
			}
		}
		return result;
	}

	public KeyClass getFirst()
	{
		return order.isEmpty() ? null : order.get( 0 );
	}

	public Iterator<KeyClass> iterator()
	{
		return order.iterator();
	}

	public boolean containsKey( KeyClass key )
	{
		return map.containsKey( key );
	}

	public Object getValueAt( int row, int column )
	{
		Object result = null;
		if( row < order.size() )
		{
			List<Object> line = map.get( order.get( row ));
			if( column < line.size())
			{
				result = line.get( column );
			}
		}
		return result;
	}

	public void putLast( KeyClass key, Object value )
	{
		List<Object> list;
		if( map.containsKey( key ) )
		{
			list = map.get( key );
		}
		else
		{
			list = new ArrayList<Object>();
			order.add( key );
		}
		list.add( value );
		map.put( key, list );
	}

	public List<Object> remove( Object key )
	{
		order.remove( key );
		return map.remove( key );
	}

	/**
	 * Orders by first column (rows compared as strings)
	 */
	public void order()
	{
		if( order != null && order.size() > 0 )
		{
			HashMap<Object, KeyClass> keyForObject = new HashMap<Object, KeyClass>();
			List<String> sortedList = new ArrayList<String>();
			for( KeyClass key : order )
			{
				List<Object> row = map.get( key );
				Object value = null;
				if( row != null && row.size() > 0 )
				{
					value = row.get( 0 );
					keyForObject.put( value.toString(), key );
					sortedList.add( value.toString() );
				}
			}
			if( sortedList.size() == order.size() )
			{
				Collections.sort( sortedList );
				Vector<KeyClass> newOrder = new Vector<KeyClass>();
				for( String value : sortedList )
				{
					newOrder.add( keyForObject.get( value ) );
				}
				order = newOrder;
			}
		}
	}

	public void addRow( KeyClass key, List<Object> grupo )
	{
		if( key != null && grupo != null )
		{
			order.add( key );
			map.put( key, grupo );
		}
	}

	public void clear()
	{
		order.clear();
		map.clear();
	}

	public void deleteRow( int row )
	{
		if( row < order.size() )
		{
			KeyClass key = order.get( row );
			order.remove( row );
			map.remove( key );
		}
	}

	public KeyClass getKeyForRow( int row )
	{
		KeyClass result = null;
		if( row < order.size() )
		{
			result = order.get( row );
		}
		return result;
	}

	public void setValueAt( int row, int col, Object obj )
	{
		if( row < order.size() )
		{
			List<Object> line = map.get( order.get( row ) );
			if( col < line.size() )
			{
				line.add( col, obj );
			}
		}
	}

	public Object getFirstValue( KeyClass key )
	{
		return getValue( key, 0 );
	}

	public Object getValue( KeyClass key, int i )
	{
		Object result = null;
		if(key != null && order.contains( key))
		{
			List<Object> row = map.get( key );
			if(row != null && row.size() > i)
			{
				result = row.get( i );
			}
		}
		return result;
	}

}
