/******************************************************
 * File: MainWindow.java
 * created 28-Oct-01 12:46:19 PM by egiva
 */


package analyse;
import java.text.*;
import Main.util.*;
import Main.parser.*;
import java.io.*;
import java.util.*;
import Main.data.*;
import java.awt.event.*;
import Main.algorithms.*;
import Main.panels.*;
import javax.swing.border.*;
import java.awt.*;
import javax.swing.*;


public class MainWindow extends JFrame implements Log
{
	private final String ITERATIONS_COUNT= "Iterations count: ";
	private final String INSPECTED_OBJECT_COUNT= "Inspected objects count: ";
	private final String MAX_VALUE= "max: ";
	private final String MIN_VALUE= "min: ";
	private final String VARIABLES= "Variables: ";
	private final String EDIT= "EDIT";
	private final String SET_VALUES= "Set Values";
	private final String SAVE_ANALYSE= "Save Analyse: ";
	private final String ALGORYTHMS= "Algorythms: ";
	private final String FINE= "Fine: ";
	private final String FINE_PROBABILITY= "Algorythms: ";
	private final String EPSILON= "Epsilon: ";
	
	private final String ANALYZE= "ANALYZE";
	
	public static final String DSA= "Direct Search Algorithm";
    public static final String IFA= "Irrelevant Fraud Algorithm";
	public static final String NSCA= "Necessary And Sufficient Conditions";
	public static final String SEA= "Strategy Elimination Algorithm";
	public static final String QSEA= "Quadratic Strategy Elimination Algorithm";
	
	private final String[] ALGORITHMS_LIST=
	{DSA,IFA,SEA, QSEA};
	
	JTextField mIterationsCount;
	JTextField mInspectedObjectsCount;
	JComboBox mVariables;
	
	JTextField mMin;
	JTextField mMax;
	
	JTextField mEpsilon;
	
	JTextField mSaveAnalyse;
	
	JButton mSetValues;
	JButton mEdit;
	
	JTextField mFine;
	JTextField mFineProbability;
	
	JComboBox mAlgorithms;
	
	private static MainWindow mInstance;
	
	AbstractAlgorithm mAlgorithm;
	
	private HashMap mVariablesMap;
	
