package evolutionAlgorithm;

import org.junit.jupiter.api.Test;
import sk.shanki.dbsuite.mapper.db.*;
import sk.shanki.dbsuite.mapper.evolutionAlgorithm.EvolutionAlgorithm;

import java.util.ArrayList;
import java.util.List;

import static sk.shanki.dbsuite.mapper.values.DbValues.*;

public class EvolutionAlgorithmTimeTest {

    private List<Row> employees = new ArrayList<>();
    private List<Row> wrongEmployees = new ArrayList<>();

    private Database createDatabase(List<Row> rows) {
        Database db = new Database();

        Table departments = new Table("departments");
        departments.add(new Column("department_id", SQLType.INTEGER, false));
        departments.add(new Column("department_name", SQLType.VARCHAR, true));
        departments.add(new Column("manager_id", SQLType.INTEGER, false));
        PrimaryKey departmentsPk = new PrimaryKey();
        departmentsPk.addColumn("department_id");
        departments.set(departmentsPk);

        Table jobs = new Table("jobs");
        jobs.add(new Column("job_id", SQLType.VARCHAR, false));
        jobs.add(new Column("job_title", SQLType.VARCHAR, true));
        PrimaryKey jobsPk = new PrimaryKey();
        jobsPk.addColumn("job_id");
        jobs.set(jobsPk);

        Table employees = new Table("employees");
        employees.add(new Column("employee_id", SQLType.INTEGER, false));
        employees.add(new Column("first_name", SQLType.VARCHAR, true));
        employees.add(new Column("last_name", SQLType.VARCHAR, true));
        employees.add(new Column("job_id", SQLType.VARCHAR, false));
        employees.add(new Column("department_id", SQLType.INTEGER, false));
        PrimaryKey employeesPk = new PrimaryKey();
        employeesPk.addColumn("employee_id");
        employees.set(employeesPk);
        ForeignKey employeeToJob = new ForeignKey("jobs");
        employeeToJob.addSourceColumn("job_id");
        employeeToJob.addTargetColumn("job_id");
        employees.add(employeeToJob);
        ForeignKey employeeToDepartments = new ForeignKey("departments");
        employeeToDepartments.addSourceColumn("department_id");
        employeeToDepartments.addTargetColumn("department_id");
        employees.add(employeeToDepartments);

        ForeignKey departmentToEmployee = new ForeignKey("employees");
        departmentToEmployee.addSourceColumn("manager_id");
        departmentToEmployee.addTargetColumn("employee_id");
        departments.add(departmentToEmployee);

        fillJobs(jobs);
        db.add(jobs);
        fillDepartments(departments);
        db.add(departments);
        fillEmployees(employees, rows);
        db.add(employees);

        return db;
    }

    private void fillJobs(Table jobs){
        jobs.add(new Row(dbString("AD_PRES"), dbString("President")));
        jobs.add(new Row(dbString("AD_VP"), dbString("Administration Vice President")));
        jobs.add(new Row(dbString("AD_ASST"), dbString("Administration Assistant")));
        jobs.add(new Row(dbString("FI_MGR"), dbString("Finance Manager")));
        jobs.add(new Row(dbString("FI_ACCOUNT"), dbString("Accountant")));
        jobs.add(new Row(dbString("AC_MGR"), dbString("Accounting Manager")));
        jobs.add(new Row(dbString("AC_ACCOUNT"), dbString("Public Accountant")));
        jobs.add(new Row(dbString("SA_MAN"), dbString("Sales Manager")));
        jobs.add(new Row(dbString("SA_REP"), dbString("Sales Representative")));
        jobs.add(new Row(dbString("PU_MAN"), dbString("Purchasing Manager")));
    }

    private void fillDepartments(Table departments){
        departments.add(new Row(dbInt(10), dbString("Administration"), dbInt(100)));
        departments.add(new Row(dbInt(20), dbString("Marketing"), dbInt(101)));
        departments.add(new Row(dbInt(30), dbString("Purchasing"), dbInt(102)));
        departments.add(new Row(dbInt(40), dbString("Human Resources"), dbInt(103)));
        departments.add(new Row(dbInt(50), dbString("Shipping"), dbInt(104)));
        departments.add(new Row(dbInt(60), dbString("IT"), dbInt(105)));
        departments.add(new Row(dbInt(70), dbString("Public Relations"), dbInt(106)));
        departments.add(new Row(dbInt(80), dbString("Sales"), dbInt(107)));
        departments.add(new Row(dbInt(90), dbString("Executive"), dbInt(108)));
        departments.add(new Row(dbInt(100), dbString("Finance"), dbInt(109)));
    }

