package evolutionAlgorithm;

import org.junit.jupiter.api.Test;
import sk.shanki.dbsuite.mapper.TableRowsMapping;
import sk.shanki.dbsuite.mapper.db.Row;
import sk.shanki.dbsuite.mapper.evolutionAlgorithm.Individual;
import sk.shanki.dbsuite.mapper.values.DbString;

import java.util.*;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class CrossingTest {
    @Test
    public void testCrossingAtStart() {
        Row jozko = new Row(DbString.instanceFor("Jozko"));
        Row ferko = new Row(DbString.instanceFor("Ferko"));
        Row zuzka = new Row(DbString.instanceFor("Zuzka"));
        List<Row> table1 = List.of(jozko, ferko, zuzka);
        List<Row> table2 = List.of(jozko, ferko, zuzka);
        List<Row> table3 = List.of(ferko, jozko, zuzka);
        List<Row> table4 = List.of(jozko, ferko, zuzka);
        Individual individual1 = new Individual(createIndividualFromInput(table1, table2));
        Individual individual2 = new Individual(createIndividualFromInput(table3, table4));


        TableRowsMapping first_table = individual1.get(0);
        TableRowsMapping second_table = individual2.get(0);
        TableRowsMapping result;

        result = individual1.crossTwoTables(first_table, second_table, 0);

        for(int index = 0; index < first_table.keys.size(); index++) {
            assertEquals(second_table.map.get(first_table.keys.get(index)), result.map.get(first_table.keys.get(index)));
        }

    }

    @Test
    public void testCrossingInMiddle() {
        Row jozko = new Row(DbString.instanceFor("Jozko"));
        Row ferko = new Row(DbString.instanceFor("Ferko"));
        Row zuzka = new Row(DbString.instanceFor("Zuzka"));
        List<Row> table1 = List.of(jozko, ferko, zuzka);
        List<Row> table2 = List.of(jozko, ferko, zuzka);
        List<Row> table3 = List.of(ferko, jozko, zuzka);
        List<Row> table4 = List.of(jozko, ferko, zuzka);
        Individual individual1 = new Individual(createIndividualFromInput(table1, table2));
        Individual individual2 = new Individual(createIndividualFromInput(table3, table4));

        TableRowsMapping first_table = individual1.get(0);
        TableRowsMapping second_table = individual2.get(0);
        TableRowsMapping result;

        result = individual1.crossTwoTables(first_table, second_table, 1);

        for(int index = 0; index < first_table.keys.size(); index++){
            if(index < 1){
                assertEquals(first_table.map.get(first_table.keys.get(index)), result.map.get(first_table.keys.get(index)));
            }
            else{
                assertEquals(second_table.map.get(first_table.keys.get(index)), result.map.get(second_table.keys.get(index)));
            }
        }
    }

    @Test
    public void testCrossingAtEnd() {
        Row jozko = new Row(DbString.instanceFor("Jozko"));
        Row ferko = new Row(DbString.instanceFor("Ferko"));
        Row zuzka = new Row(DbString.instanceFor("Zuzka"));
        List<Row> table1 = List.of(jozko, ferko, zuzka);
        List<Row> table2 = List.of(jozko, ferko, zuzka);
        List<Row> table3 = List.of(ferko, jozko, zuzka);
        List<Row> table4 = List.of(jozko, ferko, zuzka);
        Individual individual1 = new Individual(createIndividualFromInput(table1, table2));
        Individual individual2 = new Individual(createIndividualFromInput(table3, table4));

        TableRowsMapping first_table = individual1.get(0);
        TableRowsMapping second_table = individual2.get(0);
        TableRowsMapping result;

        result = individual1.crossTwoTables(first_table, second_table, first_table.map.size());

        for(int index = 0; index < second_table.keys.size(); index++) {
            assertEquals(first_table.map.get(second_table.keys.get(index)), result.map.get(second_table.keys.get(index)));
        }

    }


    private List<TableRowsMapping> createIndividualFromInput(List<Row> inputs, List<Row> targets){
        List<TableRowsMapping> newIndividual = new ArrayList<>();
        TableRowsMapping tableIndividual = new TableRowsMapping(new ArrayList<>());
        for(int row = 0; row < inputs.size(); row++) {
            Row sourceRow = inputs.get(row);
            Row targetRow = targets.get(row);
            if(targetRow == null){
                tableIndividual.put(sourceRow, null);
            }
            else{
                tableIndividual.put(sourceRow, targetRow);
            }
        }
        newIndividual.add(tableIndividual);
    return newIndividual;
    }
}
