package tvark.old;

import java.io.*;
import java.util.*;

public class SA1 {
	private Schedule initial;
	private Schedule current;
	private Schedule bestPagalbinis;
	private Schedule best;
	
	private ScheduleData data;
	private XmlFileOut analize, summary;
	private Teacher[] teachers;
//	private Student[] students;
	private Property prop;

	private int PStud = 5, PTeach = 8, POff= 10,  PMax =5, MaxLimit=11;
	private double prob=0.5;

	public SA1(Schedule start,Property prop) {
		this.prop = prop;
		this.PTeach= prop.getPTeach();
		this.PStud=prop.getPStud();
		this.POff = prop.getPOff();
		this.PMax = prop.getPMax();
		this.MaxLimit=prop.getMaxLimit();
		int  method_on = prop.getBayes_on();
		
		if(method_on == 0)
		{
			analize= new XmlFileOut(start.getFolder()+"/Analise_SA.xml", prop.getRootdir());
			summary= new XmlFileOut(start.getFolder()+"/Summary_SA.xml", prop.getRootdir());
		}
		else { summary= new XmlFileOut(start.getFolder()+"/Summary_Bayes.xml", prop.getRootdir()); }
		
	//	System.out.println();
	//	System.out.println();
		System.out.println();
		System.out.println("Starting Optimization Process... ");
		
		data = start.getData();
		teachers = data.getTeachers();
//		students = data.getStudents();
		initial = start.clone();		
		serialize(initial, prop.getRootdir()+"/"+initial.getFolder()+"/initial.ser");	
		
		current = start;
		best = new Schedule();		
		bestPagalbinis = new Schedule(); 

		System.out.println("Data collected... Process Started... ");

	
		int iterations = 0;
		int n = 0;		
		int Penalty = current.countPenalty(prop);
		int lastPenalty = Penalty;//perdejau nuo originalo
		prop.setPPInitial(Penalty);
		
		System.out.println();
		System.out.println("Starting penalty = "+Penalty);
		System.out.println();
		//System.out.println();
		
		if(method_on == 0)
		{	printXML(iterations, Penalty);
			
			if (prop.getPPInitial() >= Penalty)
				if (prop.getPPInitial() > Penalty)
				{
					prop.setPPInitial(Penalty);
					prop.setbayes_best(prop.getPPInitial());
					bestPagalbinis = best;								
					serialize(bestPagalbinis, prop.getRootdir()+"/"+initial.getFolder()+"/bestPagalbinis.ser");
					System.out.println("kaip elgiasi bestA = " + bestPagalbinis.countPenalty(prop));
				}
		}
		
		int CurPenalty = 0;
		best = current.clone();
		bestPagalbinis = best;
		serialize(best, prop.getRootdir()+"/"+initial.getFolder()+"/best.ser");		
		serialize(bestPagalbinis, prop.getRootdir()+"/"+initial.getFolder()+"/bestPagalbinis.ser");
		prop.setbayes_best(1000000);
		
		
		
		//-----------------------------------------
		for (int i = 0; i < prop.getIter1(); i++) 
		{
//			System.out.println("iteracija........"+i);
			if (iterations >= prop.getIter1())break;
			

	//		iterations++; //mano
			
			for (int j = 0; j < teachers.length; j++) 
			{
				boolean inFlag =false;
				PointL[] wind = current.findTeachWindow(j);
		
				iterations++; // buvo cia
					
				if (iterations >= prop.getIter1())break;
								//buvo randomas probability
								//=============  seedui uzdeti =========================== 
								Random rnd = new Random();
								//rnd.setSeed(System.currentTimeMillis());
								double ProbTest = rnd.nextDouble();//rnd.nextInt();
								//System.out.println("   ------------- intervalo riba = "+ProbTest);
								//========================================================		
			for(int w=0; w< wind.length; w++)
			{						
	
				if (wind[w].isPointL()) 
				{   closeWindow(j, wind[w]);
					if(!inFlag)
					{
						n++;
						inFlag=true;
						if(method_on == 0)
						{	printXML(iterations, Penalty); 
							
						if (prop.getPPInitial() >= Penalty)
							if (prop.getPPInitial() > Penalty)
							{
								prop.setPPInitial(Penalty);
								prop.setbayes_best(prop.getPPInitial());
								bestPagalbinis = best;								
								serialize(bestPagalbinis, prop.getRootdir()+"/"+initial.getFolder()+"/bestPagalbinis.ser");
							}
						}
					}
				}
							
				//current_help = current; //pidejau bandymi	
				CurPenalty = current.countPenalty(prop);   
				
				//------------------------------------ jei dabartinis yra geresnis
    			if ((Penalty > CurPenalty) && (lastPenalty > CurPenalty)) // if (Penalty > CurPenalty)//originalas
				{
					n = 0;
					System.out.println("						Got better: "+ (Penalty-CurPenalty)+ " points");					
					best = current.clone();
					serialize(best, prop.getRootdir()+"/"+initial.getFolder()+"/best.ser");
					Penalty = CurPenalty;
					lastPenalty=CurPenalty;
					prop.setbayes_best(Penalty);
				} 
				
				int h= CurPenalty-lastPenalty;
				
				if(h>0)
				{
					//double log = ((-h)*Math.log(1+prop.getCool()*prop.getIter1()))/prop.getInit();
					double log = ((-h)*Math.log(1+prop.getCool()*i))/prop.getInit();
					prob = Math.pow(Math.E,log);
					
				} 
				else 
				{	prob=1;		}	
				
				if((h>0) && (ProbTest>prob)) //if((lastPenalty < CurPenalty) && ProbTest<prob)
				//================================!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!==========================
				{	//System.out.println(" H = "+h+ "   ==============   >>>  "+ProbTest+" > "+prob);
					System.out.println("                            Got Worse with probability: " + (lastPenalty-CurPenalty)+ " Points");		
					lastPenalty=CurPenalty;
				
					{
						best = current.clone();
						serialize(best, prop.getRootdir()+"/"+initial.getFolder()+"/best.ser");					
						Penalty = lastPenalty;
						prop.setbayes_best(Penalty);
					}	
				} 
				else 
				{
					current.UnDoMove();
				}
			}	
				CurPenalty = current.countPenalty(prop);  
				
				int[] off = teachers[j].getOff();
				if (off[0]!=0 ) 
				{
					if(!inFlag)
					{
						n++;
						inFlag=true;
						if(method_on == 0)
						{
							printXML(iterations, Penalty); // buvo originalas
							
							if (prop.getPPInitial() >= Penalty)
								if (prop.getPPInitial() > Penalty)
								{
									prop.setPPInitial(Penalty);
									prop.setbayes_best(prop.getPPInitial());
									bestPagalbinis = best;
									serialize(bestPagalbinis, prop.getRootdir()+"/"+initial.getFolder()+"/bestPagalbinis.ser");
								}
						}
					}
					
					boolean flag =false;
					for(int z=0; z<off.length; z++)
					{						
						for (int lesson=0; lesson<current.getLpd(); lesson++)
						{	
							if(off[z]!=0 && current.getData().getTeachers()[j].isBusy(off[z]-1, lesson)&& !flag)
							{							
								current.FreeDay(teachers[j].getNr(), new PointL(off[z]-1, lesson,0), prop);
								flag=false;
							}
						}	
					}
				}
				CurPenalty = current.countPenalty(prop);   
				
				//------------------------------------ jei dabardinis yra geresnis
    			if ((Penalty > CurPenalty) && (lastPenalty > CurPenalty)) // if (Penalty > CurPenalty)//originalas
				{
					n = 0;
					System.out.println("						Got better: "+ (Penalty-CurPenalty)+ " points");					
					best = current.clone();
					serialize(best, prop.getRootdir()+"/"+initial.getFolder()+"/best.ser");
					Penalty = CurPenalty;
					lastPenalty=CurPenalty;
					prop.setbayes_best(Penalty);
				} 
				
				int h= CurPenalty-lastPenalty;
				
				if(h>0)
				{
					//double log = ((-h)*Math.log(1+prop.getCool()*prop.getIter1()))/prop.getInit();
					double log = ((-h)*Math.log(1+prop.getCool()*i))/prop.getInit();
					prob = Math.pow(Math.E,log);
					
				} 
				else 
				{	prob=1;		}	
				
				if((h>0) && (ProbTest>prob)) //if((lastPenalty < CurPenalty) && ProbTest<prob)
				//================================!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!==========================
				{	//System.out.println(" H = "+h+ "   ==============   >>>  "+ProbTest+" > "+prob);
					System.out.println("                            Got Worse with probability: " + (lastPenalty-CurPenalty)+ " Points");
					lastPenalty=CurPenalty;
					{
						best = current.clone();
						serialize(best, prop.getRootdir()+"/"+initial.getFolder()+"/best.ser");					
						Penalty = lastPenalty;
						prop.setbayes_best(Penalty);
					}	
				} 
				else 
				{
					current.UnDoMove();
				}						
				lastPenalty=CurPenalty;	
		// for mokytoju pabaiga		
			}
			bestPagalbinis = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/bestPagalbinis.ser"); 
		}
		prop.setbayes_best(prop.getPPInitial());

		initial = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/initial.ser");
		best = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/best.ser");
		bestPagalbinis = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/bestPagalbinis.ser");
		
		System.out.println();
		System.out.println();
		System.out.println("SA po optimizavimo best.countPenalty(prop) = "+best.countPenalty(prop));
		prop.setbayes_best(best.countPenalty(prop));
		System.out.println("SA po optimizavimo prop.getbayes_best = " + prop.getbayes_best());
		System.out.println("SA po optimizavimo bestPagalbinis.countPenalty(prop) = "+bestPagalbinis.countPenalty(prop));
		System.out.println();
		
		if (prop.getbayes_best() >= bestPagalbinis.countPenalty(prop))
		{
			prop.setbayes_best(bestPagalbinis.countPenalty(prop));
			System.out.println();
			System.out.println("jei vykdoma salyga if (prop.getbayes_best() >= bestPagalbinis.countPenalty(prop)) ===>");
			System.out.println();
			System.out.println("SA po optimizavimo prop.getbayes_best = " + prop.getbayes_best());
			System.out.println("SA po optimizavimo bestPagalbinis.countPenalty(prop) = "+bestPagalbinis.countPenalty(prop));
		}
		
		System.out.println();
		
		
		if (best.countPenalty(prop) > bestPagalbinis.countPenalty(prop))
		{
			best = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/bestPagalbinis.ser");
		}
		
		// Spausdinimui SA metode
		if (method_on == 0)
		{
			pares_SA();
		}
		prop.setbayes_best_current(best.countPenalty(prop));

	}
//-------------------------------------------------	
	public void pares_SA()
	{
		
		initial = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/initial.ser");
		best = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/best.ser");
		System.out.println("                  spausdinime SA                ;");
		System.out.println("best.countPenalty(prop) = "+best.countPenalty(prop));
		System.out.println("bestPagalbinis.countPenalty(prop) = "+bestPagalbinis.countPenalty(prop));
		
		if (best.countPenalty(prop) > bestPagalbinis.countPenalty(prop))
		{
			best = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/bestPagalbinis.ser");
			System.out.println("ar cia ieina SA_pares??? = "+best.countPenalty(prop));
		}
		
						
		System.out.print("Testing Teachers: ");
		if(best.testTeach()){ System.out.println("Pass");
		}else {
			System.out.println("Fail");
		}
		
		System.out.print("Testing Students: ");
		if(best.testStud()){ System.out.println("Pass");
		}else {
			System.out.println("Fail");
		}
		System.out.println("Process Finished... ");
		printXML("Fixed SA Summary: ");
		printXML("Optimized by Teachers : Penalty for Teacher Window - "+PTeach+ "; Students window - "+PStud+";");
		printXML("                        Students window - "+PStud+";");
		printXML("Penalty for working hour on the day off "+POff+" Penalty for Hour Limit: "+ PMax);
		printXML("Iterations:        SA     " + prop.getIter1());
		printXML("initial temperature   X1  " + prop.getInit());
		printXML("initial cooling rate  X2  " + prop.getCool());
		printXML("");
		printXML("Teacher Windows Initial:  " + initial.teachWindow());
		printXML("Teacher Windows Best:     " + best.teachWindow());
		printXML("Student Windows Initial:  " + initial.studWindow());
		printXML("Student Windows Best:     " + best.studWindow());
		printXML("Teacher OFF Initial:     " + initial.countOff());
		printXML("Teacher OFF Best:     " + best.countOff());
		printXML("Over Max Limit Initial:  " + initial.overMaxLimit(MaxLimit));
		printXML("Over Max Limit Best:     " + best.overMaxLimit(MaxLimit));
		printXML("Initial Penalty Points............" + initial.countPenalty(prop));
		printXML("Optimized Penalty Points.........." + best.countPenalty(prop));
		System.out.println("SA penalty spaudinime = "+ best.countPenalty(prop));
		best.printSubjGroupsXML("SubjGroups_optimal.xml");
		best.printSubjectsXML("Subjects_optimal");
		best.printGroupsXML("Groups_optimal");
		best.printTeachersXML("Teacher_optimal");
		analize.close();
		summary.close();


		File f = new File(prop.getRootdir()+"/"+best.getFolder()+"/students_optimized");
		if (f.mkdir()) {
			System.out.println("Dir /"+best.getFolder()+"/students_optimized Created");
		} else {
			System.out
					.println("Dir /"+best.getFolder()+"/students_optimized NOT Created OR it already  Exists");
		}
		for (int i = 0; i < data.getStudents().length; i++) {
			best.printStudentXML(data.getStudents()[i], "students_optimized");
		}

		f = new File(prop.getRootdir()+"/"+best.getFolder()+"/teachers_optimized");
		if (f.mkdir()) {
			System.out.println("Dir /"+best.getFolder()+"/teachers_optimized Created");
		} else {
			System.out
					.println("Dir /"+best.getFolder()+"/teachers_optimized NOT Created OR it already Exists");
		}
		for (int i = 0; i < data.getTeachers().length; i++) {
			best.printTeacherXML(data.getTeachers()[i], "teachers_optimized");
		}
		
		f = new File(prop.getRootdir()+"/"+best.getFolder()+"/rooms_optimized");
		if (f.mkdir()) 
		{
			System.out.println("Dir /"+best.getFolder()+"/rooms_optimized Created");
		} else {
			System.out.println("Dir /"+best.getFolder()+"/rooms_optimized NOT Created OR it already Exists");
		}
		for (int i = 0; i < data.getRooms().length; i++) 
		{
			best.printRoomXML(data.getRooms()[i], "rooms_optimized");
		}
	}
//-----------------------------------------------------------------------------	
	public void pares_bayes(){		
		initial = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/initial.ser");
		best = readSerialized(prop.getRootdir()+"/"+initial.getFolder()+"/best.ser");
		//System.out.println("                 spausdiname                ");
		//System.out.println("------------------------------------------- is bayes best.countPenalty(prop) = "+best.countPenalty(prop));
		System.out.println("------------------------------------------- is Bayes prp.getbayes_best() = "+prop.getbayes_best());
		
		System.out.print("Testing Teachers: ");
		if(best.testTeach()){ System.out.println("Pass");
		}else {
			System.out.println("Fail");
		}
		
		System.out.print("Testing Students: ");
		if(best.testStud()){ System.out.println("Pass");
		}else {
			System.out.println("Fail");
		}
		

		System.out.println("Process Finished... ");
		printXML("Fixed Bayes Summary: ");
		printXML("Optimized by Teachers : Penalty for Teacher Window - "+PTeach+ "; Students window - "+PStud+";");
		printXML("                        Students window - "+PStud+";");
		printXML("Penalty for working hour on the day off "+POff+" Penalty for Hour Limit: "+ PMax);
		printXML("Iterations:        SA     " + prop.getIter1());
		printXML("Iterations:        BAYES  " + prop.getIter_bayes());
		printXML("");
		printXML("    Parameters of Bayes: ");
		printXML(" X1(min) = "+prop.getBayesX1()+"  X2(min) = "+prop.getBayesY1());
		printXML(" X1(max) = "+prop.getBayesX2()+"  X2(max) = "+prop.getBayesY2());
		printXML("");
		printXML("Teacher Windows Initial:  " + initial.teachWindow());
		printXML("Teacher Windows Best:     " + best.teachWindow());
		printXML("Student Windows Initial:  " + initial.studWindow());
		printXML("Student Windows Best:     " + best.studWindow());
		printXML("Teacher OFF Initial:     " + initial.countOff());
		printXML("Teacher OFF Best:     " + best.countOff());
		printXML("Over Max Limit Initial:  " + initial.overMaxLimit(MaxLimit));
		printXML("Over Max Limit Best:     " + best.overMaxLimit(MaxLimit));
		printXML("Initial Penalty Points............"
			+ initial.countPenalty(prop));
		printXML("Optimized Penalty Points.........." + prop.getbayes_best());
		
		best.printSubjGroupsXML("SubjGroups_optimal.xml");
		best.printSubjectsXML("Subjects_optimal");
		best.printGroupsXML("Groups_optimal");
		best.printTeachersXML("Teacher_optimal");
		summary.close();
		
				int method_on = prop.getBayes_on();  	// Spausdinimui SA metode
				method_on = 0;							// Spausdinimui SA metode
				prop.setBeyes_on(method_on);			// Spausdinimui SA metode

		File f = new File(prop.getRootdir()+"/"+best.getFolder()+"/students_optimized");
		if (f.mkdir()) {
			System.out.println("Dir /"+best.getFolder()+"/students_optimized Created");
		} else {
			System.out
					.println("Dir /"+best.getFolder()+"/students_optimized NOT Created OR it already  Exists");
		}
		for (int i = 0; i < data.getStudents().length; i++) {
			best.printStudentXML(data.getStudents()[i], "students_optimized");
		}

		f = new File(prop.getRootdir()+"/"+best.getFolder()+"/teachers_optimized");
		if (f.mkdir()) {
			System.out.println("Dir /"+best.getFolder()+"/teachers_optimized Created");
		} else {
			System.out
					.println("Dir /"+best.getFolder()+"/teachers_optimized NOT Created OR it already Exists");
		}
		for (int i = 0; i < data.getTeachers().length; i++) {
			best.printTeacherXML(data.getTeachers()[i], "teachers_optimized");
		}
		
		f = new File(prop.getRootdir()+"/"+best.getFolder()+"/rooms_optimized");
		if (f.mkdir()) {
			System.out.println("Dir /"+best.getFolder()+"/rooms_optimized Created");
		} else {
			System.out
					.println("Dir /"+best.getFolder()+"/rooms_optimized NOT Created OR it already Exists");
		}
		for (int i = 0; i < data.getRooms().length; i++) {
			best.printRoomXML(data.getRooms()[i], "rooms_optimized");
		}
		
		
	}	
	
	
	public SA1() {

	}

	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 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;
	}

	public void closeWindow(int i, PointL wind) {

		PointL fill;
		
		
		if (wind.isPointL()) {

			fill = current.FindBestFill(wind, i, prop);

		//	fill =new PointL();

			if (fill.isPointL()) {
				
				if(current.testMoveTeacher(fill, wind) && current.testMoveRoom(fill, wind)) 
				{
					current.moveTeacher(fill, wind);
				//current.printTeacherXML(teachers[i]);
				}
			}

			if (!fill.isPointL()) {
				PointL[] points = current.findAnyFill(wind, i);
				boolean flag = true;
				for (int k = 0; k < points.length; k++) 
				{
					if (current.testMoveTeacher(points[k], wind) && flag && current.testMoveRoom(points[k], wind)) {
						flag = false;
						current.moveTeacher(points[k], wind);
					}
				}

			}

		}
	}
	
	
	public void printXML(int iter, int penalty){
		analize.startRow();
		analize.addTag(Integer.toString(iter));
		analize.addTag(Integer.toString(penalty));
		analize.endRow();
		
	}
	
	public void printXML(String in){
		summary.startRow();
		summary.addTag(in);
		summary.endRow();
		
	}

	public Schedule getBest() {
		return best;
	}

	public Schedule getInitial() {
		return initial;
	}

}
