/**
 * 
 */
package csp;

/**
 * @author mohsen
 * 
 */
public interface RelationI {

    /*
     * Permutation Semantics constant SOURCE
     * 
     * @see rename
     */
    public static final int SOURCE = RelationCore.SOURCE;
    /*
     * Permutation Semantics constant TARGET
     * 
     * @see rename
     */
    public static final int TARGET = RelationCore.TARGET;

    /**
     * @return an integer representing the relation number
     */
    public int getRelationNumber();

    /**
     * @param relationNumber
     * @throws IllegalArgumentException
     *             Thrwon if the relation number is invalid according to the
     *             rank
     */
    public void setRelationNumber(int relationNumber) throws IllegalArgumentException;

    /**
     * @return rank of the relation
     */
    public int getRank();

    /**
     * Currently unsupported Usually converting to a higher rank is simple.
     * however converting to a lower rank might require the introduction of
     * auxiliary variables and more than one relation might result from the
     * operation
     * 
     * @param rank
     *            sets the rank of the relation
     * @throws IllegalArgumentException
     */
    public void setRank(int rank) throws IllegalArgumentException;

    /**
     * Returns a magic number associated with a certain truth table column and
     * value The magic number associated with column number 0 of the truth table
     * and value 0 is basically a sequence of alternating 0 and 1 bits, packed
     * together in one integer. The magic number associated with column number 0
     * of the truth table and value 1 is a sequence of alternating 1 and 0 bits,
     * packed together in one integer. In general: (getMagicNumber(n,0) ==
     * ~getMagicNumber(n,1)) For column 1: magic numbers are fromed from
     * sequences of two 0's followed by two 1's For column 2: magic numbers are
     * formed from sequences of four 0's followed by four 1's For column 3:
     * magic numbers are formed from sequeneces of eight 0's followed by eight
     * 1's For column 4:magic numbers are formed from sequeneces of sixteen 0's
     * followed by sixteen 1's There is no other possible columns as long as we
     * are using 32 bit integers
     * 
     * The lenght of the magic number depends on the internally stored relation
     * rank
     * 
     * @param variablePosition
     *            the position of the desired magic number
     * @param value
     *            the value associated with the desired magic number
     * @return
     * @throws IllegalArgumentException
     */
    public int getMagicNumber(int variablePosition, int value) throws IllegalArgumentException;

    /**
     * @return An integer with all of its bits set to 1. The length of the
     *         integer depends on the internally stored rank. <br>
     *         the result is: 2^2^rank-1<br>
     *         Note: the method takes care of the case where 2^2^n is outside
     *         the integer range but 2^2^n-1 is not.
     */
    public int getMask();

    /**
     * Checks if the variable at a given position is irrelevant to the
     * internally stored relation
     * 
     * @param variablePosition
     *            the variable to be checked
     * @return true if the variable at vairablePosition is irrelevant otherwise
     *         returns false
     * @throws IllegalArgumentException
     */
    public boolean isIrrelevant(int variablePosition) throws IllegalArgumentException;

    /**
     * Counts the number of relevantVariables in the relation
     * 
     * @return The number of relevant variables in the relation
     */
    public int numberOfRelevantVariables();

    /**
     * Checks if the relation forces the given variablePosition
     * 
     * @param variablePosition
     *            positon of the varible checked for being forced
     * @return 0 if the given relation forces the given variable to 0 1 if the
     *         given relation forces the given variable to 1 -1 given relation
     *         doesn't forces the given variable
     * @throws IllegalArgumentException
     */
    public int isForced(int variablePosition) throws IllegalArgumentException;

    /**
     * starting at the given startPosition, get the position of the first
     * variable forced by the relation.
     * 
     * @param startPosition
     * @return -1 if nothing is forced the position of the first forced variable
     * @throws IllegalArgumentException
     */
    public int firstForcedVariable(int startPosition) throws IllegalArgumentException;

    /**
     * NMaps one of the variables in a relation i.e. replaces it by it's
     * complement for example: nMapping x in Or(x,y,z) results in: or(!x,y,z)
     * 
     * @param relationNumber
     * @param rank
     *            rank of the given relation
     * @param variablePosition
     *            the variable to be nmapped
     * @return The number of the given relation with the specified variable
     *         nmapped
     * @throws IllegalArgumentException
     */
    public int nMap(int variablePosition) throws IllegalArgumentException;

    /**
     * Reduces a relation by assigning a value to one of its variables
     * 
     * @param relationNumber
     * @param rank
     * @param variablePosition
     * @param value
     * @return
     * @throws IllegalArgumentException
     */
    public int reduce(int variablePosition, int value) throws IllegalArgumentException;

    public int swap(int variablePosition1, int variablePosition2) throws IllegalArgumentException;

    /**
     * permute the variables in the given relationNumber according to the given
     * permutation fix the truth table order after doing the permutation.
     * 
     * @see swap
     * @param relationNumber
     * @param rank
     *            rank of the given relation
     * @param permutationSemantics
     *            specifies how the permutation should be applied. can be either
     *            RelationCore.SOURCE or RelationCore.TARGET for example:
     *            <p>
     *            for the relation: R(v2,v1,v0)
     *            <p>
     *            and the permutation {1,2,0} SOURCE semantics means that v0
     *            goes to position1, v1 goes to position2, v2 goes to position 0
     *            TARGET semantics means that position0 gets v1, position1 gets
     *            v2, position2 gets v0
     * @param permutation
     *            an array of variable positions describing the desired location
     *            of every variables for example:
     *            <p>
     *            for the relation: R(v2,v1,v0)
     *            <p>
     *            and the permutation {1,2,0} means v0 goes to position1, v1
     *            goes to position2, v2 goes to position 0
     * @return the modified relationNumber
     */
    /**
     * @param relationNumber
     * @param rank
     * 
     * @param permutation
     * @return
     */
    public int renme(int permutationSemantics, int... permutation) throws IllegalArgumentException;

    /**
     * returns the number of ones in the given relationNumber
     * 
     * @param relationNumber
     * @param rank
     * @return
     */
    public int ones();

    /**
     * @param s
     * @return the number of rows in the truth table with s 1's
     * @throws IllegalArgumentException
     */
    public int q(int s) throws IllegalArgumentException;
}
