package com.hammurapi.extract;

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


/**
 * Predicate which always evaluates to true. This predicate is primarily used for
 * comparison 
 * @author Pavel Vlasov
 *
 * @param <T>
 * @param <C>
 */
public class True<T, C> implements Predicate<T, C> {
	
	private True() {
		// Singleton
	}
	
	private static True<?, ?> INSTANCE = new True<Object, Object>();
	
	@SuppressWarnings("unchecked")
	public static <T, C> True<T, C> getInstance() {
		return (True<T, C>) INSTANCE;
	}

	public ComparisonResult compareTo(Extractor<T, Boolean, C> otherPredicate) {
		if (otherPredicate instanceof True) {
			return ComparisonResult.EQUAL_NM;
		}
		
		if (otherPredicate instanceof False) {
			return ComparisonResult.OPPOSITE_NM;
		}
		
		
		if (otherPredicate == null) {
			return ComparisonResult.NOT_EQUAL_NM;
		}

		if (otherPredicate instanceof Constant) {
			if (Boolean.TRUE.equals(((Constant) otherPredicate).getValue())) {
				return ComparisonResult.EQUAL_NM;
			}
			if (Boolean.FALSE.equals(((Constant) otherPredicate).getValue())) {
				return ComparisonResult.OPPOSITE_NM;
			}
		}
		
		ComparisonResult cr = otherPredicate.compareTo(this);
		switch (cr.getType()) {
		case EQUAL:
		case NOT_EQUAL:
		case OPPOSITE:
			return cr;
		case LESS_RESTRICTIVE:
			return ComparisonResult.MORE_RESTRICTIVE_NM;
		case MORE_RESTRICTIVE:
			return ComparisonResult.LESS_RESTRICTIVE_NM;
		case OPPOSITE_LESS_RESTRICTIVE:
			return ComparisonResult.OPPOSITE_MORE_RESTRICTIVE_NM;
		case OPPOSITE_MORE_RESTRICTIVE:
			return ComparisonResult.OPPOSITE_LESS_RESTRICTIVE_NM;
		default:
			throw new IllegalArgumentException("Unexpected comparison type: "+cr.getType());
		}
	}

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

	public boolean isContextDependent() {
		return false;
	}

	public Set<Integer> parameterIndices() {
		return Collections.emptySet();
	}
	
	@Override
	public String toString() {
		return getClass().getName();
	}
	
	@Override
	public double getCost() {
		return 0;
	}

}
