package tvark.old;

//import java.io.*;
//import java.util.*;
//import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Bayes{
	private Result results;
	private int resultCount=10;
	private int testCount=1000;
	static int actualRes=0;
	private Schedule[] Best;
//	private Schedule bestPagalbinis;
	private XmlFileOut analize;
	private int Best_Bayes;
	
	public Schedule getBest() 
	{				
		double temp=results.getResult(0);
		for (int i=1; i<resultCount; i++){
			 if(temp>results.getResult(i) && results.getResult(i)!=0){
				temp = results.getResult(i);
				Best_Bayes = i;
			}
		}
		return Best[Best_Bayes];
	}

	public Bayes(Schedule initial, Property prop)
	{		
		analize= new XmlFileOut(initial.getFolder()+"/Analisie_Bayes.xml", prop.getRootdir());		
		resultCount = prop.getIter_bayes();		
		
		results =new Result(resultCount);
		Best = new Schedule[resultCount];
		//-------------------------- bayes metodo riboms nustatyti -----------------------
		int bayesX1 = prop.getBayesX1();//System.out.println("Bayes_X1 = "+bayesX1);
		int bayesY1 = prop.getBayesY1();//System.out.println("Bayes_Y1 = "+bayesY1);
		int bayesX2 = prop.getBayesX2();//System.out.println("Bayes_X2 = "+bayesX2);
		int bayesY2 = prop.getBayesY2();//System.out.println("Bayes_Y2 = "+bayesY2);
		
		Range domain = new Range(bayesX1,bayesX2,bayesY1,bayesY2);//Range domain = new Range(1000,5000,1000,5000);
				
			int method_on = prop.getBayes_on();  	// Spausdinimui SA metode
			method_on = 1;							// Spausdinimui SA metode
			prop.setBeyes_on(method_on);			// Spausdinimui SA metode
		
		this.serialize(initial,  prop.getRootdir()+"/"+initial.getFolder()+"/ser.ser");//-----------------------------------
		double coolRate[]; //initTemp[],

		int CurPenalty = 0;
		int pagalbinis_penalty_atminti = 1000000;
		int penalty_help = 0;	
		
		coolRate = new double[1000];
		double pagalbinis = 0.0;
		
		//int as = 0;
		//System.out.println("X2max = "+bayesY2);
		
		for (int i=0; i<1000; i++)
		{	
			pagalbinis = Math.random()*bayesY2;
			if ((pagalbinis >= bayesY1)&&(pagalbinis <= bayesY2))
			{	
				coolRate[i]= pagalbinis;
			}
			else
			{
				pagalbinis = pagalbinis + bayesY1;
				coolRate[i]= pagalbinis;
			}
		    //System.out.println(i+"-tasis coolRate = "+coolRate[i]);
		}
		
//===================== pirmiem 5 rezz gauti ===================================
		for (int i=0; i<5; i++)
		{	
			double skaicius = 1;
			initial = this.readSerialized( prop.getRootdir()+"/"+initial.getFolder()+"/ser.ser");

			System.out.println("Counting initial points");
			results.setPoint(new Point(domain), i); 
			System.out.println("");
			System.out.println("-----------------------");
			System.out.println("pora nr: "+(i+1));
			System.out.println("");
			System.out.println(" initial temperature " + (i+1) +"-tasis = "+ results.getPoint(i).initTemp);
			
		//	int sk = 0;
		//	sk = (((int) results.getPoint(i).initTemp) / 1000)-1;
			//System.out.println(" sk = "+sk);
			skaicius = Math.random()*bayesY2;// * sk;
			
			System.out.println(" cooling rate        " + (i+1) +"-tasis = "+ skaicius);
			System.out.println("-----------------------");
			System.out.println("");
			
			prop.setInit(results.getPoint(i).initTemp);		
			prop.setCool(skaicius);
			prop.setBeyes_on(1);
			
			SA1 temp = new SA1(initial, prop);//buvo originalas
			Best[i] = temp.getBest();			
			results.setResult( Best[i].countPenalty(prop),i);
			int penalty =  Best[i].countPenalty(prop);
			
			if (CurPenalty == 0)
			{ 	
				CurPenalty = penalty;	
			}
	//==================================================bandymui
			if (penalty < CurPenalty) //nepereina!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
			{		
				CurPenalty = penalty;
				prop.setbayes_best(penalty);
			}
	//=====================================================================================
				penalty_help = prop.getbayes_best();
		
				if (pagalbinis_penalty_atminti > penalty_help)
				{
					pagalbinis_penalty_atminti = penalty_help;
					prop.setbayes_best(pagalbinis_penalty_atminti);
				//	System.out.println("ar perstumia kita skaiciu ???? kazkodel atrodo kad ne ??? => "+prop.getbayes_best());
				}
			System.out.println((i+1)+ "-tasis prop.getbayes_best => "+prop.getbayes_best());
		    System.out.println();
	    
			printXML(i, penalty_help);
			results.setResult(prop.getbayes_best(), i); 
			actualRes++;
			
			if((temp!=null) && (i == 4) && (i == resultCount-1))
			{
				prop.setbayes_best(pagalbinis_penalty_atminti);
				temp.pares_bayes();
				initial = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/initial.ser");
			}
		}
		
		SA1 temp = null;
		
//========================================= etapas nuo 5 iteracijos apsisukimo ====================================
		for (int i =actualRes; i< resultCount; i++)
		{   
			double skaicius = 1;
			initial = this.readSerialized( prop.getRootdir()+"/"+initial.getFolder()+"/ser.ser");

			System.out.println("Predicting and counting points");
			Result predictions = predict(testCount, domain, results);
			results.setPoint(predictions.getPoint(minResultNr(predictions)), i);
			//prop.setInit(results.getPoint(i).initTemp);
			//prop.setCool(coolRate[i]);
			System.out.println("");
			System.out.println("-----------------------");
			System.out.println("pora nr: "+(i+1));
			System.out.println("");
			System.out.println(" initial temperature " + (i+1) +"-tasis = "+ results.getPoint(i).initTemp);
			//int sk = 0;
			//sk = (((int) results.getPoint(i).initTemp) / 1000)-1;
			//System.out.println(" sk = "+sk);
			skaicius = Math.random()*bayesY2;
			
			System.out.println(" cooling rate        " + (i+1) +"-tasis = "+ skaicius);
			System.out.println("-----------------------");
			System.out.println("");
			
			prop.setInit(results.getPoint(i).initTemp);		
			prop.setCool(skaicius);
			
			temp = new SA1(initial, prop);
			Best[i] = temp.getBest(); //Best[i] = getBest();			
			results.setResult( Best[i].countPenalty(prop),i);
			int penalty =  Best[i].countPenalty(prop);
			
			if (CurPenalty == 0)
			{ 	
				CurPenalty = penalty;	
			}

	//==================================================bandymui
			if (penalty < CurPenalty) //nepereina!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
			{		
				CurPenalty = penalty;
				prop.setbayes_best(penalty);
			}
	//=====================================================================================
				penalty_help = prop.getbayes_best();
				//System.out.println("=================== is bayes penalty_help =============== " + penalty_help);
				//System.out.println("=================== is bayes pagalbinis_penalty_atminti = " + pagalbinis_penalty_atminti);

				if (pagalbinis_penalty_atminti > penalty_help)
				{
					pagalbinis_penalty_atminti = penalty_help;
					prop.setbayes_best(pagalbinis_penalty_atminti);
				//	System.out.println("ar perstumia kita skaiciu ???? kazkodel atrodo kad ne ??? => "+prop.getbayes_best());
				}
			System.out.println((i+1)+ "-tasis prop.getbayes_best => "+prop.getbayes_best());
		    System.out.println();
		    
			printXML(i, penalty_help);
			results.setResult(prop.getbayes_best(), i); 
			actualRes++;
		}
		
		if(temp!=null)
		{
			prop.setbayes_best(pagalbinis_penalty_atminti);
			//System.out.println("ar perduoda proes spausdinima - prop.getbayes_best => "+prop.getbayes_best());
			temp.pares_bayes();			//System.out.println(" pereina i isvedima Summary_Bayes ");
			initial = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/initial.ser");
		}
		analize.close();
		prop.setBeyes_on(0);
		actualRes = 0;
	}

