// 1999 Modified by Vitalius Marcinkevicius IFM-4/2 vmarcink@soften.ktu.lt
// 2000 Modified by Andrejus Sidorovas
// 2000 Modified by Vytautas Perlibakas

// Mokytojai0 saugomas geriausias variantas
// Mokytojai - darbinis variantas

import lt.ktu.gmj.tasks.*;
import lt.ktu.gmj.ui.*;    //import GlobalTools;

import lt.ktu.gmj.*;
import lt.ktu.gmj.propertySheet.*; //import UrlProterty;//import UrlEditor;

import java.io.*;
import java.util.Random;
import java.util.Date;
import java.lang.Long;

import java.net.URL;
import java.net.MalformedURLException;
import java.net.*;
import lt.monarch.awt.*;

//--------------------------------------------------------------------------
class TvarkaDomain extends Domain
{

	static final String []dimensions={"Tikimybe"};
    TvarkaDomain ()
    {
        min[0] = 0;
        max[0] = 1;
        defaultPoint.x[0] = 0.5;
    }
    public String[] dimensions ()
    {
        return dimensions;
    }
};

//--------------------------------------------------------------------------
public class Tvarka implements Task
{
// gTvarka reikalingas, kad galima butu prieiti prie Mokytojai is
// TvarkaAnaliser klases
    public static final String C_LANGAS = "X";  // naudojamas ir TvarkaAnalyzer!
    public static Tvarka gTvarka = null;                // naudojamas ir TvarkaAnalyzer!
    public static String SessionUID = "";	// stringas is skaiciuku; "unikalus" taskui; paimam sistemos laika
	
public int bestiter=-1, curriter=-1;
public double bestresult, currresult;	//funkcijos minimumas
	
	public static String getSessionUID()
	{
		return SessionUID;
	}

	public static Tvarka getTvarka()
    {
//        System.runFinalization();
        return gTvarka;
    }

    public static SheduleLoader gSheduleLoader=null;

/*
    public String data_url=new String( GlobalTools.getCodeBase()+"mokytojai.txt" );
    public String write_program_url=new String( GlobalTools.getCodeBase()+"write.cgi" );
*/

	public static String data_file_url	= "";
	public static String write_program_url	= "";
	public static String fup_program_url	= "";
	public static String result_file_url	= "";

	public void setURLStrings()
	{
		if ( ((GlobalTools.g_cgi_scripts_url).trim()).length()>1 )
			write_program_url = (GlobalTools.g_cgi_scripts_url)+"write.cgi";
		else write_program_url = GlobalTools.getCodeBase()+"write.cgi";

//		System.out.println(write_program_url);	

		if ( ((GlobalTools.g_cgi_scripts_url).trim()).length()>1 )
			fup_program_url = (GlobalTools.g_cgi_scripts_url)+"fup/index.shtml";
		else fup_program_url = GlobalTools.getCodeBase()+"fup/index.shtml";

		if ( ((GlobalTools.g_data_files_url).trim()).length()>1 )
			data_file_url = (GlobalTools.g_data_files_url)+"mokytojai.txt";
		else data_file_url = GlobalTools.getCodeBase()+"mokytojai.txt";

		if ( ((GlobalTools.g_result_files_url).trim()).length()>1 )
			result_file_url = (GlobalTools.g_result_files_url)+"mokytojai.rez";
		else result_file_url = GlobalTools.getCodeBase()+"mokytojai.rez";
	}

    public Tvarka ()
    {
	GlobalTools.setParameters();
	setURLStrings();
	
//       System.out.println("Tvarka() begin");
       gTvarka = this;
	bestresult = Double.MAX_VALUE;

	SessionUID = SessionUID.valueOf((new Date()).getTime());
//	System.out.print("SessionUID = "); System.out.println(SessionUID);
	err_msg_nera_tvarkarascio=false;
 
	gSheduleLoader=	new SheduleLoader();
	gSheduleLoader.setTvarka(gTvarka);
	gSheduleLoader.setSize(800,400);
	gSheduleLoader.show();
    }



    protected void finalize() throws Throwable
    {
       //System.out.println("Tvarka::finalize() begin");
       //gTvarka = null;
       super.finalize();
    }

    public int maxMokytoju = 64;  // mokytoju skaicius mokykloje
    public final int maxPamoku = 7;     // pamoku skaicius per diena
    public final int maxDienu  = 5;     // dienu skaicius per savaite
    public final int maxInfo   = 3;     // mokytojo info: pavarde, dalykas, spec.klase
    public int eMo=64;                  // == maxMokytoju;
    public int sMo=38;                  // == maxMokytojas + maxDienu * maxPamoku;

    public String [][] Mokytojai  = null;
    public String [][] Mokytojai0 = null;