    private void fillEmployees(Table employees, List<Row> rows){
        for (Row row : rows) {
            employees.add(row);
        }

    }

    private void setEmployees(){
        employees.clear();
        employees.add(new Row(dbInt(100), dbString("Steven"), dbString("King"), dbString("AD_PRES"), dbInt(90)));
        employees.add(new Row(dbInt(101), dbString("Neena"), dbString("Kochhar"), dbString("AD_VP"), dbInt(90)));
        employees.add(new Row(dbInt(102), dbString("Lex"), dbString("De Haan"), dbString("AD_VP"), dbInt(90)));
        employees.add(new Row(dbInt(103), dbString("Alexander"), dbString("Hunold"), dbString("AD_ASST"), dbInt(60)));
        employees.add(new Row(dbInt(104), dbString("Bruce"), dbString("Ernst"), dbString("AD_ASST"), dbInt(60)));
        employees.add(new Row(dbInt(105), dbString("David"), dbString("Austin"), dbString("AD_ASST"), dbInt(60)));
        employees.add(new Row(dbInt(106), dbString("Valli"), dbString("Pataballa"), dbString("AD_ASST"), dbInt(60)));
        employees.add(new Row(dbInt(107), dbString("Diana"), dbString("Lorentz"), dbString("AD_ASST"), dbInt(60)));
        employees.add(new Row(dbInt(108), dbString("Nancy"), dbString("Greenberg"), dbString("FI_MGR"), dbInt(100)));
        employees.add(new Row(dbInt(109), dbString("Daniel"), dbString("Faviet"), dbString("FI_ACCOUNT"), dbInt(100)));
        employees.add(new Row(dbInt(110), dbString("John"), dbString("Chen"), dbString("FI_ACCOUNT"), dbInt(100)));
        employees.add(new Row(dbInt(111), dbString("Ismael"), dbString("Sciarra"), dbString("FI_ACCOUNT"), dbInt(100)));
        employees.add(new Row(dbInt(112), dbString("Jose Manuel"), dbString("Urman"), dbString("FI_ACCOUNT"), dbInt(100)));
        employees.add(new Row(dbInt(113), dbString("Luis"), dbString("Popp"), dbString("FI_ACCOUNT"), dbInt(100)));
        employees.add(new Row(dbInt(114), dbString("Den"), dbString("Raphaely"), dbString("SA_MAN"), dbInt(30)));
        employees.add(new Row(dbInt(115), dbString("Alexander"), dbString("Khoo"), dbString("SA_MAN"), dbInt(30)));
        employees.add(new Row(dbInt(116), dbString("Shelli"), dbString("Baida"), dbString("SA_MAN"), dbInt(30)));
        employees.add(new Row(dbInt(117), dbString("Sigal"), dbString("Tobias"),dbString("SA_MAN"), dbInt(30)));
        employees.add(new Row(dbInt(118), dbString("Guy"), dbString("Himuro"), dbString("SA_MAN"), dbInt(30)));
        employees.add(new Row(dbInt(119), dbString("Karen"), dbString("Colmenares"), dbString("SA_MAN"), dbInt(30)));
        employees.add(new Row(dbInt(120), dbString("Matthew"), dbString("Weiss"), dbString("SA_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(121), dbString("Adam"), dbString("Fripp"), dbString("SA_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(122), dbString("Payam"), dbString("Kaufling"), dbString("SA_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(123), dbString("Shanta"), dbString("Vollman"),dbString("SA_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(124), dbString("Kevin"), dbString("Mourgos"), dbString("SA_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(125), dbString("Julia"), dbString("Nayer"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(126), dbString("Irene"), dbString("Mikkilineni"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(127), dbString("James"), dbString("Landry"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(128), dbString("Steven"), dbString("Markle"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(129), dbString("Laura"), dbString("Bissot"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(130), dbString("Mozhe"), dbString("Atkinson"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(131), dbString("James"), dbString("Marlow"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(132), dbString("TJ"), dbString("Olson"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(133), dbString("Jason"), dbString("Mallin"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(134), dbString("Michael"), dbString("Rogers"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(135), dbString("Ki"), dbString("Gee"), dbString("PU_MAN"),dbInt(50)));
        employees.add(new Row(dbInt(136), dbString("Hazel"), dbString("Philtanker"), dbString("PU_MAN"),dbInt(50)));
        employees.add(new Row(dbInt(137), dbString("Renske"), dbString("Ladwig"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(138), dbString("Stephen"), dbString("Stiles"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(139), dbString("John"), dbString("Seo"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(140), dbString("Joshua"), dbString("Patel"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(141), dbString("Trenna"), dbString("Rajs"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(142), dbString("Curtis"), dbString("Davies"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(143), dbString("Randall"), dbString("Matos"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(144), dbString("Peter"), dbString("Vargas"), dbString("PU_MAN"), dbInt(50)));
        employees.add(new Row(dbInt(145), dbString("John"), dbString("Russell"), dbString("SA_MAN"), dbInt(80)));
        employees.add(new Row(dbInt(146), dbString("Karen"), dbString("Partners"), dbString("SA_MAN"), dbInt(80)));
        employees.add(new Row(dbInt(147), dbString("Alberto"), dbString("Errazuriz"), dbString("SA_MAN"), dbInt(80)));
        employees.add(new Row(dbInt(148), dbString("Gerald"), dbString("Cambrault"), dbString("SA_MAN"), dbInt(80)));
        employees.add(new Row(dbInt(149), dbString("Eleni"), dbString("Zlotkey"), dbString("SA_MAN"), dbInt(80)));
        employees.add(new Row(dbInt(150), dbString("Peter"), dbString("Tucker"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(151), dbString("David"), dbString("Bernstein"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(152), dbString("Peter"), dbString("Hall"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(153), dbString("Christopher"), dbString("Olsen"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(154), dbString("Nanette"), dbString("Cambrault"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(155), dbString("Oliver"), dbString("Tuvault"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(156), dbString("Janette"), dbString("King"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(157), dbString("Patrick"), dbString("Sully"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(158), dbString("Allan"), dbString("McEwen"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(159), dbString("Lindsey"), dbString("Smith"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(160), dbString("Louise"), dbString("Doran"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(161), dbString("Sarath"), dbString("Sewall"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(162), dbString("Clara"), dbString("Vishney"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(163), dbString("Danielle"), dbString("Greene"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(164), dbString("Mattea"), dbString("Marvins"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(165), dbString("David"), dbString("Lee"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(166), dbString("Sundar"), dbString("Ande"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(167), dbString("Amit"), dbString("Banda"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(168), dbString("Lisa"), dbString("Ozer"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(169), dbString("Harrison"), dbString("Bloom"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(170), dbString("Tayler"), dbString("Fox"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(171), dbString("William"), dbString("Smith"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(172), dbString("Elizabeth"), dbString("Bates"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(173), dbString("Sundita"), dbString("Kumar"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(174), dbString("Ellen"), dbString("Abel"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(175), dbString("Alyssa"), dbString("Hutton"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(176), dbString("Jonathon"), dbString("Taylor"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(177), dbString("Jack"), dbString("Livingston"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(178), dbString("Kimberely"), dbString("Grant"), dbString("SA_REP"),  dbInt(80)));
        employees.add(new Row(dbInt(179), dbString("Charles"), dbString("Johnson"), dbString("SA_REP"), dbInt(80)));
        employees.add(new Row(dbInt(180), dbString("Winston"), dbString("Taylor"), dbString("SA_REP"), dbInt(50)));
        employees.add(new Row(dbInt(181), dbString("Jean"), dbString("Fleaur"), dbString("SA_REP"), dbInt(50)));
        employees.add(new Row(dbInt(182), dbString("Martha"), dbString("Sullivan"), dbString("SA_REP"), dbInt(50)));
        employees.add(new Row(dbInt(183), dbString("Girard"), dbString("Geoni"), dbString("SA_REP"), dbInt(50)));
        employees.add(new Row(dbInt(184), dbString("Nandita"), dbString("Sarchand"), dbString("SA_REP"), dbInt(50)));
        employees.add(new Row(dbInt(185), dbString("Alexis"), dbString("Bull"), dbString("SA_REP"), dbInt(50)));
        employees.add(new Row(dbInt(186), dbString("Julia"), dbString("Dellinger"), dbString("SA_REP"), dbInt(50)));
        employees.add(new Row(dbInt(187), dbString("Anthony"), dbString("Cabrio"), dbString("SA_REP"), dbInt(50)));
        employees.add(new Row(dbInt(188), dbString("Kelly"), dbString("Chung"), dbString("SA_REP"), dbInt(50)));
        employees.add(new Row(dbInt(189), dbString("Jennifer"), dbString("Dilly"), dbString("SA_REP"), dbInt(50)));
        employees.add(new Row(dbInt(190), dbString("Timothy"), dbString("Gates"), dbString("SA_REP"), dbInt(50)));

    }

    private void setWrongEmployees(){
        wrongEmployees.add(new Row(dbInt(196), dbString("Alana"), dbString("Walsh"), dbString("AC_ACCOUNT"), dbInt(50)));
        wrongEmployees.add(new Row(dbInt(197), dbString("Kevin"), dbString("Feeney"), dbString("PU_MAN"), dbInt(50)));
        wrongEmployees.add(new Row(dbInt(198), dbString("Donald"), dbString("OConnell"), dbString("FI_MGR"), dbInt(50)));
        wrongEmployees.add(new Row(dbInt(199), dbString("Douglas"), dbString("Grant"), dbString("PU_MAN"), dbInt(50)));
        wrongEmployees.add(new Row(dbInt(200), dbString("Jennifer"), dbString("Whalen"), dbString("AC_ACCOUNT"), dbInt(10)));
        wrongEmployees.add(new Row(dbInt(201), dbString("Michael"), dbString("Hartstein"), dbString("PU_MAN"), dbInt(20)));
        wrongEmployees.add(new Row(dbInt(202), dbString("Pat"), dbString("Fay"), dbString("AC_ACCOUNT"), dbInt(20)));
        wrongEmployees.add(new Row(dbInt(203), dbString("Susan"), dbString("Mavris"), dbString("PU_MAN"), dbInt(40)));
        wrongEmployees.add(new Row(dbInt(204), dbString("Hermann"), dbString("Baer"), dbString("PU_MAN"), dbInt(70)));
        wrongEmployees.add(new Row(dbInt(205), dbString("Shelley"), dbString("Higgins"), dbString("FI_MGR"), dbInt(110)));

    }

    @Test
    public void testEvolutionAlgorithm() {
        int wrongRows = 10;
        setEmployees();
        setWrongEmployees();
        List<Row> studentEmployees = new ArrayList<>();
        for(int i = 0; i < employees.size() - wrongRows; i++){
            studentEmployees.add(employees.get(i));
        }
        for(int i = 0; i < wrongRows; i++){
            studentEmployees.add(wrongEmployees.get(i));
        }

        setEmployees();
        Database correctDb = createDatabase(employees);
        Database studentDb = createDatabase(studentEmployees);
        correctDb.buildReferencedRowsIndex();
        studentDb.buildReferencedRowsIndex();

        for(int i = 0 ; i < correctDb.size(); i++){
            for(int j = 0; j < correctDb.get(i).size(); j++){
                Row correctRow = correctDb.get(i).get(j);
                Row studentRow = studentDb.get(i).get(j);
                correctRow.mapTo(studentRow);
                studentRow.mapTo(correctRow);
            }
        }

        double penalization = correctDb.computeDatabasePenalisation(AlphaFormulas.numberOfDataColumns(), RowDistanceFormulas.getCUSTOM());
        penalization += studentDb.computeDatabasePenalisation(AlphaFormulas.numberOfDataColumns(), RowDistanceFormulas.getCUSTOM());

        EvolutionAlgorithm evolutionAlgorithm = new EvolutionAlgorithm(correctDb, studentDb, 500, 300);
        evolutionAlgorithm.solve(penalization);

    }

}
