/**
 * This class stores the list of controls
 * for a multiply controlled one-bit gate.
 */
public class Controls {
	private int _numBits;//number of bits in circuit
	
	private int _numControls;
	
	private int[]  _bitPositions;//array's length = numControls
	
    //control type is either: 
    //true for n 
    //or 
    //false for nbar=1-n 	
	private Boolean[]  _types;//array's length = numControls
	
/**
 * 
 */	
	public Controls(){
		_numBits = 0;
		_numControls = 0;
		_bitPositions = null;
		_types = null;
	}

/**
 * 
 */	
	public Controls(int numBits, int numControls){
		_numBits = numBits;
		_numControls = numControls;
		_bitPositions = new int[numControls];
		_types = new Boolean[numControls];

	}
/**
 * 
 */	
	public Controls(Controls controls){
		_numBits = controls._numBits;
		_numControls = controls._numControls;
		_bitPositions = controls._bitPositions;
		_types = controls._types;

	}

/**
 * 
 */
	public void setBitPos(int c, int bitPos){
		Throw.If(c<0 || c>=_numControls, 
			"control array index is out of bounds");

		Throw.If(bitPos<0 || bitPos>=_numBits, 
			"control bit position is out of bounds");
	
		_bitPositions[c] = bitPos;
		
	}
/**
 * 
 */
	public void setType(int c, Boolean type){
		Throw.If(c<0 || c>=_numControls, 
			"control array index is out of bounds");
		_types[c] = type;
		
	}
/**
 * 
 */
	public void setControl(int c, int bitPos, Boolean type){
		setBitPos(c, bitPos);
		setType(c, type);
	}
/**
 * 
 */
	public int  getNumControls(){
		return _numControls;
	}	
	
/**
 * 
 */
	public int getBitPos(int c){
		return _bitPositions[c];
	}
/**
 * 
 */
	public Boolean  getType(int c){
		return _types[c];
	}
/**
 * 
 */

	public void checkBitPosAreDecreasing(){
        for(int c=0; c<_numControls-1; c++){
            Throw.If(_bitPositions[c] <= _bitPositions[c+1],
              "controls bitPositions must be in " +
              "strictly decreasing order");
        }		
	}
	
/**
 * 
 */
	public void addP0_padding(int numBits, int numBitsInP0Pad){
		if(numBitsInP0Pad!=0){
			//this throw will help detect if
			//not using addP0_padding()/removeP0_padding()
			//together
			Throw.If(_numBits != numBits,
					"numBits disagreement when enter addP0_padding()");
			_numBits += numBitsInP0Pad;
			
			int newNumControls = _numControls + numBitsInP0Pad;
			int[] newBitPositions = new int[newNumControls];
			Boolean[] newTypes = new Boolean[newNumControls];
			int c;
			int k = _numBits - 1;
			for(c=0; c < numBitsInP0Pad; c++){
				newBitPositions[c] = k;
				newTypes[c] = false;
				k--;
			}
			for(c=numBitsInP0Pad; c < newNumControls; c++){
				newBitPositions[c] = _bitPositions[c - numBitsInP0Pad];
				newTypes[c] = _types[c - numBitsInP0Pad];			
			}
			
			_numControls = newNumControls;
			_bitPositions = newBitPositions;
			_types = newTypes;
		}
		
	}	
/**
 * 
 */
	public void removeP0_padding(int numBitsInP0Pad){
		if(numBitsInP0Pad!=0){
			_numBits -= numBitsInP0Pad;
			
			int newNumControls = _numControls - numBitsInP0Pad;
			int[] newBitPositions = new int[newNumControls];
			Boolean[] newTypes = new Boolean[newNumControls];
			int c;
			for(c=0; c < newNumControls; c++){
				newBitPositions[c] = _bitPositions[c + numBitsInP0Pad];
				newTypes[c] = _types[c + numBitsInP0Pad];			
			}
			
			_numControls = newNumControls;
			_bitPositions = newBitPositions;
			_types = newTypes;
		}
		
	}	
	
}
