/*
 * SmartGenerator.java
 *
 * Created on 13. říjen 2000, 14:39
 */

package timetable.test;

import timetable.data.*;
import timetable.util.*;
/**
 *
 * @author  Administrator
 * @version 
 */

public class SmartGenerator extends Object {
    protected Config config=null;
    protected int UCEBEN=20;
    protected int VYUCUJICICH=20;
    protected int TRID=20;
    protected int SKUPIN_UCEBEN=20;
    protected int UCEBEN_VE_SKUPINE_MIN=1;
    protected int UCEBEN_VE_SKUPINE_MAX=5;
    protected int UCEBNA_VE_SKUPINACH_MIN=1;
    
    protected int DELKA_AKTIVITY_MIN=1;
    protected int DELKA_AKTIVITY_MAX=5;
    
    protected int ZAPLNENI_UCEBEN_PROC=70;
    //---------------------------------------------------
    
    protected int HARD_VE_VOLNYCH_ZDROJICH_PROC=30;
    protected int SOFT_VE_VOLNYCH_ZDROJICH_PROC=20;
    protected int SOFT_V_POUZITYCH_ZDROJICH_PROC=5;
    
    protected int HARD_VE_VOLNYCH_AKTIVITACH_PROC=30;
    protected int SOFT_VE_VOLNYCH_AKTIVITACH_PROC=20;
    
    protected int POCET_BINARNICH_PODMINEK=1000;
    
    
    int celkemDelka = 0;
    
    public ResourceGroup ucebny = new ResourceGroup();
    public ResourceGroup vyucujici = new ResourceGroup();
    public ResourceGroup tridy = new ResourceGroup();
    
    public Problem problem;
    public Problem partProblem;
    
    int random(int limit) {
        return (int)(java.lang.Math.random()*limit);
    }
    
    protected void init() throws TimetableException {
        UCEBEN=config.getInt("GEN_UCEBEN");
        VYUCUJICICH=config.getInt("GEN_VYUCUJICICH");
        TRID=config.getInt("GEN_TRID");
        SKUPIN_UCEBEN=config.getInt("GEN_SKUPIN_UCEBEN");
        UCEBEN_VE_SKUPINE_MIN=config.getInt("GEN_UCEBEN_VE_SKUPINE_MIN");
        UCEBEN_VE_SKUPINE_MAX=config.getInt("GEN_UCEBEN_VE_SKUPINE_MAX");
        UCEBNA_VE_SKUPINACH_MIN=config.getInt("GEN_UCEBNA_VE_SKUPINACH_MIN");
    
        DELKA_AKTIVITY_MIN=config.getInt("GEN_DELKA_AKTIVITY_MIN");
        DELKA_AKTIVITY_MAX=config.getInt("GEN_DELKA_AKTIVITY_MAX");
    
        ZAPLNENI_UCEBEN_PROC=config.getInt("GEN_ZAPLNENI_UCEBEN_PROC");
    
        HARD_VE_VOLNYCH_ZDROJICH_PROC=config.getInt("GEN_HARD_VE_VOLNYCH_ZDROJICH_PROC");
        SOFT_VE_VOLNYCH_ZDROJICH_PROC=config.getInt("GEN_SOFT_VE_VOLNYCH_ZDROJICH_PROC");
        SOFT_V_POUZITYCH_ZDROJICH_PROC=config.getInt("GEN_SOFT_V_POUZITYCH_ZDROJICH_PROC");
    
        HARD_VE_VOLNYCH_AKTIVITACH_PROC=config.getInt("GEN_HARD_VE_VOLNYCH_AKTIVITACH_PROC");
        SOFT_VE_VOLNYCH_AKTIVITACH_PROC=config.getInt("GEN_SOFT_VE_VOLNYCH_AKTIVITACH_PROC");
    
        POCET_BINARNICH_PODMINEK=config.getInt("GEN_POCET_CASOVYCH_ZAVISLOSTI");
    }
    
    public SmartGenerator(Config k) throws TimetableException {
        this(k,true);
    }
    