    private String klaidosTekstas = new String (" ");
	private int[] KlPam;	// klases pirmu/paskutiniu pamoku pagalbinis masyvas.
	private int firsttime=0;	// ar funkcija f() kvieciama pirma karta
    public int K = 2;

    public void customize (PropertyManager manager)
    {
       manager.add ( new IntProperty ("K  number of repetitions", new TvarkaIntProvider (this),1,100));
    }

    private int kel;
    private int kelintas;
    private int kurKlaida = -1;
    private int kuris =0;
    private double eval;
    private double eval0;
    private int perstatymai=0;
    private int pos=0;

    public int number_of_variables=1;
    private double norm_point[];
    private double norm_eval[], n_eval[];
    private Random rnd = new Random();
    private TvarkaDomain domain=new TvarkaDomain();

	private static boolean err_msg_nera_tvarkarascio=false;

    public Domain domain ()
    {
        return domain;
    }

    public double f (Point pt)
    {
        if (firsttime ==0)
	{
		firsttime=1;
		currresult=-1;
		System.out.println("-----------------------------------------");
	}

	main ( pt );
	curriter = curriter+1;
	currresult=eval0;

	if (eval0<bestresult)
	{
		bestresult = eval0;
		bestiter = curriter;
		System.out.print("Iteration = "); System.out.print(bestiter);
		System.out.print("\t F(x) = "); System.out.println(bestresult);

// suraso rezultatus i serveryje esanti faila mokytojai.rez
// irasymui naudoja tame paciame kataloge esanti skripta write.cgi
//		try { Output(); } catch (IOException e) { }
	}

        return eval0;
     }

	public String SheduleFromArrayIntoString () throws IOException
	{
		String str = "";
		String temp;
		int i, j;
	    	for (i=0; i<eMo; i++)
	    	{
	        	for (j=0; j<sMo; j++)
	        	{
                		if (j != (sMo-1)) temp = " ";
                		else temp = "";
                		str += Mokytojai[i][j]; str += temp;
	        	}
            		if (i != (eMo-1))
            		{
                		temp = "\n";
                		str += temp;
            		}
	    	}
		return str;
	}

	public void OutputStr(String str) throws IOException
	{
//		System.out.println(write_program_url);
		StringBuffer all = new StringBuffer(8096);

		String old_str; old_str = str;
		
		char curr_chr;
		String add_str;

		for (int i=0; i<old_str.length(); i++)
		{
			curr_chr=old_str.charAt(i);
			add_str = old_str.substring(i,i+1);
			if (curr_chr == '\r') add_str="\r";
			if (curr_chr == '\n') add_str="&&";
			if (curr_chr == ' ') add_str="::";
			all.append(URLEncoder.encode(add_str));
		}
	
		String stringas = all.toString();
		try {
			URL url = new URL(write_program_url);
			URLConnection connection = url.openConnection();
			connection.setDoOutput(true);

			PrintWriter out = new PrintWriter(connection.getOutputStream());
			out.println("string=" + stringas);
			out.flush();
			out.close();
		}
		catch (MalformedURLException e){System.out.println(e);} catch (IOException e){System.out.println(e);};
    }

   public void Output() throws IOException
	{
//        System.out.println(write_program_url);
	    StringBuffer all = new StringBuffer(8096);
        String temp;
	    int i, j;
	    for (i=0; i<eMo; i++){
	        for (j=0; j<sMo; j++){
                if (j != (sMo-1))
                    temp = "::";
                else
                    temp = "";
                all.append(URLEncoder.encode(Mokytojai0[i][j]+temp));
	        }
            if (i != (eMo-1)){
                temp = "&&";
                all.append(URLEncoder.encode(temp));
            }
	    }
    	String stringas = all.toString();
	    try {
	        URL url = new URL(write_program_url);
	        URLConnection connection = url.openConnection();
	        connection.setDoOutput(true);

        	PrintWriter out = new PrintWriter(connection.getOutputStream());
	        out.println("string=" + stringas);
        	out.flush();
        	out.close();
	    }
	    catch (MalformedURLException e){if (GlobalTools.IsApplet()) System.out.println(e);}
	    catch (IOException e){if (GlobalTools.IsApplet()) System.out.println(e);};
    }

	// dinamiskai sukuria masyvus
	public void AllocateArrays()
	{
		Mokytojai  = new String[eMo][sMo];
		Mokytojai0 = new String[eMo][sMo];
	}