//----------------------------------------------------
	public Result predict(int count,Range domain, Result data)
	{
		Result ret = new Result(count);
		double Cn = minResult(data) - 1;
		
		for(int i =0; i<count; i++)
		{
			if(domain!=null) ret.setPoint(new Point(domain), i);
			else ret.setPoint(new Point(), i);
			
			double min=(ret.getPoint(i).minus(data.getPoint(0)))/(data.getResult(0) - Cn);
			
			for (int j=1; j<actualRes; j++){
				double temp =(ret.getPoint(i).minus(data.getPoint(j)))/(data.getResult(j) - Cn);
				if(min>temp) min=temp;
			}		
			ret.setResult(minResult(data)-min, i);	
		}
		return ret;
	}

//-------------------------------------------
	public int minResultNr(Result res)
	{
		double temp = res.getResult(0);
		int min = 0;
		
		for (int i=1; i<res.getLength(); i++)
		{
			if(temp>res.getResult(i) && res.getResult(i)!=0)
			{
				temp=res.getResult(i);
				min=i;
			}
		}
		return min;
		
	}
//-----------------------------------------	
	public double minResult(Result res)
	{
		double temp = res.getResult(0);
		int min = 0;
		
		for (int i=1; i<res.getLength(); i++){
			if(temp>res.getResult(i) && res.getResult(i)!=0)
			{
				temp=res.getResult(i);
				min=i;
			}
		}
		
		return res.getResult(min);
		
	}
	
