/**
 * This class creates a new instance of 
 * a Fruit Incidence Matrix (FruitIncMat).
 * The matrix contains blocks for a line, tree, glue and oracle. 
 */
public class FruitIncMat {
	private int  _lineNumBits;
	private int  _treeNumBits;
	private int  _lineDoor;
	private OracleBands _bands;
	private int[][] _matrix;
	
/**
 * lineDoor\in [0, line number of states)
 * is the number of the line node that is connected to the tree
 */
    public FruitIncMat(int lineNumBits, int treeNumBits, 
    		int lineDoor, OracleBands bands    		
    ) {
    	Throw.If(lineNumBits<2 , 
			"lineNumBits of bits must be >= 2");  
    	Throw.If(treeNumBits<2 , 
			"treeNumBits of bits must be >= 2");  
    	_lineNumBits = lineNumBits;    	
    	_treeNumBits = treeNumBits;
    	int lvsNumBits = treeNumBits-1;//lvs = leaves
    	
     	int lineNumRows = 1<<lineNumBits;
       	int treeNumRows = 1<<treeNumBits;
       	int lvsNumRows = 1<<lvsNumBits;
        int numRows = lineNumRows + treeNumRows + lvsNumRows;

                
    	Throw.If(lineDoor<0 || lineDoor>=lineNumRows,
			"line door is out of bounds");
		_lineDoor = lineDoor;
    	Throw.If(bands.getLvsNumBits()!=lvsNumBits, 
			"bands out of bounds");
		_bands = new OracleBands(bands);
    	


        //_matrix automatically initialized to zero
        _matrix = new int[numRows][numRows];
         int row, col;

        LineIncMat lmat = new LineIncMat(lineNumBits);    
        for(row=0; row<lineNumRows; row++){
        	for(col=0; col<lineNumRows; col++){
        		_matrix[row][col] = lmat.getEntry(row, col);
        	}       	
        }

        TreeIncMat tmat = new TreeIncMat(treeNumBits);
        for(row=0; row<treeNumRows; row++){
        	for(col=0; col<treeNumRows; col++){
        		_matrix[lineNumRows + row][lineNumRows + col] = 
        			tmat.getEntry(row, col);
        	}       	
        }

        
        //pair of states that is glued
		//lineNumRows is dud state
        _matrix[lineNumRows+1][lineDoor] = 1;
        _matrix[lineDoor][lineNumRows+1] = 1;
        
        
        
        OracleIncMat omat = new OracleIncMat(treeNumBits, bands);
        for(row=0; row<treeNumRows; row++){
        	for(col=0; col<treeNumRows; col++){
        		_matrix[lineNumRows + lvsNumRows + row]
        		       [lineNumRows + lvsNumRows + col] = 
        			omat.getEntry(row, col);
        	}       	
        }
  	
    }
/**
 * 
 */   
	public String toString(){
       int numRows = _matrix.length;
       String output = "";
       output += "numRows = "+ numRows + '\n';
       int row, col;
       for(row=0; row<numRows; row++){
    	   for(col=0; col<numRows; col++){
    		   output += _matrix[row][col] + " ";
    	   }
    	   output += '\n';
       }
       return output;
   }
/**
 *
 */
	public int getEntry(int row, int col) {
		return _matrix[row][col];
	}
/**
* 
*/    
	public static void main(String[] args){
		int lineNumBits = 2;
		int treeNumBits = 4;
		int lineDoor = 2;
		OracleBands bands = new OracleBands( treeNumBits-1,
				new int[][] {{0,1}, {3,3}, {6,7}});

		System.out.println("lineNumBits, treeNumBits = " +
				lineNumBits + ", " + treeNumBits);
		System.out.println("lineDoor = " + lineDoor);
		System.out.println(bands.toString());
		
		FruitIncMat mat = new FruitIncMat(lineNumBits, treeNumBits, 
	    		lineDoor, bands);
        System.out.println(mat.toString());
      
   }
	
}