    public void InputSheduleFromString(String str) throws IOException
    {
	//System.out.println ( "I tvarkarasciu masyvus surasysim tvarkarasti, perduota kaip stringa" );

	if ( (str.trim()).length()<=1 ) throw new IOException("Is pradziu iveskite pradini tvarkarasti.");
	
        boolean bIsNewFileFormat;
	String first3_str = str.substring(0, 3);
        if ( first3_str.compareTo("Nr.")==0 ){
            bIsNewFileFormat = true;        // assume new file format
//            System.out.println("File open: Assuming NEW file format.");
        }
        else{
            bIsNewFileFormat = false;
//            System.out.println("File open: Assuming OLD file format.");
        }

        boolean bIsCaption, bIsNumber;
        if (bIsNewFileFormat){
            bIsCaption = bIsNumber = true;
        }
        else{
            bIsCaption = bIsNumber = false;
        }

	// suskaiciuosim kiek mokytoju (netusciu eiluciu)	
        BufferedReader buf_r = new BufferedReader( new StringReader(str) );
	if (bIsCaption)  buf_r.readLine();           //pavadinimai Nr. Mokytojas ...
	String tmp_line;
	tmp_line = buf_r.readLine();
	int mokytoju_skaicius = 0;
	while (tmp_line!=null)
	{
		if ( (tmp_line.trim()).length()>1 ) mokytoju_skaicius++;
		tmp_line = buf_r.readLine();
	}
	buf_r.close();
//	System.out.print ( "Mokytoju skaicius = " ); System.out.println ( mokytoju_skaicius );
	eMo		=	mokytoju_skaicius;
	maxMokytoju	=	mokytoju_skaicius;
	AllocateArrays();

	StringReader str_rdr = new StringReader(str);
        BufferedReader r = new BufferedReader( str_rdr );
	if (bIsCaption)  r.readLine();           //pavadinimai Nr. Mokytojas ...
        StreamTokenizer st = new StreamTokenizer( r );
        st.resetSyntax();
        st.whitespaceChars( '\u0000', '\u0020' );
        st.wordChars( '\u0020'+1, '\u00FF' );

//        while (st.nextToken()!=st.TT_EOF){
        for ( int i=0; i<eMo; i++ ){
            if (bIsNumber)
                st.nextToken();   //Nr.
            for(int j=0; j<sMo; j++){
                st.nextToken();
                if (st.ttype == st.TT_WORD) Mokytojai[i][j] = st.sval;
            }
        }
        r.close();
//        System.out.println("Data ready...");
    }


    private void NewInput() throws IOException
    {
        InputStreamReader file;
        boolean bIsNewFileFormat;

        file = GlobalTools.getInputStreamReader( data_file_url );
        char[] buf = new char[3];
        file.read(buf, 0, 3);
        String str = new String(buf);
        file.close();

        if ( str.compareTo("Nr.")==0 ){
            bIsNewFileFormat = true;        // assume new file format
//            System.out.println("File open: Assuming NEW file format.");
        }
        else{
            bIsNewFileFormat = false;
//            System.out.println("File open: Assuming OLD file format.");
        }

        boolean bIsCaption, bIsNumber;
        if (bIsNewFileFormat){
            bIsCaption = bIsNumber = true;
        }
        else{
            bIsCaption = bIsNumber = false;
        }

        file = GlobalTools.getInputStreamReader( data_file_url);
        BufferedReader r = new BufferedReader( file );
        if (bIsCaption)
            r.readLine();           //pavadinimai Nr. Mokytojas ...

        StreamTokenizer st = new StreamTokenizer( r );
        st.resetSyntax();
        st.whitespaceChars( '\u0000', '\u0020' );
        st.wordChars( '\u0020'+1, '\u00FF' );

//        while (st.nextToken()!=st.TT_EOF){
        for ( int i=0; i<eMo; i++ ){
            if (bIsNumber)
                st.nextToken();   //Nr.
            for(int j=0; j<sMo; j++){
                st.nextToken();
                if (st.ttype == st.TT_WORD) Mokytojai[i][j] = st.sval;
            }
        }
        r.close();
        file.close();
//        System.out.println("Data ready...");
    }

