package org.jumbune.datavalidation;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;

/**
 * A MultiValueTreeMap allows Map to have more than one value for a key.
 * The multiple values for a key if present will be sorted based on the Comparator<V>.
 * MultiValueTreeMap is not synchronized and is not thread-safe

 * @param <K>
 * @param <V>
 */
public class MultiValueTreeMap<K,V> extends HashMap<K,TreeMap<V, LinkedList<V>>> implements Cloneable, java.io.Serializable {

	private static final long serialVersionUID = -7316106923870914861L;

	private static final boolean lineSeparatorInToString = false;
	
	private int MAX_STORED_ELEMENTS;

	public MultiValueTreeMap(int maxSortedElements){
		super();
		MAX_STORED_ELEMENTS = maxSortedElements;
	}

	/**
	 * Adds the value to the collection associated with the given key
	 * @param reference
	 * @param value
	 */
	public void add(K reference, V value){
		TreeMap<V, LinkedList<V>> innerMap;
		innerMap = get(reference);
		LinkedList<V> list;
		if(innerMap!=null){
			list = innerMap.get(value);
			if(list!=null){
				list.add(value);
			}else{
				list = new LinkedList<V>();
				innerMap.put(value, list);
				list.add(value);
			}
		}else {
			innerMap = new TreeMap<V, LinkedList<V>>();
			put(reference, innerMap);
			list = new LinkedList<V>();
			list.add(value);
			innerMap.put(value, list);
		}
		if (innerMap.size() > MAX_STORED_ELEMENTS){
			innerMap.remove(innerMap.lastKey());
		}
	}

	/**
	 * Given the reference returns the collection of linked values. The collector iterator returns the values in ascending order
     * of the corresponding keys.
	 * @param reference
	 * @return sorted map containing linked values
	 */
	public List<V> getAllElements(K reference){
		List<V> returnedList = null;
		if(containsKey(reference)){
			returnedList = new LinkedList<V>();
			TreeMap<V, LinkedList<V>> innerMap = get(reference);
			for(LinkedList<V> list: innerMap.values()){
				for(V t: list){
					returnedList.add(t);
				}
			}
			if(returnedList.size()>MAX_STORED_ELEMENTS){
				return returnedList.subList(0, MAX_STORED_ELEMENTS);
			}	
		}
		return returnedList;
	}

	public String toString(){
		StringBuilder b = new StringBuilder();
		for(K reference: keySet()){
			b.append("\nReference -"+reference);
			TreeMap<V, LinkedList<V>> innerMap = get(reference);
			for(List<V> list : innerMap.values()){
				b.append(System.lineSeparator());
				for(V entry:list){
					if(lineSeparatorInToString){
						if(entry!=null){
							b.append( entry  );						
						}
						b.append(System.lineSeparator());
					}else{
						b.append("[" + entry + "], " );					
					}
				}
			}
		}
		return b.toString();
	}
	
	public void clear(){
		super.clear();
	}
	
	
}