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.*;

public class CorrectionTest {
    @Test
    public void testCorrection() {
        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 individual = new Individual(createIndividualFromInput(table1, table2));
        Individual parent = new Individual(createIndividualFromInput(table3, table4));

        TableRowsMapping tableIndividual = individual.get(0);
        TableRowsMapping tableParent = parent.get(0);

        TableRowsMapping result = individual.correction(tableIndividual, tableParent);
        assertSame(result, tableIndividual);
    }

    @Test
    public void testCorrectionWithNullInValues() {
        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);
        List<Row> table3 = List.of(jozko, ferko, zuzka);
        List<Row> table4 = List.of(jozko, ferko, zuzka);
        Individual individual = new Individual(createIndividualFromInput(table1, table2));
        Individual parent = new Individual(createIndividualFromInput(table3, table4));

        TableRowsMapping tableIndividual = individual.get(0);
        TableRowsMapping tableParent = parent.get(0);

        assertTrue(tableIndividual.map.containsValue(null));
        TableRowsMapping result = individual.correction(tableIndividual, tableParent);
        assertFalse(tableIndividual.map.containsValue(null));
        assertFalse(result.map.containsValue(null));
        for(Row value: tableParent.map.values()){
            assertTrue(result.map.containsValue(value));
        }
    }

    @Test
    public void testCorrectionWithNullInParent() {
        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);
        List<Row> table3 = List.of(jozko, ferko, zuzka);
        List<Row> table4 = List.of(jozko, zuzka);
        Individual individual = new Individual(createIndividualFromInput(table1, table2));
        Individual parent = new Individual(createIndividualFromInput(table3, table4));

        TableRowsMapping tableIndividual = individual.get(0);
        TableRowsMapping tableParent = parent.get(0);

        assertTrue(tableIndividual.map.containsValue(null));
        TableRowsMapping result = individual.correction(tableIndividual, tableParent);
        assertTrue(result.map.containsValue(null));
        for (Row value : tableParent.map.values()) {
            assertTrue(result.map.containsValue(value));
        }
    }

    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);
            if(targets.size() < row + 1){
                tableIndividual.put(sourceRow, null);
            }
            else {
                Row targetRow = targets.get(row);
                tableIndividual.put(sourceRow, targetRow);
            }
        }
        newIndividual.add(tableIndividual);
        return newIndividual;
    }

}