    private void norm ()
    {
        int sum = 0;
        for (int i = 0; i < 10; i++) sum += norm_eval[i];
        for (int i = 0; i < 10; i++) norm_eval[i] = norm_eval[i] / sum;
    }

//------------------ Pagrindinis skaiciavimu metodas -----------------------

	
    private void main ( Point pt )
    {
        int it = 0;

	try
	{
		eval0 = geriausias();

	}
	catch (NullPointerException e)
	{
		if (!err_msg_nera_tvarkarascio)
			GlobalTools.showError("Klaida. Neivestas pradinis tvarkarastis. Is pradziu iveskite pradini tvarkarasti, o tik po to optimizuokite.");
		err_msg_nera_tvarkarascio=true;
		return;
	}

        synchronized ( Mokytojai0 ){
            for ( int i = 0; i < eMo; i++ )
                for (int j = 0; j < sMo; j++ )
                    Mokytojai0[i][j] = Mokytojai[i][j];
        }

        while ( it < K )
        {
            it++;
            kel = 0;
            while ( kel < eMo )
            {
                double x = rnd.nextDouble ();
                if ( x > pt.x[0] )
                     if ( ieskoti ( kel ) ){
                        eval = geriausias();
                        if ( eval < eval0 ){
                            eval0 = eval;
                            synchronized ( Mokytojai0 ){
                                for ( int i = 0; i < eMo; i++ )
                                    for (int j = 0; j < sMo; j++ )
                                        Mokytojai0[i][j] = Mokytojai[i][j];
                            }
                        }
                     }
                kel++;
            }
        }
    }

//--------------------------------- Iesko patogios paskaitos ir lango -------------
// Grazina TRUE jei rasta ir sukeista, FALSE priesingu atveju
    private boolean ieskoti ( int kel )
    {
        int langoVieta = 0;
        int patogiPamoka = 0;
        boolean isRyto = false;
        double kurisX = rnd.nextDouble () * 20;	// 20 - tiesiog pakankamai didelis max(kurisX)
        int iter = 0;
        int j = 0;
		
		
        while ( iter < kurisX ){
			// ieskom lango
			if ( Mokytojai[kel][j].equals ( C_LANGAS ) ){
                langoVieta = j;
                iter++;
            }
			// ieskom patogios pamokos
			if ( Mokytojai[kel][j].equals ( "Q" ) &&
                    ( Mokytojai[kel][j+1].startsWith("P") ||
                      Mokytojai[kel][j+1].startsWith("A") ||
                      Mokytojai[kel][j+1].startsWith("T") ||
                      Mokytojai[kel][j+1].startsWith("K") ||
                      Mokytojai[kel][j+1].startsWith("N") ) ){
                patogiPamoka = j + 1;
                isRyto = true;
                iter++;
            }
            if ( Mokytojai[kel][j+1].equals ( "Q" ) &&
                    ( Mokytojai[kel][j].startsWith("P") ||
                      Mokytojai[kel][j].startsWith("A") ||
                      Mokytojai[kel][j].startsWith("T") ||
                      Mokytojai[kel][j].startsWith("K") ||
                      Mokytojai[kel][j].startsWith("N") ) ){
                patogiPamoka = j;
                isRyto = false;
                iter++;
            }
            j++;
            if ( j >= sMo-1 ){ j = 0; iter++; }
        }
        if (( langoVieta >= 3 ) && ( patogiPamoka >= 3 ) && ( langoVieta < sMo ) && ( patogiPamoka < sMo )){
            if ( !perstatymas ( kel, langoVieta, patogiPamoka, isRyto )){
                return false;
            }
            else return true;
        }
        else return false;
    }

//---------------------------------------------- Perstato jei viskas yra teisingai -------------------------

    private boolean perstatymas ( int kel, int langoVieta, int patogiPamoka, boolean isRyto )
    {
        int langoPamoka = ( langoVieta - 2 ) % 7;
        if ( langoPamoka == 0 ) langoPamoka = 7;
        int langoDiena = (int)Math.ceil ((double)(langoVieta - 2) / 7);
        int pamokosPamoka = ( patogiPamoka - 2 ) % 7;
        if ( pamokosPamoka == 0 ) pamokosPamoka = 7;
        int pamokosDiena = (int)Math.ceil ((double)(patogiPamoka - 2) / 7);

        if ( tikrintiPriestaravimus ( kel, langoVieta, patogiPamoka )){
            switch (langoDiena){
                case 1: Mokytojai[kel][langoVieta] = "P"; break;
                case 2: Mokytojai[kel][langoVieta] = "A"; break;
                case 3: Mokytojai[kel][langoVieta] = "T"; break;
                case 4: Mokytojai[kel][langoVieta] = "K"; break;
                case 5: Mokytojai[kel][langoVieta] = "N"; break;
            }

//??? pataisymas, nes panasu kad optimizuojamame tvarkarastyje perkelus
//    pamoka jos numeris nepakeiciamas
            pamokosPamoka = langoPamoka;


            Mokytojai[kel][langoVieta] = Mokytojai[kel][langoVieta].concat(String.valueOf(pamokosPamoka));
            Mokytojai[kel][langoVieta] = Mokytojai[kel][langoVieta].concat(Mokytojai[kel][patogiPamoka].substring(2));
            Mokytojai[kel][patogiPamoka] = "Q";
            int zenklas;
            if ( isRyto ) zenklas = 1;
            else zenklas = -1;
            while ( (Mokytojai[kel][patogiPamoka+zenklas] == "X")  && (patogiPamoka+zenklas < sMo) )
                Mokytojai[kel][patogiPamoka+zenklas] = "Q";
            return true;
        }
        else
            return false;
    }


//------------------------------- Tikrina ar nera priestaravimu ------------------------

