import java.io.FileNotFoundException;

/**
 * This class is the main main method, entry point of QuanFruit
 */
public class FruitMain {
	private String 	_filePrefix;

	private int  _lineNumBits;
	private int  _treeNumBits;
	private int  _lvsNumBits;
	private int  _numBits;
	
    private double 	_strength;
    
	private int  _lineDoor;
	private Pair  _pair;

 	private OracleBands _bands;

	private int  _lineNumTrots;
	private int  _lineSuzukiHalfOrder;
	
	private int  _treeNumTrots;
	
	private int  _metaNumTrots;
	private int  _metaSuzukiHalfOrder;
	
	private int		_lenOfSEO;
	private double 	_error;

/**
 *
 */
	public FruitMain(
	        String 	filePrefix,
	        int lineNumBits,
	        int treeNumBits,
	        double strength,
	        int lineDoor,
			OracleBands bands,
			int  lineNumTrots,
			int  lineSuzukiHalfOrder,			
			int  treeNumTrots,
			int  metaNumTrots,
			int  metaSuzukiHalfOrder)
	{ 
		_filePrefix = filePrefix;
		
		_lineNumBits = lineNumBits;    	
		_treeNumBits = treeNumBits;
		_lvsNumBits = treeNumBits-1;//lvs = leaves
		
	 	int lineNumRows = 1<<lineNumBits;
	   	int treeNumRows = 1<<treeNumBits;
	   	int lvsNumRows = 1<<_lvsNumBits;
	    int numRows = lineNumRows + treeNumRows + lvsNumRows;
	    int numBits = 0;
	    while((1<<numBits) < numRows){numBits++;}
	    _numBits = numBits;
	
		_strength = strength;
	            
		_lineDoor = lineDoor;
		//pair of states that is glued
		//lineNumRows is dud state
		_pair = new Pair(lineNumRows+1, lineDoor);
		
		_bands = new OracleBands(bands);

		_lineNumTrots = lineNumTrots;
		_lineSuzukiHalfOrder = lineSuzukiHalfOrder;			
		_treeNumTrots = treeNumTrots;
		_metaNumTrots = metaNumTrots;
		_metaSuzukiHalfOrder = metaSuzukiHalfOrder;
		
		
    	FruitSEO_writer 	writer = new FruitSEO_writer(
    	        filePrefix,
    	        lineNumBits,
    	        treeNumBits,
    	        strength,
    	        lineDoor,
    			bands,
    			lineNumTrots,
    			lineSuzukiHalfOrder,			
    			treeNumTrots,
    			metaNumTrots,
    			metaSuzukiHalfOrder);
    	
    	FruitIncMat 	incMat = new FruitIncMat(
    			lineNumBits, treeNumBits, 
        		lineDoor, bands);
    	//System.out.println(incMat.toString());
    	double[][] realSymMat = new double[numRows][numRows];    	
    	int row, col;
    	for(row=0; row<numRows; row++){
    		for(col=0; col<numRows; col++){
    			realSymMat[row][col] = strength*incMat.getEntry(row,col);
    		}
    	}
    	ExpiRealSym  expiMat = new ExpiRealSym(realSymMat);
    	//System.out.println(expiMat.toString());
    	
    	SEO_reader	reader = new SEO_reader(
    	    filePrefix + "_qfru",
    	    numBits, 
    	    false); // useSparse
    	_lenOfSEO = reader.getLenOfSEO();
    	//System.out.println(reader.toString());
    	
    	_error = 0.0;
    	for(row=0; row<numRows; row++){
    		for(col=0; col<numRows; col++){
    			_error += Complex.abs(Complex.minus(
    					expiMat.getEntry(row,col), 
    					reader.getEntry(row,col)
    					));
    		}
    	}

    	for(row=numRows; row<(1<<numBits); row++){
    		for(col=0; col<row; col++){
    			_error += Complex.abs(
    					reader.getEntry(row,col)
    					);
    		}
    	}
    	for(col=numRows; col<(1<<numBits); col++){
    		for(row=0; row<col; row++){
    			_error += Complex.abs(
    					reader.getEntry(row,col)
    					);
    		}
    	}
	
    	for(col=numRows; col<(1<<numBits); col++){
    		_error += Complex.abs(Complex.minus(
					Globals.complexOne, reader.getEntry(col,col)
    				));
    	}
   	
 	
    	java.io.PrintWriter   logOut = null;
    	try{
	        java.io.File    logFile = 
	            new java.io.File(filePrefix + "_qfru_log.txt");
	        logOut = new java.io.PrintWriter(logFile);
    	}
    	catch(FileNotFoundException ex){
            ex.printStackTrace();
        }
 /*
public FruitMain(
	        String 	filePrefix,
	        int lineNumBits,
	        int treeNumBits,
	        double strength,
	        int lineDoor,
			OracleBands bands,
			int  lineNumTrots,
			int  lineSuzukiHalfOrder,			
			int  treeNumTrots,
			int  metaNumTrots,
			int  metaSuzukiHalfOrder)
*/
    	logOut.println("Inputs:");
        logOut.println("File Prefix = " + filePrefix);        
        logOut.println("Line: Number of Bits = " + lineNumBits);
        logOut.println("Tree: Number of Bits = " + treeNumBits);
        logOut.println("Coupling Constant = " + strength);
        logOut.println("Line Door = " + lineDoor);
        logOut.println(bands.toString());
        logOut.println("Line: Number of Trots = " + lineNumTrots);   
        logOut.println("Line: Order of Suzuki Approximant = " + 
        		2*lineSuzukiHalfOrder); 
        logOut.println("Tree: Number of Trots = " + treeNumTrots);
        logOut.println("Tree: Order of Approximant is always 3.");
        logOut.println("Meta: Number of Trots = " + metaNumTrots);   
        logOut.println("Meta: Order of Suzuki Approximant = " + 
        		2*metaSuzukiHalfOrder); 
       
        
        logOut.println("");
        logOut.println("Outputs:");
        logOut.println(filePrefix + "_qfru_eng.txt");
        logOut.println(filePrefix + "_qfru_pic.txt");
        logOut.println(filePrefix + "_qfru_log.txt");
        logOut.println("Number of Qubits = " + numBits);
        logOut.println("Number of Elem. Ops. = " + _lenOfSEO);
        logOut.printf("Error = %e\n", _error);
        logOut.close();
   	
	}
/**
 * 
 */
	public int getNumBits() {
		return _numBits;
	}
/**
 *
 */
	public int getLenOfSEO() {
		return _lenOfSEO;
	}
/**
 *
 */
	public double getError(){
		return _error;
	}
/**
 *
 */
    public static void main(String[] args){
    	String 	filePrefix = "test";
		int lineNumBits = 3;
		int treeNumBits = 4;
		double strength = .1;
		int lineDoor = 2;
		OracleBands bands = new OracleBands( treeNumBits-1,
				new int[][] {{0,0},{2,3}});
		int  lineNumTrots = 1;
		int  lineSuzukiHalfOrder = 1;			
		int  treeNumTrots = 1;
		int  metaNumTrots = 1;
		int  metaSuzukiHalfOrder = 1;

		
		
    	FruitMain 	m = new FruitMain(
    	        filePrefix,
    	        lineNumBits,
    	        treeNumBits,
    	        strength,
    	        lineDoor,
    			bands,
    			lineNumTrots,
    			lineSuzukiHalfOrder,			
    			treeNumTrots,
    			metaNumTrots,
    			metaSuzukiHalfOrder);
    	
    	
/*    	
    	System.out.println("expiMat");
    	System.out.println(expiMat.toString());

    	System.out.println("SEO product");
    	System.out.println(reader.toString());
*/
    	System.out.println("error is  " + m._error);
   	

    }
}
