import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import org.junit.Assert;

import org.junit.BeforeClass;
import org.junit.Test;

public class SimpleTest {

    private static TSP greedyTSP;
    private static final double TOL = 1e-8;
    
    @BeforeClass public static void init() {
        greedyTSP = new GreedyTSP();
    }    

    @Test
    public void test1() {
        List<City> cities = Arrays.asList(
            new City(0.0, 0.0),
            new City(5.6, 4.1),
            new City(0.0, 4.9),
            new City(7.1, 1.3)
        );
        List<City> orig = new ArrayList<>(cities);
        
        greedyTSP.verbeterRoute(cities);
        
        // Geldigheid controleren: alle steden moeten eenmaal bezocht worden.
        Assert.assertTrue("Niet alle steden uit de input-lijst worden bezocht.", cities.containsAll(orig));
        Assert.assertEquals("Elke stad moet exact 1 keer bezocht worden.", orig.size(), cities.size());
        
        // Optimaliteit controleren: de globaal optimale doelfunctiewaarde moet bereikt worden.
        // De testdata is hier immers zodanig gekozen dat de goblaal optimale doelfunctiewaarde bereikt moet worden met de 2-OPT procedure.
        Assert.assertEquals("Doelfunctie niet optimaal.", 20.95136325739353, totaleAfst(cities), TOL);
        
    }
    
    @Test
    public void test2() {
        List<City> cities = Arrays.asList(
            new City(0.0, 1.0),
            new City(4.1, 9.7),
            new City(12.9, 1.0),
            new City(12.9, 9.7),
            new City(4.1, 1.0),
            new City(0.0, 9.7)
        );
        List<City> orig = new ArrayList<>(cities);
        
        greedyTSP.verbeterRoute(cities);
        
        // Geldigheid controleren: alle steden moeten eenmaal bezocht worden.
        Assert.assertTrue("Niet alle steden uit de input-lijst worden bezocht.", cities.containsAll(orig));
        Assert.assertEquals("Elke stad moet exact 1 keer bezocht worden.", orig.size(), cities.size());
        
        // Optimaliteit controleren: de globaal optimale doelfunctiewaarde moet bereikt worden.
        // De testdata is hier immers zodanig gekozen dat de goblaal optimale doelfunctiewaarde bereikt moet worden met de 2-OPT procedure.
        Assert.assertEquals("Doelfunctie niet optimaal.", 43.2, totaleAfst(cities), TOL);
        
    }
    
    @Test
    public void test3() {
        List<City> cities = Arrays.asList(
            new City(0.9, 1.0),
            new City(5.2, 10.0),
            new City(29.1, 11.7),
            new City(40.1, 9.1),
            new City(33.3, 16.1),
            new City(31.2, 8.0),
            new City(7.5, 2.5),
            new City(0.0, 8.3)
        );
        List<City> orig = new ArrayList<>(cities);
        
        greedyTSP.verbeterRoute(cities);
        
        // Geldigheid controleren: alle steden moeten eenmaal bezocht worden.
        Assert.assertTrue("Niet alle steden uit de input-lijst worden bezocht.", cities.containsAll(orig));
        Assert.assertEquals("Elke stad moet exact 1 keer bezocht worden.", orig.size(), cities.size());
        
        // Optimaliteit controleren: de globaal optimale doelfunctiewaarde moet bereikt worden.
        // De testdata is hier immers zodanig gekozen dat de goblaal optimale doelfunctiewaarde bereikt moet worden met de 2-OPT procedure.
        Assert.assertEquals("Doelfunctie niet optimaal.", 92.69419227525472, totaleAfst(cities), TOL);
        
    }
    
    public static double totaleAfst(List<City> antw){
        double afstand = euclAfst(antw.get(antw.size()-1),antw.get(0));
        for(int i = 0; i < antw.size()-1; i++){
            afstand += euclAfst(antw.get(i), antw.get(i+1));
        }
        return afstand;
    }
    
    
    public static double euclAfst(City c1, City c2){
        return Math.sqrt(Math.pow(c1.getX() - c2.getX(),2) + Math.pow(c1.getY() - c2.getY(),2));
    }
    
}