
package net.ranides.assira.test;

import java.io.PrintStream;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import net.ranides.assira.collection.HashComparator;

/**
 *
 * @author msieron
 */
public class TComparator<K> implements HashComparator<K> {
	
	private final Map<K, HGRecord> records = new LinkedHashMap<>();

	public TComparator(TMap.TItems<K,?> items) {
        int i=0;
		for(TMap.TItem<K,?> item : items) {
			records.put(item.key(), new HGRecord(i, i));
            i++;
		}
	}
    
    public TComparator(TCollection.TItems<K> items) {
        int i=0;
		for(TCollection.TItem<K> item : items) {
			records.put(item.value(), new HGRecord(i, i));
            i++;
		}
	}
	
	public TComparator<K> hash(int... hashes) {
		int mi = (int)Math.ceil((double)records.size() / (double)hashes.length);
		int i=0;
		for(HGRecord r : records.values()) {
			r.hash = hashes[i/mi];
			i++;
		}
		return this;
	}
	
	public TComparator<K> hash(int h, K key) {
		records.get(key).hash = h;
		return this;
	}
	
	public TComparator<K> order(int... values) {
		int mi = (int)Math.ceil((double)records.size() / (double)values.length);
		int i=0;
		for(HGRecord r : records.values()) {
			r.order = values[i/mi];
			i++;
		}
		return this;
	}
	
	public TComparator<K> order(int v, K key) {
		records.get(key).order = v;
		return this;
	}
    
    /**
     * @see TMap#urange(int, int) 
     * @return 
     */
    public TComparator<K> uorder() {
        int i=0;
        Iterator<HGRecord> iterator = records.values().iterator();
        while(true) {
            if(!iterator.hasNext()) { break; }
            iterator.next().set(i, i);
            
            if(!iterator.hasNext()) { break; }
            iterator.next().set(i, i);    // full collision
            
            if(!iterator.hasNext()) { break; }
            iterator.next().set(i, i+1);  // hash collision
            
            i+=2;
        }
        return this;
    }
	
	@Override
	public int hashCode(K object) {
		return records.get(object).hash;
	}
    
    public int[] hashCodes(TMap.TItems<K,?> items) {
        int[] array = new int[items.data.size()];
        for(int i=0; i<array.length; i++) {
            array[i] = hashCode(items.at(i).key());
        }
		return array;
	}
    
    public int[] hashCodes(TCollection.TItems<K> items) {
        int[] array = new int[items.data.size()];
        for(int i=0; i<array.length; i++) {
            array[i] = hashCode(items.at(i).value());
        }
		return array;
	}

	@Override
	public int compare(K o1, K o2) {
		return records.get(o1).order - records.get(o2).order;
	}

	public void dump(PrintStream out) {
		int i=0;
		for(HGRecord r : records.values()) {
			out.printf("%4d. %4d : %4d%n", i++, r.hash, r.order);
		}
	}
	
	private static final class HGRecord {
		
		public int hash;
		
		public int order;

		public HGRecord(int hash, int order) {
            set(hash, order);
		}
        
        public HGRecord set(int hash, int order) {
            this.hash = hash;
            this.order = order;
            return this;
        }

	}

}
