package ch.epfl.isochrone.timetable;

import static org.junit.Assert.assertEquals;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.junit.Ignore;
import org.junit.Test;

import ch.epfl.isochrone.geo.PointWGS84;

public class TestFastestPathTree {

    private Stop s1 = new Stop("EPFL", new PointWGS84(1, 1));
    private Stop s2 = new Stop("Lausanne-Flon", new PointWGS84(0, 0));
    private Stop s3 = new Stop("Ouchy", new PointWGS84(-1, 0));

    @Test
    @Ignore
    public void namesAreOk() {
        Stop stop = null;
        Map<Stop, Integer> arrivalTimes = null;
        Map<Stop, Stop> predecessors = null;
        FastestPathTree f = new FastestPathTree(stop, arrivalTimes, predecessors);
        Stop s = f.startingStop();
        int i = f.startingTime();
        Set<Stop> ss = f.stops();
        i = f.arrivalTime(stop);
        List<Stop> p = f.pathTo(stop);
        System.out.println("" + s + i + ss + p);

        FastestPathTree.Builder fb = new FastestPathTree.Builder(stop, 0);
        fb.setArrivalTime(stop, 0, stop);
        i = fb.arrivalTime(stop);
        f = fb.build();
    }

    @Test(expected = java.lang.IllegalArgumentException.class)
    public void testConstructorInvalidity() {
        Map<Stop, Integer> arrivalTime = new HashMap<>();
        arrivalTime.put(s1, 1);
        arrivalTime.put(s2, 10);
        Map<Stop, Stop> predecessors = new HashMap<>();
        predecessors.put(s3, s3);
        predecessors.put(s2, s2);
        new FastestPathTree(s3, arrivalTime, predecessors);
    }

    @Test
    public void testStartingStop() {
        Map<Stop, Integer> arrivalTime = new HashMap<>();
        arrivalTime.put(s1, 1);
        arrivalTime.put(s2, 10);
        Map<Stop, Stop> predecessors = new HashMap<>();
        predecessors.put(s2, s2);
        assertEquals(s1, new FastestPathTree(s1, arrivalTime, predecessors).startingStop());
    }

    @Test
    public void testStartingTime() {
        Map<Stop, Integer> arrivalTime = new HashMap<>();
        arrivalTime.put(s1, 15);
        arrivalTime.put(s2, 10);
        Map<Stop, Stop> predecessors = new HashMap<>();
        predecessors.put(s2, s2);
        assertEquals(15, new FastestPathTree(s1, arrivalTime, predecessors).startingTime());
    }
    
    @Test
    public void testSetStops() {
        Map<Stop, Integer> arrivalTime = new HashMap<>();
        arrivalTime.put(s1, 15);
        arrivalTime.put(s2, 10);
        Map<Stop, Stop> predecessors = new HashMap<>();
        predecessors.put(s2, s2);
        Set<Stop> s=new HashSet<>();
        s.add(s1);
        s.add(s2);
        assertEquals(s, new FastestPathTree(s1, arrivalTime, predecessors).stops());
    }
    
    @Test(expected = java.lang.UnsupportedOperationException.class)
    public void testStopsUnsupportedException() {
        Map<Stop, Integer> arrivalTime = new HashMap<>();
        arrivalTime.put(s1, 15);
        arrivalTime.put(s2, 10);
        Map<Stop, Stop> predecessors = new HashMap<>();
        predecessors.put(s2, s2);
        new FastestPathTree(s1, arrivalTime, predecessors).stops().clear();
    }
    
    @Test(expected = java.lang.UnsupportedOperationException.class)
    public void testPathToUnsupportedException() {
        Map<Stop, Integer> arrivalTime = new HashMap<>();
        arrivalTime.put(s1, 15);
        arrivalTime.put(s2, 10);
        Map<Stop, Stop> predecessors = new HashMap<>();
        predecessors.put(s2, s2);
        new FastestPathTree(s1, arrivalTime, predecessors).pathTo(s1).clear();;
    }
    