//---------------------------------------------------------	
	public void serialize(Schedule serial, String filename) 
	{
		FileOutputStream fos = null;
		ObjectOutputStream out = null;
		try {
			fos = new FileOutputStream(filename);
			out = new ObjectOutputStream(fos);
			out.writeObject(serial);
			out.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		}

	}

//-----------------------------------------------
	public void printXML(int iter, int penalty)
	{
		  analize.startRow();
		  analize.addTag(Integer.toString(iter));
		  analize.addTag(Integer.toString(penalty));
		  analize.endRow();	  
	}
//-------------------------------------------------------	
	public Schedule readSerialized(String filename) 
	{	
		Schedule ret = new Schedule();

		FileInputStream fis = null;
		ObjectInputStream in = null;
		try {
			fis = new FileInputStream(filename);
			in = new ObjectInputStream(fis);
			ret = (Schedule) in.readObject();
			in.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (ClassNotFoundException ex) {
			ex.printStackTrace();
		}
		return ret;
	}	
}
//----------------------------------------------------
class Result
{
		private double[] result;
		private Point[] points;
		int length;

		Result(int resultCount){
		result=new double[resultCount];
		points = new Point[resultCount];
		length = resultCount;
}
	
	public Point getPoint(int index) 
	{
		return points[index];
	}

	public void setPoint(Point point, int index) 
	{
		this.points[index] = point;
	}

	public double getResult(int index) 
	{
		return result[index];
	}

	public void setResult(double result, int index) 
	{
		this.result[index] = result;
	}
	
	public int getLength() 
	{
		return length;
	}
}
//-------------------------------------------------------------
class Range
{
	double minTemp;
	double maxTemp;
	double minRate;
	double maxRate;
	
	Range(){	
	}
	
	Range(double iTemp, double jTemp, double iRate, double jRate)
	{
		minTemp = iTemp;
		maxTemp = jTemp;
		minRate = iRate;
		maxRate = jRate;	
	}
}
//--------------------------------------------------
class Point
{
	double initTemp;
	double coolRate;
	
	Point(double temp, double rate)
	{
		initTemp = temp;
		coolRate = rate;	
	}
	
	Point(Range domain)
	{
		initTemp=domain.minTemp + Math.random()*(domain.maxTemp-domain.minTemp);
		coolRate=domain.minRate + Math.random()*(domain.maxRate-domain.minRate);
	}
	
	Point()
	{
		initTemp=1+ Math.random()*Integer.MAX_VALUE;
		coolRate=1+ Math.random()*Integer.MAX_VALUE;
	}
//------------------------------------------	
	public double minus(Point p)
	{
		double temp=0;
		temp = Math.pow((p.initTemp-this.initTemp),2)+Math.pow((p.coolRate-this.coolRate),2);
		return temp;
	}
}