package me.doubledutch.lazyjson.compressor;

import java.util.*;

public class DictionaryCache{
	private String[] data=new String[32767];
	private short next=0;
	private Map<String,Short> dataMap=new HashMap<String,Short>();
	private LinkedHashMap<String,Integer> slidingWindow;
	private final int windowSize;
	private int minRepetitions;

	/**
	 * Create a new dictionary with the given window size and given repetition
	 * requirement before new values are added to the dictionary.
	 *
	 * @param windowSizeArg the size of the sliding window of values
	 * @param minRepetitions the number of times a value must be seen within the sliding window before its added to the dictionary
	 */
	public DictionaryCache(int windowSizeArg,int minRepetitions){
		this.windowSize=windowSizeArg;
		this.minRepetitions=minRepetitions;
		// We are going to use a linked hash map to maintain our sliding window
		slidingWindow=new LinkedHashMap<String,Integer>(windowSize+1, .75F, false){
            protected boolean removeEldestEntry(Map.Entry<String,Integer> eldest){
                return size()>windowSize;                                  
            }
        };
	}

	/**
	 * Returns the value held at a specific location in the dictionary.
	 *
	 * @param index the value to look up
	 * @return the value from the dictionary or null if no such value exists
	 */
	public String get(short index){
		if(index<0)return null;
		if(index>=next)return null;
		return data[index];
	}

	/**
	 * Returns the location of a value in the dictionary if it is present, but
	 * does not increase the sliding window stats or attempt to put the value
	 * in the dictionary.
	 *
	 * @param value the value to lookup
	 * @return the location in the dictionary if the value was present
	 */

	public short get(String value){
		if(dataMap.containsKey(value))return dataMap.get(value);
		return -1;
	}

	/**
	 * Add a new value to the dictionary if we have seen it a certain number
	 * of times within the current sliding window. If not, return -1 and mark
	 * that we saw it. If the value is already in the dictionary, just return
	 * the lookup position.
	 *
	 * @param value the value to add
	 * @return the index of the value in the dictionary of -1 if it wasn't added
	 */
	public short put(String value){
		// Do we already have this value?
		if(dataMap.containsKey(value))return dataMap.get(value);
		// Are we filled up?
		if(next==32767)return -1;
		// Should we add values without actual repetitions?
		if(minRepetitions==0){
			data[next]=value;
			dataMap.put(value,next);
			return next++;
		}
		// Have we seen this value before?
		if(slidingWindow.containsKey(value)){
			int count=slidingWindow.get(value)+1;
			// Does it satisfy the minimum repetition count?
			if(count>minRepetitions){
				slidingWindow.remove(value);
				data[next]=value;
				dataMap.put(value,next);
				return next++;
			}else{
				slidingWindow.put(value,count);
			}
		}else{
			// Add this new value to the map
			slidingWindow.put(value,1);
		}
		return -1;
	}
}
@@ -331,16 +331,46 @@
 titions;
+%0A%09private boolean dirty=false;
 %0A%0A%09/**%0A%09
@@ -1180,24 +1180,246 @@
      %7D;%0A%09%7D%0A%0A
+%09/**%0A%09 * Returns a flag specifying wether or not the dictionary has been modified.%0A%09 *%0A%09 * @return a boolean specifying wether or not the dictionary has been modified%0A%09 */%0A%09public boolean isDirty()%7B%0A%09%09return dirty;%0A%09%7D%0A%0A%09%0A%0A
 %09/**%0A%09 * Ret
@@ -2801,16 +2801,31 @@
 ,next);%0A
+%09%09%09dirty=true;%0A
 %09%09%09retur
@@ -3092,16 +3092,16 @@
 =value;%0A
-
 %09%09%09%09data
@@ -3121,16 +3121,32 @@
 ,next);%0A
+%09%09%09%09dirty=true;%0A
 %09%09%09%09retu

add dirty flag