    private boolean tikrintiPriestaravimus ( int kel, int langoVieta, int patogiPamoka )
    {
        String s = new String(Mokytojai[kel][patogiPamoka].substring(2));
        boolean isKaires = false;
        boolean isDesines = false;
        for ( int i = 0; i < eMo; i++ ){
			// Tikrinama, ar neatsiras mokiniams lango
			if ( Mokytojai[i][patogiPamoka-1].length() >= 4 )
                if ( s.equals(Mokytojai[i][patogiPamoka-1].substring(2)) ) isKaires = true;
            if ( Mokytojai[i][patogiPamoka+1].length() >= 4 )
                if ( s.equals(Mokytojai[i][patogiPamoka+1].substring(2)) ) isDesines = true;
			// O gal jau sita klase turi paskaita mokytojo lango metu?
			if ( Mokytojai[i][langoVieta].length() >= 4 )
                if ( s.equals(Mokytojai[i][langoVieta].substring(2)) ) return false;
			// Negali vykti 2 to pacio dalyko paskaitos is eiles
			if ( Mokytojai[i][langoVieta-1].length() >= 4 ){
                if ( Mokytojai[kel][1].equals(Mokytojai[i][1]) && ( kel != i ) &&
                    s.equals(Mokytojai[i][langoVieta-1].substring(2)) ) return false;
                if ( ( kel == i ) && ( langoVieta-1 != patogiPamoka ) &&
                    s.equals(Mokytojai[i][langoVieta-1].substring(2)) ) return false;
            }
            if ( Mokytojai[i][langoVieta+1].length() >= 4 ){
                if ( Mokytojai[kel][1].equals(Mokytojai[i][1]) && ( kel != i ) &&
                     s.equals(Mokytojai[i][langoVieta+1].substring(2)) ) return false;
                if ( ( kel == i ) && ( langoVieta+1 != patogiPamoka ) &&
                    s.equals(Mokytojai[i][langoVieta+1].substring(2)) ) return false;
            }
            if ( isKaires && isDesines ) return false;
        }
        return true;
    }


// Grazina pamoku skaiciu duotu metu tikrinamai klasei, jei => 2, reikia imtis veiksmu...
private int PamSkaic(int stulp, String s)
{

	int rez = 0;
	boolean R_B = false;			// ar buvo padalintu pamoku...
	for (int j = 0; j < eMo; j++)
		if (Mokytojai[j][stulp].length() >= 4)
		{
			if (s.equals(Mokytojai[j][stulp].substring(2))
				&& (Mokytojai[j][2].equals("R") || Mokytojai[j][2].equals("B")))
					R_B = true;
			if (s.equals(Mokytojai[j][stulp].substring(2))
				&& !(Mokytojai[j][2].equals("R") || Mokytojai[j][2].equals("B")))
				rez++;
		}
	if (R_B)						// reikia tuo atveju, kai prisideda pamoka 
		rez++;						// prie padalintu pamoka
	return rez;
}	
	

// Grazina eiluteje pirma sutikta pamoka, kuriai is paskos eina antra tai paciai klasei, 
// 0 priesingu atveju.
// Norint tikrinti nuo eilutes pradzios, prad = 4
private int IsEiles(int eil, int prad )
{
	String s;
	for (int j = prad - 1; j < sMo - 1; j++)
		if (Mokytojai[eil][j].length() >= 4)
		{
			s = new String (Mokytojai[eil][j].substring(2));
			if (Mokytojai[eil][j + 1].length() >= 4)
				if (s.equals(Mokytojai[eil][j + 1].substring(2))
				&& !(Mokytojai[eil][2].equals("D") || Mokytojai[eil][2].equals("B")))
				return j;
		}
	return 0;
}


// Grazina TRUE jei galima perkelti pamoka i nurodyta vieta (naudojama PerkelPam)
boolean GalimaKelti(int eil, int st, String s)
{
	if ( (PamSkaic(st, s) < 2) && (IsEiles(eil, st) == 0 || IsEiles(eil, st) > st))
		return true;
	else
		return false;
	
}

// Sukeicia 2 pamokas vietomis
void Swap(int eil1, int eil2, int st1, int st2)
{

	int pirmPamoka, antrPamoka;
	int pirmDiena, antrDiena;
	
		pirmPamoka = ( st1 - 2 ) % 7;
        if ( pirmPamoka == 0 ) pirmPamoka = 7;
        pirmDiena = (int)Math.ceil ((double)(st1 - 2) / 7);
		antrPamoka = ( st2 - 2 ) % 7;
        if ( antrPamoka == 0 ) antrPamoka = 7;
        antrDiena = (int)Math.ceil ((double)(st2 - 2) / 7);

	String temp;
	temp = Mokytojai[eil1][st1];

	// Jei perkeliama pamoka...
	if( Mokytojai[eil2][st2].length() >= 4)
	{
       switch (pirmDiena){
           case 1: Mokytojai[eil1][st1] = "P"; break;
           case 2: Mokytojai[eil1][st1] = "A"; break;
           case 3: Mokytojai[eil1][st1] = "T"; break;
           case 4: Mokytojai[eil1][st1] = "K"; break;
           case 5: Mokytojai[eil1][st1] = "N"; break;
       }
       Mokytojai[eil1][st1] = Mokytojai[eil1][st1].concat(String.valueOf(pirmPamoka));
       Mokytojai[eil1][st1] = Mokytojai[eil1][st1].concat(Mokytojai[eil2][st2].substring(2));
	}   
	else
			// jei ne pirma/pask. pamoka ir aplinkui yra pamokos
       if( ( pirmPamoka > 1 && pirmPamoka < 7) && (!Mokytojai[eil1][st1 - 1].equals("Q")) 
			&& (!Mokytojai[eil1][st1 + 1].equals("Q")))
			Mokytojai[eil1][st1] = C_LANGAS;
	   else
			Mokytojai[eil1][st1] = "Q";				
		

	// tas pats, tik kitai pamokai
	if( temp.length() >= 4)
	{
       switch (antrDiena){
           case 1: Mokytojai[eil2][st2] = "P"; break;
           case 2: Mokytojai[eil2][st2] = "A"; break;
           case 3: Mokytojai[eil2][st2] = "T"; break;
           case 4: Mokytojai[eil2][st2] = "K"; break;
           case 5: Mokytojai[eil2][st2] = "N"; break;
       }
       Mokytojai[eil2][st2] = Mokytojai[eil2][st2].concat(String.valueOf(antrPamoka));
       Mokytojai[eil2][st2] = Mokytojai[eil2][st2].concat(temp.substring(2));
	}   
	else
			// jei ne pirma/pask. pamoka ir aplinkui yra pamokos
       if( ( antrPamoka > 1 && antrPamoka < 7) && (!Mokytojai[eil2][st2 - 1].equals("Q")) 
			&& (!Mokytojai[eil2][st2 + 1].equals("Q")))
			Mokytojai[eil2][st2] = C_LANGAS;
	   else
			Mokytojai[eil2][st2] = "Q";				

}


boolean PerkelPam(int eil, int pamoka)
{
	int i;
	
	for (i = 3; i < sMo; i++)
		if(Mokytojai[eil][i].equals("Q") || Mokytojai[eil][i].equals(C_LANGAS))
		{	Swap(eil, eil, pamoka, i);
			if(GalimaKelti(eil, i, Mokytojai[eil][i].substring(2)))
				return true;
			else
				Swap(eil, eil, i, pamoka);
		}

	for (i = 3; i < sMo; i++)
		if(Mokytojai[eil][i].length() >= 4 && !(Mokytojai[eil][i].substring(2).equals(Mokytojai[eil][pamoka].substring(2))))
		{	Swap(eil, eil, pamoka, i);
			if(GalimaKelti(eil, i, Mokytojai[eil][i].substring(2))&&
			   GalimaKelti(eil, pamoka, Mokytojai[eil][pamoka].substring(2)))
				return true;
			else
				Swap(eil, eil, i, pamoka);
		}
	return false;

}

// Tikrina ir bando pataisyti visus atvejus, kai klasei yra 2 ar daugiau
// pamoku is eiles
private boolean TikrPamSkaic()
{
	int i, j;
	String s;
	boolean rez;
	MessageBox msg;
	
	for( j = 3; j < sMo; j++)
		for( i = 0; i < eMo; i++)
			if (Mokytojai[i][j].length() >= 4)
			{
				s = new String (Mokytojai[i][j].substring(2));
				if (PamSkaic(j, s) > 1)
				{
		            klaidosTekstas = "<"+ s + "> class has two lessons at the same time. Column (" + String.valueOf(j-2) +")\nTrying to recover...";
					
					rez = TaisPamSkaic(j, s);
					if ( !rez)
					{
			            klaidosTekstas = klaidosTekstas.concat("... failed !!!\n");
		                msg = new MessageBox(" Schedule recover message ", klaidosTekstas);
			            msg.show();
					
						return false;
					}
					else
					{
			            klaidosTekstas = klaidosTekstas.concat("... recovered successfully !\n");
		                msg = new MessageBox(" Schedule recover message ", klaidosTekstas);
			            msg.show();
					}
						
				}
			}
	return true;
}

private boolean TaisPamSkaic(int st, String klase)
{
	int i;
	int pam_sk = PamSkaic(st, klase);
	boolean rez;
	
	for( i = 0; i < eMo; i++)
		if ((Mokytojai[i][st].length() >= 4) && (klase.equals(Mokytojai[i][st].substring(2))))
		{
			rez = PerkelPam(i, st);
			if ( rez)
				pam_sk--;
			if (pam_sk == 1)			// Kai liko 1 pamoka klasei, nieko nebereikia kilnoti...
				return true;
		}
	return false;
}

// Tikrina ar nera klasems keliu pamoku is eiles ir bando pataisyti...
private boolean TikrTaisIsEiles()
{
	int i, st;
	boolean rez;
	MessageBox msg;
	
	for( i = 0; i < eMo; i++)
	{
		st = IsEiles(i, 4);
		while (st != 0)
			{
	            klaidosTekstas = "<"+ Mokytojai[i][st].substring(2) + "> class has two lessons one after another. Position (" 
								 + String.valueOf(i+1) + "," + String.valueOf(st-2)+")\nTrying to recover...";

				rez = PerkelPam(i, st);
				if ( !rez)						//Jei nepavykoperkelti pirmos dvigubos pamokos...
				{	rez = PerkelPam(i, st + 1);
					if( !rez)					// ir net antros...
					{
			            klaidosTekstas = klaidosTekstas.concat("... failed !!!\n");
		                msg = new MessageBox(" Schedule recover message ", klaidosTekstas);
			            msg.show();
					
						return false;
					}
				}
				if (rez)
					{
			            klaidosTekstas = klaidosTekstas.concat("... recovered successfully !\n");
		                msg = new MessageBox(" Schedule recover message ", klaidosTekstas);
			            msg.show();
					}
				st = IsEiles(i, 4);
						
			}
	}

	return true;
}

// Grazina true, jei duotame stulpelyje yra nurodyta klase
private boolean KlasStulp(int st, String kl)
{
	for(int i = 0; i < eMo; i++)
		if (Mokytojai[i][st].length() >= 4)
			if (Mokytojai[i][st].substring(2).equals(kl))
				return true;
	return false;

}


// Grazina stulpeli, kuriame yra klases langas, arba 0, jai nerasta ne vieno
private int KlasLangas(String kl)
{
	int i, j, k, l;
	int prad, pab;
	
	for (i = 0; i < 5; i++)
	{
		prad = 3 + 7*i;
		pab = 9 + 7*i; 
		j = 0;
		k = 0;
		while ( !KlasStulp(prad+j, kl))		// kol klase neturi pamoku is ryto
			if (prad + j < pab)
				j++;
			else
				break;
	
		while ( !KlasStulp(pab-k, kl))		// kol klase neturi pamoku vakare
			if (pab - k > prad)
				k++;
			else
				break;
	
		for( l = prad+j; l < pab - k; l++)
			if( !KlasStulp(l, kl))
				return l;
	}
	return 0;
		
}

// Grazina pirmu/paskutiniu klases pamoku stulpeliu masyvo dydi bei uzpildo ta masyva
private int KlasPatogPam(String kl)
{
	int i, j, k, l;
	int prad, pab;
	
	l = 0;
	KlPam = new int[10];

	for (i = 0; i < 5; i++)
	{
		prad = 3 + 7*i;
		pab = 9 + 7*i; 
		j = 0;
		k = 0;
		while ( !KlasStulp(prad+j, kl))		// kol klase neturi pamoku is ryto
			if (prad + j < pab)
				j++;
			else
				break;
	
		while ( !KlasStulp(pab-k, kl))		// kol klase neturi pamoku vakare
			if (pab - k > prad)
				k++;
			else
				break;
	
		if( prad+j <= pab-k)
		{
			KlPam[l++] = prad + j;
			KlPam[l++] = pab - k;
		}

	}
	return l;
		
}

// Bando "uzkisti" klases langa
private boolean TaisKlLangas( int st, String kl)
{
	int n = KlasPatogPam(kl);
	MessageBox msg;
	int i, j;
	
	klaidosTekstas = "<"+ kl + "> class has window. Column (" + String.valueOf(st - 2) +")\nTrying to recover..." ;
								 
	for ( i = 0; i < n; i++)				// pradzioj bandome nukelti i laisva vieta....
		for( j = 0; j < eMo; j++)
			if (Mokytojai[j][KlPam[i]].length() >= 4 
				&&	Mokytojai[j][KlPam[i]].substring(2).equals(kl)
				&& (Mokytojai[j][st].equals("Q") || Mokytojai[j][st].equals(C_LANGAS))
				&& !(Mokytojai[j][2].equals("R") || Mokytojai[j][2].equals("B") || Mokytojai[j][2].equals("D")))
			{	Swap(j, j, KlPam[i], st);
				if(GalimaKelti(j, st, kl))
				{
		            klaidosTekstas = klaidosTekstas.concat("... recovered successfully !\n");
	                msg = new MessageBox(" Schedule recover message ", klaidosTekstas);
		            msg.show();
					
					return true;
				}
				else
					Swap(j, j, st, KlPam[i]);
			}
				
	for ( i = 0; i < n; i++)				// jei nepavyko - tai i kitos pamokos vieta
		for( j = 0; j < eMo; j++)
			if (Mokytojai[j][KlPam[i]].length() >= 4
				&& Mokytojai[j][st].length() >= 4
				&&	Mokytojai[j][KlPam[i]].substring(2).equals(kl)
				&& !(Mokytojai[j][2].equals("R") || Mokytojai[j][2].equals("B") || Mokytojai[j][2].equals("D"))
				&& KlasStulp(KlPam[i], Mokytojai[j][st].substring(2)))
			{	Swap(j, j, KlPam[i], st);
				if(GalimaKelti(j, st, kl)
				   && (KlasLangas(Mokytojai[j][KlPam[i]].substring(2)) == 0 
					   || KlasLangas(Mokytojai[j][KlPam[i]].substring(2)) > KlPam[i]))	// jei tikrai neatsiranda kitos klases lango.
				{
		            klaidosTekstas = klaidosTekstas.concat("... recovered successfully !\n");
	                msg = new MessageBox(" Schedule recover message ", klaidosTekstas);
		            msg.show();
					
					return true;
				}
				else
					Swap(j, j, st, KlPam[i]);
			}

	klaidosTekstas = klaidosTekstas.concat("... failed !!!\n");
    msg = new MessageBox(" Schedule recover message ", klaidosTekstas);
    msg.show();
					
	return false;
}

// Tikrina klases langu buvima ir bando istaisyti...
private boolean TikrKlLangas()
{
	int i, j, k, n;
	int st;
	String[] kl = new String[100];	//masyvas skirtingoms klasems - 100 turi uztekti
	n = 0;
	boolean rasta = false;
	
	// masyvo pildymas
	for (i = 0; i < eMo; i++)
		for (j = 3; j < sMo; j++)
			if (Mokytojai[i][j].length() >= 4)
			{
				rasta = false;
				for (k = 0; k < n; k++)
					if (kl[k].equals(Mokytojai[i][j].substring(2)))
						rasta = true;
				if (!rasta)
					kl[n++] = Mokytojai[i][j].substring(2);
			}
	
	for (k = 0; k < n; k++)
	{
		st = KlasLangas(kl[k]);
		while (st != 0)
			if ( !TaisKlLangas(st, kl[k]))
				return false;
			else 
				st = KlasLangas(kl[k]);
				
	}
	return true;
}

public boolean TaisTvark()
{
	MessageBox msg;
	
	if( !TikrTaisIsEiles())
	{
		klaidosTekstas = "Schedule recover failed.\n";
        msg = new MessageBox(" Schedule error ", klaidosTekstas);
        msg.show();
		
		return false;
	}

	if( !TikrPamSkaic())
	{
		klaidosTekstas = "Schedule recover failed.\n";
        msg = new MessageBox(" Schedule error ", klaidosTekstas);
        msg.show();
		
		return false;
	}

	if( !TikrKlLangas())
	{
		klaidosTekstas = "Schedule recover failed.\n";
        msg = new MessageBox(" Schedule error ", klaidosTekstas);
        msg.show();
		
		return false;
	}

	return true;	
}

//------------------------------- Skaiciuoja kiek yra langu ------------------------

    private int geriausias ()
    {
        int langai = 0;
        for ( int i = 0; i < eMo; i++ )
            for ( int j = 3; j < sMo; j++ )
                if ( Mokytojai[i][j].equals ( C_LANGAS ) )
                    langai++;
        return langai;
    }
};

//--------------------------------------------------------------------------
//----------- PropertyProviders --------------------------------------------


class TvarkaIntProvider extends SimplePropertyProvider
{
    public Tvarka obj;

    public TvarkaIntProvider (Tvarka  _obj)
    {
        obj=_obj;
    }

    public Object get ()
    {
        return new Integer( obj.K );
    }

    public void set (Object value) throws InvalidPropertyException
    {
        obj.K=((Integer) value).intValue();
    }

    protected void finalize() throws Throwable
    {
       obj = null;
       super.finalize();
    }
};

//--------------------------------------------------------------------------

