package de.dhbwstuttgart.typeinference.unify.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * A pair which contains two types and an operator, e.q. (Integer <. a).
 * @author Florian Steurer
 */
public class UnifyPair {
	
	/**
	 * The type on the left hand side of the pair.
	 */
	private final UnifyType lhs;
	
	/**
	 * The type on the right hand side of the pair.
	 */
	private final UnifyType rhs;
	
	/**
	 * The operator that determines the relation between the left and right hand side type.
	 */
	private PairOperator pairOp;
	
	private final int hashCode;
	
	/**
	 * Creates a new instance of the pair.
	 * @param lhs The type on the left hand side of the pair.
	 * @param rhs The type on the right hand side of the pair.
	 * @param op The operator that determines the relation between the left and right hand side type.
	 */
	public UnifyPair(UnifyType lhs, UnifyType rhs, PairOperator op) {
		this.lhs = lhs;
		this.rhs = rhs;
		pairOp = op;
		
		// Caching hashcode
		hashCode = 17 + 31 * lhs.hashCode() + 31 * rhs.hashCode() + 31 * pairOp.hashCode();
	}	
	
	/**
	 * Returns the type on the left hand side of the pair.
	 */
	public UnifyType getLhsType() {
		return lhs;
	}
	
	/**
	 * Returns the type on the right hand side of the pair.
	 */
	public UnifyType getRhsType() {
		return rhs;
	}
	
	/**
	 * Returns the operator that determines the relation between the left and right hand side type.
	 */
	public PairOperator getPairOp() {
		return pairOp;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(!(obj instanceof UnifyPair))
			return false;
		
		if(obj.hashCode() != this.hashCode())
			return false;

		UnifyPair other = (UnifyPair) obj;
		
		return other.getPairOp() == pairOp 
				&& other.getLhsType().equals(lhs) 
				&& other.getRhsType().equals(rhs);
	}

	@Override
	public int hashCode() {
		return hashCode;
	}
	
	@Override
	public String toString() {
		return "(" + lhs + " " + pairOp + " " + rhs + ")";
	}

	public List<? extends PlaceholderType> getInvolvedPlaceholderTypes() {
		ArrayList<PlaceholderType> ret = new ArrayList<>();
		ret.addAll(lhs.getInvolvedPlaceholderTypes());
		ret.addAll(rhs.getInvolvedPlaceholderTypes());
		return ret;
	}
}


