package com.hammurapi.extract;

import java.util.Collections;
import java.util.Map;
import java.util.Set;

import com.hammurapi.extract.ComparisonResult.Type;

/**
 * Extracts value at index.
 * @author Pavel Vlasov.
 *
 * @param <T>
 */
public class IndexedExtractor<T, C> implements Extractor<T, T, C>, Mappable<T,T,C> {
	
	private int idx;

	public IndexedExtractor(int idx) {
		this.idx = idx;
	}

	public Set<Integer> parameterIndices() {
		return Collections.singleton(idx);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + idx;
		return result;
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		IndexedExtractor other = (IndexedExtractor) obj;
		if (idx != other.idx)
			return false;
		return true;
	}


	public T extract(C context, Map<C, Map<Extractor<T, ? super T, C>, ? super T>> cache, T... obj) {
		return obj[idx];
	}

	public boolean isContextDependent() {
		return false;
	}

	@Override
	public String toString() {
		return "IndexedExtractor [idx=" + idx + "]";
	}

	@Override
	public ComparisonResult compareTo(Extractor<T, T, C> other) {
		if (other instanceof IndexedExtractor) {
			int otherIdx = ((IndexedExtractor<T, C>) other).idx;
			if (otherIdx==idx) {
				return ComparisonResult.EQUAL_NM;
			}
			int[] map = new int[otherIdx+1];
			map[otherIdx]= idx;
			return new ComparisonResult(Type.EQUAL, map);
		}
		return ComparisonResult.NOT_EQUAL_NM;
	}			

	@Override
	public double getCost() {
		return 0;
	}

	@Override
	public Extractor<T, T, C> map(int[] map) {
		for (int i=0; i<map.length; ++i) {
			if (map[i]==idx) {
				return new IndexedExtractor<T, C>(i);
			}
		}
		return null;
	}
	
	public int getIndex() {
		return idx;
	}
}
