/*
 * SEAlgorithm.java
 *
 * Created on Ketvirtadienis, 2007, Sausio 25, 17.09
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package Main.algorithms;


import Main.*;


public class SEAlgorithm extends AbstractAlgorithm
{
	protected IFAlgorithm mIFA;
	protected double[][] mTempMatrix;
	/**
	*  remember unique index of the rezult matrix
	*/
	protected int[] indexes;
	// for tracking reduced UV
	protected int[] indexesClone;
	
	public void solve()
	{
		solve(true);
	}
	
	public void solve(boolean calculateUV)
	{
		mLog.logn("----------------------------------");
		mLog.logn("SEA BEGINS");
		
		if(calculateUV)
		{
			mLog.logn("-- MATRIX U");
			calculateMatrixU();
			outputMatrix(getMatrixU());
			mLog.logn("-- MATRIX V");
			calculateMatrixV();
			outputMatrix(getMatrixV());
		}
		
		result= new double[matrix.length][2];
		fillMatrix(result, -1);
		
		indexes= new int[matrix.length];
		fillIndexes(indexes);
		
		indexesClone= (int[])indexes.clone();
		
		boolean solved= false;
		mTempMatrix= (double[][])matrix.clone();
		mIFA= new IFAlgorithm();
		mIFA.setMatrix(mTempMatrix);
		
		mIFA.setMatrixU(getMatrixU());
		mIFA.setMatrixV(getMatrixV());
		
		do
		{
			mIFA.solve(solved);
			double[][] tempRezult= mIFA.getResult();
			mLog.logn("-- Throwing negative --");
			try{
			solved= !throwNegative(tempRezult);
			}
			catch(Exception e)
			{
				mLog.logn("--SEA ALGORITHM FAILED");
				setSolved(false);
				return;
			}
			if(!solved)
			{
				mLog.logn("-- Setting reduced matrix U --");
				mIFA.setMatrixU(reduceMatrixUV(indexesClone,getMatrixU()));
				mLog.logn("-- Setting reduced matrix V --");
				mIFA.setMatrixV(reduceMatrixUV(indexesClone,getMatrixV()));
			}
			else
			{
				setMatrixU(mIFA.getMatrixU());
				setMatrixV(mIFA.getMatrixV());
				mLog.logn("-- Marging results --");
				fillRestOfRezult(indexesClone,tempRezult);
				
				U= mIFA.U;
				V= mIFA.V;
			}
		}
		while(!solved);
			
		setSolved(true);
		
		mLog.logn("SEA ENDS");
		mLog.logn("----------------------------------");
		
	}
	
	protected void fillMatrix(double[][] m, double value)
	{
		for(int i= 0;i< m.length;i++)
		{
			for(int j= 0;j<m[i].length;j++)
			{
				m[i][j]= value;
			}
		}
	}
	
	protected void fillIndexes(int[] m)
	{
		for(int i= 0;i< m.length;i++)
		{
			m[i]= i;
		}
	}
	
	protected boolean throwNegative(double[][] tempRes) throws IllegalArgumentException
	{
		
		int count= 0;
		for(int i= 0;i<tempRes.length; i++)
		{
			boolean copy= false;
			if(tempRes[i][0]<=0)
			{
				
				copy= true;
				
			}
			if(tempRes[i][1]<=0)
			{
				
				copy= true;
			}
			if(copy)
			{
				result[indexesClone[i]][0]= 0;
				result[indexesClone[i]][1]= 0;
				indexes[ indexesClone[i]]= -1;
				indexesClone[i]= -1;
				count++;
			}
		}
		

		if(count != 0)
		{
			// needed for evauation
			/*if((indexesClone.length == count)
			{
				return false;
			}*/
			/*if((indexesClone.length-count) < 1)
			{
				throw new IllegalArgumentException();
			}*/
			
			int[] tempArray;
			tempArray= new int[indexesClone.length-count];
			int j= 0;
			
			for(int i= 0; i<indexesClone.length;i++)
			{
				if(indexesClone[i] != -1)
				{
					tempArray[j]= indexesClone[i];
					j++;
				}
			}
			indexesClone= tempArray;
			
	//		mLog.logn("Indexes of not removed rows: ");
	//		printArray(indexesClone);
			
			return true;
		}
		//needed for evaluation
		/*else if(count == indexesClone.length)
		{
			indexesClone= new int[0]; 
			return false;
		}*/
		else
			return false;
	}
	
	protected void fillRestOfRezult(int index[], double[][] rezultas)
	{
		for(int i= 0;i<rezultas.length;i++)
		{
			//if(result[i][0]== -1)
			{
				result[index[i]][0]= rezultas[i][0];
				result[index[i]][1]= rezultas[i][1];
			}
	
		}
	}
	
	protected double[][] reduceMatrixUV(int[] index,double[][] m)
	{
		double[][] ret= new double[index.length][]; 
		for(int i= 0;i< index.length;i++)
		{
			ret[i]= reduceRows(index, m[index[i]]);
		}
		return ret;
	}
	
	protected double[] reduceRows(int[] index, double[] m)
    {
		double[] ret= new double[index.length];
		for(int i= 0; i< index.length; i++)
		{
			ret[i]= m[index[i]];
		}
		return ret;
	}
	
	protected void printArray(int[] array)
	{
		for(int i= 0; i<array.length;i++)
		{
			mLog.log(" "+array[i]);
		}
		mLog.logn("");
	}
	
	protected void printArray(double[][] array)
	{
		for(int i= 0; i<array.length;i++)
		{
			for(int j= 0; i<array[i].length;j++)
				mLog.log(" "+array[i][j]);
			mLog.logn("");
		}
		
	}
	
	public IFAlgorithm getIFA()
	{
		return mIFA;
	}
	
	
}