	AlgorithmPanel mAlgPanel;
	
	
	private MainWindow()
	{
		AbstractAlgorithm.setLog( this );
		
		BoxLayout layout= new BoxLayout(getContentPane(), BoxLayout.Y_AXIS);
		getContentPane().setLayout(layout);
		
		JPanel tmpPanel= new JPanel(new GridLayout(1, 2));
		tmpPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
		tmpPanel.add(new JLabel(ITERATIONS_COUNT));
		tmpPanel.add(mIterationsCount= new JTextField());
		getContentPane().add(tmpPanel);
		
		tmpPanel= new JPanel(new GridLayout(1, 2));
		tmpPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
		tmpPanel.add(new JLabel(INSPECTED_OBJECT_COUNT));
		tmpPanel.add(mInspectedObjectsCount= new JTextField());
		getContentPane().add(tmpPanel);

		mVariablesMap= new HashMap();
		
		mergeVariables(InputDataSlot.DATA_NAMES);
		
		tmpPanel= new JPanel(new GridLayout(2, 3));
		tmpPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
		tmpPanel.add(new JLabel(VARIABLES));
		tmpPanel.add(mVariables= new JComboBox(mVariablesMap.values().toArray()));
			JPanel tmp= new JPanel();
			tmp.setLayout(new GridLayout(1,4));
			tmp.add(new JLabel(MIN_VALUE));
			tmp.add(mMin= new JTextField() );
			tmp.add(new JLabel(MAX_VALUE));
			tmp.add(mMax= new JTextField() );
			tmp.setBorder(new EmptyBorder(5, 11, 6, 12));
		tmpPanel.add(tmp);
		tmpPanel.add(new JPanel());
		tmpPanel.add(mEdit= new JButton(EDIT));
		tmpPanel.add(mSetValues= new JButton(SET_VALUES));
		getContentPane().add(tmpPanel);
		
		tmpPanel= new JPanel(new GridLayout(1, 2));
		tmpPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
		tmpPanel.add(new JLabel(ALGORYTHMS));
		tmpPanel.add(mAlgorithms= new JComboBox(ALGORITHMS_LIST));
		getContentPane().add(tmpPanel);
		
		mAlgorithms.addItemListener(new ItemListener()
		{
			public void itemStateChanged(ItemEvent e)
			{
				AbstractAlgorithm alg= null;
				Object value= mAlgorithms.getSelectedItem();
				if(value.equals(DSA))
				{
					alg= new DSAAlgorithm();
				}
				else if(value.equals(IFA))
				{
					alg= new IFAlgorithm();
				}
				else if(value.equals(SEA))
				{
					alg= new SEAlgorithm();
				}
				else if(value.equals(QSEA))
				{
					alg= new QSEAlgorithm();
				}
				setAlgorithm(alg);				
			}
		}
		);

		tmpPanel= new JPanel(new GridLayout(1, 2));
		tmpPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
		tmpPanel.add(new JLabel(EPSILON));
		tmpPanel.add(mEpsilon= new JTextField());
		getContentPane().add(tmpPanel);
		
		tmpPanel= new AlgorithmPanel();
		mAlgPanel= (AlgorithmPanel)tmpPanel;
		tmpPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
		getContentPane().add(tmpPanel);
		
		tmpPanel= new JPanel(new GridLayout(1, 2));
		tmpPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
		tmpPanel.add(new JLabel(SAVE_ANALYSE));
		tmpPanel.add(mSaveAnalyse= new JTextField());
		getContentPane().add(tmpPanel);
		
		JButton analyze= new JButton(ANALYZE);
		tmpPanel= new JPanel(new GridLayout(1, 1));
		tmpPanel.add(analyze);
		getContentPane().add(tmpPanel);
		analyze.addActionListener( new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				analyze();
			}
		}
		);
		
		
		mEdit.addActionListener( new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				EditColumns col= new EditColumns(new Frame(), "Edit Columns", true ); 
				col.setVisible(true);
				if(col.getStatus() == EditColumns.OK)
				{
					InputDataSlot.updateColumnNames(col.getColumns());
					mergeVariables(InputDataSlot.DATA_NAMES);
					mVariables.setModel(new DefaultComboBoxModel(mVariablesMap.values().toArray()));
				}
			}
		}
		);
		
		mVariables.addItemListener(new ItemListener()
		{
			public void itemStateChanged(ItemEvent e)
			{
				Variable var= (Variable)mVariables.getSelectedItem();
				if(e.getStateChange() == ItemEvent.SELECTED)
				{
					mMax.setText(""+var.max);
					mMin.setText(""+var.min);
				}
			
			}
		}
		);
		
		mSetValues.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent event)
			{
				Variable var= (Variable)mVariables.getSelectedItem();
				
				float value= Float.parseFloat( mMax.getText() );
				var.max= value;
				value= Float.parseFloat( mMin.getText() );
				var.min= value;
			}
		}
		);
		
		mAlgorithms.setSelectedIndex(1);
		mVariables.setSelectedIndex(1);
		
		mSaveAnalyse.setText("d:\\Magistrinis\\analyze.txt");
		mEpsilon.setText(""+ 0);
		
		
	}
	
	static public void main(String arg[])
	{
		//System.setErr(new Main.util.OutputStream());
		//System.setOut(new Main.util.OutputStream());
		MainWindow mw= MainWindow.getInstance();
		mw.pack();
		(mw).setVisible(true);
		
	}
	
	public static MainWindow getInstance()
	{
		if(mInstance == null)
		{
			mInstance= new MainWindow();
		}
		return mInstance;
	}
	
	private void setAlgorithm(AbstractAlgorithm a)
	{
		mAlgorithm= a;
	}
	
	private AbstractAlgorithm getAlgorithm()
	{
		return mAlgorithm;
	}
	
	class Variable
	{
		String name= "";
		double min= 0;
	    double max= 1;
		
		/*public int hashCode()
		{
			return name.hashCode();
		}
		
		public boolean equals(Object obj)
		{
			if(obj instanceof Variable)
			{
				return ((Variable)obj).name.equals(name);
			}
			else if(obj instanceof String)
			{
				return obj.equals(name);
			}
			return false;
		}*/
		
		public String toString()
		{
			return name;
		}
	}
	
	private void addVariable(String name, double min, double max)
	{
		Variable var= new Variable();
		var.name= name;
		var.min= min;
		var.max= max;
		mVariablesMap.put(name, var);
		 
	}
	
	private void mergeVariables(String [] names)
	{
		HashMap tmp= mVariablesMap;
		for(int i= 0; i< names.length; i++)
		{
			addVariable(names[i], 0, 1);
		}
		
		for(Iterator it= tmp.keySet().iterator(); it.hasNext();)
		{
			Variable var= (Variable)tmp.get(it.next());
			
			Variable tempVar;
			if( (tempVar= (Variable)mVariablesMap.get(var)) != null)
			{
				tempVar.min= var.min;
				tempVar.max= var.max;
			}
		}
	}
	
	private void analyze()
	{
		int iterationsCount;
		int inspectedObjectCount;
		float epsilon;
		DataOutputStream mOutputStream= null;
		
		try{
			iterationsCount= Integer.parseInt(mIterationsCount.getText());
			inspectedObjectCount= Integer.parseInt(mInspectedObjectsCount.getText());
			epsilon= Float.parseFloat(mEpsilon.getText());
			
			mOutputStream= new DataOutputStream( new FileOutputStream(mSaveAnalyse.getText()));
			
			EquationsManager.getInstance().parseText(mAlgPanel.getUEquation(), EquationsManager.U_EQUATION);
			EquationsManager.getInstance().parseText(mAlgPanel.getVEquation(), EquationsManager.V_EQUATION);
			
			if(mAlgorithm == null)
			{
				throw new Exception("null algorithm");
			}

			double[][] matrixSolved= new double[iterationsCount][2];
			double[][] UV_D_deal_penalty= new double[iterationsCount][3];
			for(int i= 0; i< matrixSolved.length; i++)
			{
				Arrays.fill(matrixSolved[i], -1d);
			}
			
			for(int i= 0; i< UV_D_deal_penalty.length; i++)
			{
				Arrays.fill(UV_D_deal_penalty[i], -1d);
			}
			
			int counter= 0;
			int evaluatedCounter=0;
			int pureStrategyCounter= 0;
			int UVmaxLessUVstarCounter=0;
		    int UVmaxMoreUVstarCounter=0;
			int UVmaxEqualUVstarCounter=0;
			double mUEpsilonEvarage= 0;
			double mVEpsilonEvarage= 0;
			
			double mUEpsilonMax= 0;
			double mVEpsilonMax= 0;
			double mUmaxVid= 0;
			double mVmaxVid= 0;
			
			for(int i= 0; i< iterationsCount; i++)
			{
				mOutputStream.writeBytes("DUOMENYS PRADZIA. ITERACIJA: "+i+"\n");
				mOutputStream.writeBytes(InputDataSlot.createRepresentationString()+"\n");
				mAlgorithm.setMatrix(createMatrix(inspectedObjectCount));
				outputMatrix(mAlgorithm.getMatrix(), mOutputStream);
				mOutputStream.writeBytes("DUOMENYS PABAIGA\n");
				
				mAlgorithm.solve();
				
				double[][] matrix= null;
				
				if(mAlgorithm.isSolved())
				{
					if(mAlgorithm instanceof QSEAlgorithm && ((QSEAlgorithm)mAlgorithm).isPureStrategy())
					{
						pureStrategyCounter++;
					}
					
					mAlgorithm.solveFineProblem();
					
					UV_D_deal_penalty[i][0]= mAlgorithm.U_deal;
					UV_D_deal_penalty[i][1]= mAlgorithm.V_deal;
					UV_D_deal_penalty[i][2]= mAlgorithm.penalty;

					
					mAlgorithm.calculateMatrixU();
					mAlgorithm.calculateMatrixV();
					double[][] matrixU= mAlgorithm.getMatrixU();
					double[][] matrixV= mAlgorithm.getMatrixV();
					
					/*mOutputStream.writeBytes("Matrica U:\n");
					outputMatrix(matrixU, mOutputStream);
					mOutputStream.writeBytes("Matrica V:\n");
					outputMatrix(matrixV, mOutputStream);*/
					
					double U_A= mAlgorithm.calculateU();
					double V_A= mAlgorithm.calculateV();
					
					mOutputStream.writeBytes("X, Y\n");
		            outputMatrix(mAlgorithm.getResult(), mOutputStream);
					Evaluation evaluation= new Evaluation();
					evaluation.setMatrix(mAlgorithm.getMatrix());
					evaluation.setMatrixXY(mAlgorithm.getResult());
					evaluation.setAlgorithm(mAlgorithm);
					
					double[][] rezult= mAlgorithm.getResult();
					//mAlgorithm.reset();
					
					evaluation.solve();

					mOutputStream.writeBytes("Umax= "+evaluation.U+" Vmax= "+evaluation.V+"\n");
					mOutputStream.writeBytes("U*= "+U_A+" V*= "+V_A+"\n");
					
					mUmaxVid+= evaluation.U;
					mVmaxVid+= evaluation.V;
					
					if(!evaluation.getAlgorithm().isSolved())
					{
						mOutputStream.writeBytes("IVERTINIMO ISRAISKOS SPRENDIMAS NEPAVYKO\n");
						continue;
					}

					counter++;
					
					boolean evaluationFlag= true;
					
					int tmpVal= 0;
					
					if(U_A == (evaluation.U+epsilon)|| (U_A >= (evaluation.U-epsilon) && U_A <= (evaluation.U+epsilon)))
					{
						mOutputStream.writeBytes("U* = Umax+"+epsilon+" ");
						evaluationFlag= evaluationFlag && true;
						tmpVal= 0;
					}
					else if(U_A < (evaluation.U+epsilon))
					{
						mOutputStream.writeBytes("U* < Umax+"+epsilon+" ");
						evaluationFlag= evaluationFlag && false;
					    tmpVal= 1;
					}
					else
					{
						evaluationFlag= evaluationFlag && false;
						mOutputStream.writeBytes("U* > Umax+"+epsilon+" ");
						tmpVal= -1;
					}
					
					if(V_A == (evaluation.V+epsilon) || (V_A >= (evaluation.V-epsilon) && V_A <= (evaluation.V+epsilon)))
					{
						evaluationFlag= evaluationFlag && true;
						mOutputStream.writeBytes("V* = Vmax+"+epsilon);
					}
					else if(V_A < (evaluation.V+epsilon))
					{
						evaluationFlag= evaluationFlag && false;
						mOutputStream.writeBytes("V* < Vmax+"+epsilon);
						if(tmpVal != -1)
						{
							tmpVal= 1;
						}
					}
					else
					{
						evaluationFlag= evaluationFlag && false;
						mOutputStream.writeBytes("V* > Vmax+"+epsilon);
						tmpVal= -1;
					}
					
					if(tmpVal== 0)
					{
						UVmaxEqualUVstarCounter++;
					}
					else if(tmpVal == 1)
					{
						UVmaxMoreUVstarCounter++;
					}
					else if(tmpVal == -1)
					{
						UVmaxLessUVstarCounter++;
					}
					
					mOutputStream.writeBytes("\n");
					
					if(evaluationFlag)
					{
								
						/*double[][] evaluationResult= evaluation.getResult();
						
						matrix= new double[rezult.length][2];
						
						for(int j=0; j< matrix.length; j++)
						{
							matrix[j][0]= rezult[j][0]- evaluationResult[j][0];
							matrix[j][1]= rezult[j][1]- evaluationResult[j][1];
							matrixAvarage[j][0]+= Math.abs(matrix[j][0]);
							matrixAvarage[j][1]+= Math.abs(matrix[j][1]);
						}*/
						
						mOutputStream.writeBytes("IVERTINIMO SALYGA TENKINAMA\n");
						evaluatedCounter++;
						//outputMatrix(matrix, mOutputStream);
					}
					else
					{
						mOutputStream.writeBytes("IVERTINIMAS NEPAVYKO. RASTOS REIKSMES NEATITINKA IVERTINIMO SALYGOS .\n");
						
					}
					
					double tmpU= Math.abs(evaluation.U-U_A);
				    double tmpV= Math.abs(evaluation.V-V_A);
					
					matrixSolved[i][0]= tmpU;
					matrixSolved[i][1]= tmpV;
					
					mUEpsilonEvarage+= tmpU;
					mVEpsilonEvarage+= tmpV;
					
					if(tmpU>mUEpsilonMax)
					{
						mUEpsilonMax= tmpU;
					}
					
					if(tmpV>mVEpsilonMax)
					{
						mVEpsilonMax= tmpV;
					}
				}
				
				else
				{
					mOutputStream.writeBytes("INSPEKTORIAUS ALGORITMAS NEISSIPRENDE. IVERTINIMAS NESKAICIUOTAS.\n");
				}
				
				mOutputStream.writeBytes("\n");
				
				
				//mAlgorithm.solveFineProblem();
				//MainWindow.getInstance().getOutputDataPanel().getOutputModel().setDataAsArray(algorithm.getResult());
				//evaluation(mAlgorithm);
			}
			
			mOutputStream.writeBytes("SKAICIAVIMO NUSTATYTA PAKLAIDA: "+epsilon+"\n");
			mOutputStream.writeBytes("ISSPRESTU ALGORITMU SKAICIUS: "+counter+"\n");
			mOutputStream.writeBytes("TENKINANCIU IVERTINIMO SALYGAS SKAICIUS: "+evaluatedCounter+"\n");
			mOutputStream.writeBytes("GRYNUJU STRATEGIJU SPRENDINIU SKAICIUS: "+pureStrategyCounter+"\n");
			mOutputStream.writeBytes("SKAICIUS U* = Umax ir V* = Vmax: "+UVmaxEqualUVstarCounter+"\n");
			mOutputStream.writeBytes("SKAICIUS U* <= Umax arba V* <= Vmax: "+UVmaxMoreUVstarCounter+"\n");
			mOutputStream.writeBytes("SKAICIUS U* > Umax arba V* > Vmax: "+UVmaxLessUVstarCounter+"\n");
			mOutputStream.writeBytes("|Umax-U*|   |Vmax-V*| \n");
			for(int i= 0; i< matrixSolved.length ; i++)
			{
				mOutputStream.writeBytes(""+i+":  "+matrixSolved[i][0]+"  "+matrixSolved[i][1]+"\n");
			}
			mOutputStream.writeBytes("-------------------------------------------------\n");
			mOutputStream.writeBytes("IVERTINIMO VIDUTINE PAKLAIDA: dUvid dVvid\n");
			if(counter == 0)
			{
				mOutputStream.writeBytes("NESKAICIUOTA\n");
			}
			else
			{
				mOutputStream.writeBytes(mUEpsilonEvarage/(double)counter+"  "+mVEpsilonEvarage/(double)counter+"\n");
				mOutputStream.writeBytes("PASKAICIUOTI VIDUTINIAI Umax_vid Vmax_vid: \n");
				mOutputStream.writeBytes(mUmaxVid/(double)counter+"  "+mVmaxVid/(double)counter+"\n");
			}
			mOutputStream.writeBytes("IVERTINIMO MAKSIMALI PAKLAIDA: dUmax dVmax\n");
			mOutputStream.writeBytes(mUEpsilonMax+"  "+mVEpsilonMax+"\n");
			
			mOutputStream.writeBytes("SUTARTINES Udeal Vdeal IR REIKALINGA MINIMALI BAUDA APSAUGAI:\n");
			outputMatrix(UV_D_deal_penalty, mOutputStream);
			
			//mOutputStream.writeBytes("AVARAGE EVALUTION:\n");
			//outputMatrix(matrixAvarage, mOutputStream);
		
		}
		catch(Exception e)
		{
			if(mOutputStream != null)
			{
				try{
					mOutputStream.close();
				}
				catch(Exception ex)
				{
				}
			}
			
			e.printStackTrace();
		}
		//EquationsManager.getInstance().parseText(mUEquation.getText(), EquationsManager.U_EQUATION);
		//EquationsManager.getInstance().parseText(mVEquation.getText(), EquationsManager.V_EQUATION);
	}
	
	private double[][] createMatrix(int rows)
	{
		double[][] matrix= new double[rows][InputDataSlot.DATA_NAMES.length];
		
		Random random= new Random();
		
		for(int i= 0; i< rows; i++)
		{
			for(int j= 0; j< InputDataSlot.DATA_NAMES.length; j++)
			{
				Variable var= (Variable)mVariablesMap.get(InputDataSlot.DATA_NAMES[j]);
				double top= var.max-var.min;
				double value= random.nextDouble();
				value= value*top;
				matrix[i][j]= value+var.min;
			}
		}
		
		return matrix;
	}
	
	private void outputMatrix(double[][] matrix, java.io.DataOutputStream out) throws IOException
	{
		StringBuffer buffer= new StringBuffer();
		for(int i= 0; i<matrix.length; i++)
		{
			for(int j= 0; j<matrix[i].length; j++)
			{
				buffer.append(matrix[i][j]).append(" ");
			}
			
			buffer.append('\n');
		}
		out.writeBytes( new String(buffer));
	}
	

	/*private double[] evaluation(AbstractAlgorithm a, DataOutputStream mStream)
	{
		
		double[][] matrix= null
		
		
		Evaluation evaluation= new Evaluation();
		evaluation.setMatrix(a.getMatrix());
		evaluation.setMatrixXY(a.getResult());
		evaluation.setAlgorithm(a);
		
		double[][] rezult= a.getResult();
		a.reset();
		
		evaluation.solve();
		
		double[][] evaluationResult= evaluation.getResult();
		
		matrix= new double[rezult.length][2];
		
		for(int i=0; i< matrix.length; i++)
		{
			matrix[i][0]= Math.abs(rezult[i][0]- evaluationResult[i][0]);
			matrix[i][1]= Math.abs(rezult[i][1]- evaluationResult[i][1]);
		}
		
	}*/
	
	public void log(String v)
	{
		System.out.print(v);
	}
	
	public void logn(String v)
	{
		System.out.println(v);
	}
	
	public void logn()
	{
		System.out.println();
	}
	
	
}