    /** Creates new SmartGenerator */
    public SmartGenerator(Config k,boolean reset) throws TimetableException {
        this.config=k;
        init();
        ucebny.name="Ucebny";vyucujici.name="Vyucujici";tridy.name="Tridy";
        problem = new Problem(config);
        Resource u[] = new Resource [UCEBEN];
        java.util.Vector uc2sk[] = new java.util.Vector [UCEBEN];
        for (int i=0;i<UCEBEN;i++) {
            u[i]=new Resource(config,"U"+(1+i));
            ucebny.add(u[i]);
            uc2sk[i]= new java.util.Vector();
        };
        Resource v[] = new Resource [VYUCUJICICH];
        for (int i=0;i<VYUCUJICICH;i++) {
            v[i]=new Resource(config,"V"+(1+i));
            vyucujici.add(v[i]);
        };
        Resource t[] = new Resource [TRID];
        for (int i=0;i<TRID;i++) {
            t[i]=new Resource(config,"T"+(i+1));
            tridy.add(t[i]);
        };
        ResourceGroup sz[] = new ResourceGroup[SKUPIN_UCEBEN];
        for (int i=0;i<SKUPIN_UCEBEN;i++) {
            sz[i]=new ResourceGroup();
            for (int j=0;j<random(1+UCEBEN_VE_SKUPINE_MAX-UCEBEN_VE_SKUPINE_MIN)+UCEBEN_VE_SKUPINE_MIN;j++) {
                int uc=0;
                do {
                    uc = random(UCEBEN);
                } while (sz[i].isInGroup(u[uc]));
                sz[i].add(u[uc]);
                uc2sk[uc].add(sz[i]);
            }
        }
        for (int i=0;i<UCEBEN;i++) 
            while (uc2sk[i].size()<UCEBNA_VE_SKUPINACH_MIN) {
                int sk=0;
                do { 
                    sk = random(SKUPIN_UCEBEN);
                } while (sz[sk].isInGroup(u[i]));
                sz[sk].add(u[i]);
                uc2sk[i].add(sz[sk]);
            }
        int rozvrhU[][] = new int[config.getInt("POCET_SLOTU")][UCEBEN];
        int rozvrhV[][] = new int[config.getInt("POCET_SLOTU")][VYUCUJICICH];
        int rozvrhT[][] = new int[config.getInt("POCET_SLOTU")][TRID];
        for (int i=0;i<config.getInt("POCET_SLOTU");i++) 
            for (int j=0;j<UCEBEN;j++)
                rozvrhU[i][j]=0;
        for (int i=0;i<config.getInt("POCET_SLOTU");i++) 
            for (int j=0;j<VYUCUJICICH;j++)
                rozvrhV[i][j]=0;
        for (int i=0;i<config.getInt("POCET_SLOTU");i++) 
            for (int j=0;j<TRID;j++)
                rozvrhT[i][j]=0;
        int celkem = config.getInt("POCET_SLOTU")*UCEBEN;
        int zaplneno = 0;
        int aktivita = 1;
        int Adelka ;
        int pokus = 0;
        int nrSlotsPerDay = config.getInt(Config.NR_SLOTS)/config.getInt(Config.NR_DAYS);
        do {
            int zacatek = random(config.getInt("POCET_SLOTU"));
            int ucebna = random(UCEBEN);
            if (pokus<500) { 
                pokus =0;
              while (rozvrhU[zacatek][ucebna]==0 && pokus <500) {
                  zacatek = random(config.getInt("POCET_SLOTU"));
                  ucebna = random(UCEBEN); 
                  pokus ++;
              };
            };
            if (pokus==500) do {
                zacatek = random(config.getInt("POCET_SLOTU"));
                ucebna = random(UCEBEN);
                int uc=ucebna;
                while (zacatek<config.getInt("POCET_SLOTU") && rozvrhU[zacatek][uc]!=0) {
                    uc++;
                    if (uc>=UCEBEN) {uc=ucebna; zacatek++;}
                }
                ucebna = uc;
            } while ( zacatek>=config.getInt("POCET_SLOTU") || rozvrhU[zacatek][ucebna]!=0);
            int delka = DELKA_AKTIVITY_MAX;// random(DELKA_AKTIVITY_MAX-DELKA_AKTIVITY_MIN+1)+DELKA_AKTIVITY_MIN;
            Adelka = 0;
            int vyucujici;
            int trida;
            int pokusP = 0;
            do {
               vyucujici = random(VYUCUJICICH);
               trida = random(TRID);
            } while (pokusP<500 && (rozvrhV[zacatek][vyucujici]!=0 || rozvrhT[zacatek][trida]!=0));
            if (pokusP<500) {
                int zac = zacatek;
                boolean first = true;
                while (delka>0 && (first || (zacatek%nrSlotsPerDay!=0)) && zacatek<config.getInt("POCET_SLOTU") && rozvrhU[zacatek][ucebna]==0 && rozvrhV[zacatek][vyucujici]==0 && rozvrhT[zacatek][trida]==0) {
                    rozvrhU[zacatek][ucebna]=aktivita;
                    rozvrhV[zacatek][vyucujici]=aktivita;
                    rozvrhT[zacatek][trida]=aktivita;
                    first = false;
                    zacatek++;delka--;zaplneno++;Adelka++;
                };
                Activity akt = new Activity (config,"a"+aktivita,Adelka);
                akt.resources.add(t[trida]);
                akt.resources.add(v[vyucujici]);
                akt.resources.add((ResourceGroup)(uc2sk[ucebna].get(random(uc2sk[ucebna].size()))));
                akt.selectedResources = new ActivityResources();
                akt.selectedResources.add(t[trida]);
                akt.selectedResources.add(v[vyucujici]);
                akt.selectedResources.add(u[ucebna]);
                akt.schedule(zac, akt.selectedResources);
                aktivita++;
                problem.activities.add(akt);
                celkemDelka+=Adelka;
            };
        } while ((100*zaplneno/celkem) < ZAPLNENI_UCEBEN_PROC);
        int soft_plny=0;
        int soft_volny=0;
        int hard_volny=0;
        for (int i=0;i<config.getInt("POCET_SLOTU");i++) {
            for (int j=0;j<UCEBEN;j++) {
                if (rozvrhU[i][j]==0) {
                    if (random(100)<HARD_VE_VOLNYCH_ZDROJICH_PROC) {
                        hard_volny++;
                        u[j].getPreference().setHARD(i);
                    } else if (random(100)<(100*SOFT_VE_VOLNYCH_ZDROJICH_PROC/(100-HARD_VE_VOLNYCH_ZDROJICH_PROC))) {
                        soft_volny++;
                        u[j].getPreference().setSOFT(i);
                    }
                } else if (random(100)<SOFT_V_POUZITYCH_ZDROJICH_PROC) {
                    soft_plny++;
                    u[j].getPreference().setSOFT(i);
                }
            }
            for (int j=0;j<TRID;j++) {
                if (rozvrhT[i][j]==0) {
                    if (random(100)<HARD_VE_VOLNYCH_ZDROJICH_PROC) {
                        hard_volny++;
                        t[j].getPreference().setHARD(i);
                    } else if (random(100)<(100*SOFT_VE_VOLNYCH_ZDROJICH_PROC/(100-HARD_VE_VOLNYCH_ZDROJICH_PROC))) {
                        soft_volny++;
                        t[j].getPreference().setSOFT(i);
                    }
                } else if (random(100)<SOFT_V_POUZITYCH_ZDROJICH_PROC) {
                    soft_plny++;
                    t[j].getPreference().setSOFT(i);
                }
            }
            for (int j=0;j<VYUCUJICICH;j++) {
                if (rozvrhV[i][j]==0) {
                    if (random(100)<HARD_VE_VOLNYCH_ZDROJICH_PROC) {
                        hard_volny++;
                        v[j].getPreference().setHARD(i);
                    } else if (random(100)<(100*SOFT_VE_VOLNYCH_ZDROJICH_PROC/(100-HARD_VE_VOLNYCH_ZDROJICH_PROC))) {
                        soft_volny++;
                        v[j].getPreference().setSOFT(i);
                    }
                } else if (random(100)<SOFT_V_POUZITYCH_ZDROJICH_PROC) {
                    soft_plny++;
                    v[j].getPreference().setSOFT(i);
                }
            }
        };
        int soft_akt = 0;
        int hard_akt = 0;
        for (int i=0;i<problem.activities.size();i++) {
            for (int j=0;j<config.getInt("POCET_SLOTU");j++) {
                if (j<problem.activities.get(i).start ||
                    j>=problem.activities.get(i).start+problem.activities.get(i).length) {
                    if (random(100)<HARD_VE_VOLNYCH_AKTIVITACH_PROC) {
                        hard_akt++;
                        problem.activities.get(i).getPreference().setHARD(j);
                    } else if (random(100)<(100*SOFT_VE_VOLNYCH_AKTIVITACH_PROC/(100-HARD_VE_VOLNYCH_AKTIVITACH_PROC))) {
                        soft_akt++;
                        problem.activities.get(i).getPreference().setSOFT(j);
                    };
                };
            }
        }
        for (int i=0;i<POCET_BINARNICH_PODMINEK;) {
            Activity a1 = problem.activities.get(random(problem.activities.size()));
            Activity a2;
            do {
                a2 = problem.activities.get(random(problem.activities.size()));
            } while (a1==a2);
            TimeActivityDependence tad = null;
            if (a1.start<a2.start) {
                if (a1.start+a1.length==a2.start)
                    tad = new TimeActivityDependence(a1,TimeActivityDependence.CLOSELY_BEFORE,a2);
                else if (a1.start+a1.length<a2.start)
                    tad = new TimeActivityDependence(a1,TimeActivityDependence.BEFORE,a2);
            } else {
                if (a2.start==a1.start+a1.length)
                    tad = new TimeActivityDependence(a1,TimeActivityDependence.CLOSELY_AFTER,a2);
                else if (a2.start>a1.start+a1.length) 
                    tad = new TimeActivityDependence(a1,TimeActivityDependence.AFTER,a2);
            }
            if (tad!=null) {
//                System.out.println("GENERATE "+tad.toString());
                problem.dependences.add(tad);
                i++;
            }
        };
        System.out.println("Celkem je "+(aktivita-1)+" aktivit. ");
        System.out.println("Zaplneno "+zaplneno+" slotu, to je "+(100*zaplneno/celkem)+"%");
        System.out.println("Prumerna delka je "+((float)celkemDelka/(aktivita-1))+" slotu.");
        System.out.println("HARD podminek u zdoju je "+(100*hard_volny/(UCEBEN*config.getInt("POCET_SLOTU")+VYUCUJICICH*config.getInt("POCET_SLOTU")+TRID*config.getInt("POCET_SLOTU")-3*zaplneno))+" %");
        System.out.println("SOFT podminek u volnych zdoju je "+(100*soft_volny/(UCEBEN*config.getInt("POCET_SLOTU")+VYUCUJICICH*config.getInt("POCET_SLOTU")+TRID*config.getInt("POCET_SLOTU")-3*zaplneno))+" %");
        System.out.println("SOFT podminek u zaplnenych zdoju je "+(100*soft_plny/(3*zaplneno))+" %");
        System.out.println("HARD podminek u volnych aktivit je "+(100*hard_akt/(problem.activities.size()*config.getInt("POCET_SLOTU")-zaplneno))+" %");
        System.out.println("SOFT podminek u volnych aktivit je "+(100*soft_akt/(problem.activities.size()*config.getInt("POCET_SLOTU")-zaplneno))+" %");
        System.out.println("V zadani je "+problem.dependences.size()+" casovych zavislosti.");
        System.out.println("--------------------------------------------------------------------------------");
        problem.resources = new ResourceGroup[] {tridy,vyucujici,ucebny,new ResourceGroup()};
        problem.print("GenRozU.txt",tridy,0,3);
        problem.print("GenRozV.txt",vyucujici,1,3);
        problem.print("GenRozT.txt",ucebny,2,3);
        partProblem = new Problem(config);
        if (reset) problem.reset();
    }
    
    public Problem generujCele() {
        return problem;
    }
    
    public Problem generuj() {
        if (problem.activities.size()==0) return partProblem;
        int akt = random(problem.activities.size());
        partProblem.activities.add(problem.activities.get(akt));
        problem.activities.remove(problem.activities.get(akt));
        return partProblem;
    }
    
    void odeber(Activity a) {
        a.remove(null);
        partProblem.activities.remove(a);
        problem.activities.add(a);
    }
    
    void odeber() {
        odeber(partProblem.activities.get(partProblem.activities.size()-1));
    }
    
    void main(String [] args) {
        if (args.length==0) {
            System.out.println("Usage: SmartGenerator [config_file] output_file");
            return;
        }
        try {
            String cfg = null, outfile = null;
            if (args.length==1) outfile = args[0];
            if (args.length==2) {cfg=args[0]; outfile=args[1];}
            Config k;
            if (cfg!=null) k=new Config(cfg); else k=new Config();
            SmartGenerator g = new SmartGenerator(k);
            Problem p = g.generujCele();
            p.save(outfile);
        } catch (Exception e) {
            System.err.println("Error:" + e);
            e.printStackTrace();
        }
    }
    

}