    @Test
    public void testArrivalTime() {
        Map<Stop, Integer> arrivalTime = new HashMap<>();
        arrivalTime.put(s1, 15);
        arrivalTime.put(s2, 10);
        Map<Stop, Stop> predecessors = new HashMap<>();
        predecessors.put(s2, s2);
        assertEquals(10, new FastestPathTree(s1, arrivalTime, predecessors).arrivalTime(s2));
    }
    
    @Test
    public void testArrivalTimeInfinite() {
        Map<Stop, Integer> arrivalTime = new HashMap<>();
        arrivalTime.put(s1, 1);
        arrivalTime.put(s2, 10);
        Map<Stop, Stop> predecessors = new HashMap<>();
        predecessors.put(s2, s2);
        assertEquals(SecondsPastMidnight.INFINITE, new FastestPathTree(s1, arrivalTime, predecessors).arrivalTime(s3));
    }

    @Test
    public void testPathTo() {
        Stop s4=new Stop("Renens", new PointWGS84(1, 0));
        Map<Stop, Integer> arrivalTime = new HashMap<>();
        arrivalTime.put(s1, 1);
        arrivalTime.put(s2, 10);
        arrivalTime.put(s3, 10);
        arrivalTime.put(s4, 10);
        Map<Stop, Stop> predecessors = new HashMap<>();
        predecessors.put(s4, s3);
        predecessors.put(s2, s1);
        predecessors.put(s3, s2);
        List<Stop> list=new LinkedList<Stop>();
        list.add(s1);
        list.add(s2);
        list.add(s3);
        list.add(s4);
        assertEquals(list, new FastestPathTree(s1, arrivalTime, predecessors).pathTo(s4));
    }
    
    @Test(expected = java.lang.IllegalArgumentException.class)
    public void testpathToInvalidity() {
        Map<Stop, Integer> arrivalTime = new HashMap<>();
        arrivalTime.put(s1, 1);
        arrivalTime.put(s2, 10);
        Map<Stop, Stop> predecessors = new HashMap<>();
        predecessors.put(s3, s3);
        predecessors.put(s2, s2);
        new FastestPathTree(s1, arrivalTime, predecessors).pathTo(s3);
    }

    // ----- Test FastestPathTree.Builder -----

    @Test(expected = java.lang.IllegalArgumentException.class)
    public void testBuilderConstructorInvalidity() {
        new FastestPathTree.Builder(s1, -1);
    }

    @Test
    public void testBuilderSetArrivalTime() {
        Random rng = new Random();
        for (int i = 0; i < 100; ++i) {
            int time = rng.nextInt(50)+1;
            assertEquals(time,new FastestPathTree.Builder(s1, 1).setArrivalTime(s2,time,s3).arrivalTime(s2));
        }
    }
    
    @Test
    public void testBuilderArrivalTimeInfinite() {
        assertEquals(SecondsPastMidnight.INFINITE,new FastestPathTree.Builder(s1, 2).arrivalTime(s2));
    }
    
    @Test(expected = java.lang.IllegalArgumentException.class)
    public void testBuilderSetArrivalTimeInvalidity() {
        new FastestPathTree.Builder(s1, 2).setArrivalTime(s2, 1, s3);
    }
    
    @Test
    public void testBuilderBuild() {
        FastestPathTree.Builder fB=new FastestPathTree.Builder(s1,1);
        fB.setArrivalTime(s2, 10, s1);
        fB.setArrivalTime(s3, 20, s2);
        Map<Stop,Integer> arrivalTime=new HashMap<>();
        arrivalTime.put(s1, 1);
        arrivalTime.put(s2, 10);
        arrivalTime.put(s3, 20);
        Map<Stop,Stop> predecessor=new HashMap<>();
        predecessor.put(s2, s1);
        predecessor.put(s3, s2);
        FastestPathTree tree= new FastestPathTree(s1,arrivalTime,predecessor);
        assertEquals(fB.build().arrivalTime(s1),tree.arrivalTime(s1));
        assertEquals(fB.build().arrivalTime(s2),tree.arrivalTime(s2));
        assertEquals(fB.build().arrivalTime(s3),tree.arrivalTime(s3));
    }

}
