package com.uca.flights;

import org.junit.jupiter.api.Test;
import java.util.concurrent.Callable;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.*;
import java.time.*;

public class TestFlight
{
	public static void testCityId()
	{
		//Constructor
		assertThat(exceptionOf(() -> new CityId(null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new CityId("")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new CityId("    ")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new CityId("	")), instanceOf(IllegalArgumentException.class));
		assertThat(new CityId("test").getValue(), equalTo("test"));

		//length()
		assertThat(new CityId("test").length(), equalTo(4));

		//compareTo()
		assertThat(new CityId("test").compareTo(new CityId("test")), equalTo(0));
		assertThat(new CityId("test").compareTo(new CityId("test2")), equalTo(1));

		//equals()
		assertThat(new CityId("test").compareTo(new CityId("test2")), equalTo(false));
		assertThat(new CityId("test").compareTo(new CityId("test")), equalTo(true));

		//hashcode
		assertThat(new CityId("test").hashCode(), equalTo(4));
	}

	public static void testCity()
	{
		//Constructor
		assertThat(exceptionOf(() -> new City(null,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new City(new CityId("test"),null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new City(new CityId("test")," ")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new City(new CityId("test"),"	")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new City(new CityId("test"),"")), instanceOf(IllegalArgumentException.class));
		assertThat(new City(new CityId("test"),"test2").getName(), equalTo("test2"));
		assertThat(new City(new CityId("test"),"test2").getCode().getValue(), equalTo("test"));
		
		//setName()
		City c = new City(new CityId("test"),"test2");
		c.setName("test3");
		assertThat(c.getName(), equalTo("test3"));

		//toString()
		assertThat(new City(new CityId("test"),"test2").toString(), equalTo("test  test2"));

		//equals()
		assertThat(new City(new CityId("test"),"test2").equals(new City(new CityId("test"),"test2")), equalTo(true));
		assertThat(new City(new CityId("test"),"test2").equals(new City(new CityId("test3"),"test2")), equalTo(false));

		//hashCode()
		assertThat(new City(new CityId("test"),"test2").hashCode(), equalTo(4));
	}

	public static void testAirportId()
	{
		//Constructor
		assertThat(exceptionOf(() -> new AirportId(null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new AirportId("")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new AirportId(" ")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new AirportId("	")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new AirportId("troplong")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new AirportId("g")), instanceOf(IllegalArgumentException.class));
		assertThat(new AirportId("tes").getValue(), equalTo("tes"));

		//length()
		assertThat(new AirportId("tes").length(), equalTo(3));

		//compareTo()
		assertThat(new AirportId("te1").compareTo(new AirportId("te1")), equalTo(0));
		assertThat(new AirportId("te1").compareTo(new AirportId("te2")), equalTo(1));

		//equals()
		assertThat(new AirportId("te1").compareTo(new AirportId("te2")), equalTo(false));
		assertThat(new AirportId("tes").compareTo(new AirportId("tes1")), equalTo(true));

		//hashcode
		assertThat(new AirportId("tes").hashCode(), equalTo(3));
	}

	public static void testAirport()
	{
		City c      = new City(new CityId("test"),"test");
		AirportId a = new AirportId("tes");

		//Constructor 1
		assertThat(exceptionOf(() -> new Airport(null,(String)null,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,(String)null,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c," ",null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,"	",null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,"",null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,"tes",null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,"tes","")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,"tes","  ")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,"tes","	")), instanceOf(IllegalArgumentException.class));
		assertThat(new Airport(c,"tes","test").getName(), equalTo("test"));
		assertThat(new Airport(c,"tes","test").getId().getValue(), equalTo("tes"));

		//Constructor 2
		assertThat(exceptionOf(() -> new Airport(null,(String)null,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,(String)null,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,a,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,a,"")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,a,"  ")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Airport(c,a,"	")), instanceOf(IllegalArgumentException.class));
		assertThat(new Airport(c,a,"test").getName(), equalTo("test"));
		assertThat(new Airport(c,a,"test").getId(), equalTo(a));
		
		//setName()
		Airport j = new Airport(c,a,"test2");
		j.setName("test3");
		assertThat(j.getName(), equalTo("test3"));

		//equals()
		assertThat(new Airport(c,a,"test").equals(new Airport(c,a,"test2")), equalTo(true));
		assertThat(new Airport(c,a,"test2").equals(new Airport(c,new AirportId("test3"),"test2")), equalTo(false));

		//hashCode()
		assertThat(new Airport(c,a,"test2").hashCode(), equalTo(3));
	}

	public static void testCitiesAndCompany()
	{
		City c1 = new City(new CityId("c4"),"t4");
		City c2 = new City(new CityId("c5"),"t5");
		City c3 = new City(new CityId("c6"),"t6");

		Airport a1 = new Airport(c1, "ae1","n1");
		Airport a2 = new Airport(new City(new CityId("c2"),"t2"), "ae2","n2");
		Airport a3 = new Airport(new City(new CityId("c3"),"t3"), "ae3","n3");

		//Addcity()
		assertThat(a1.getServedCity().size(), equalTo(1));
		a1.addCity(c2);
		assertThat(a1.getServedCity().size(), equalTo(2));
		a1.addCity(c2);
		assertThat(a1.getServedCity().size(), equalTo(2));
		assertThat(c1.getAirports().size(), equalTo(1));
		assertThat(c2.getAirports().size(), equalTo(1));
		a1.addCity(c3);
		assertThat(a1.getServedCity().size(), equalTo(3));
		assertThat(c3.getAirports().size(), equalTo(1));

		System.out.println(a1.getServedCity().toString());

		//removeCity()
		List<City> l = (ArrayList<City>)a1.getServedCity();
		assertThat(l.get(0), equalTo(c1));
		assertThat(a1.getMainCity(), equalTo(c1));
		assertThrows(IllegalArgumentException.class, () -> a1.removeCity(c1));
		assertThrows(IllegalArgumentException.class, () -> a1.removeCity(c2));
		a1.removeCity(c2);
		assertThat(c2.getAirports().size(), equalTo(0));

		//addAirport()
		c2.addAirport(a1);
		assertThat(c2.getAirports().size(), equalTo(1));
		assertThat(a1.getServedCity().size(), equalTo(3));

		//removeAirport()
		assertThrows(IllegalArgumentException.class, () -> c1.removeAirport(a1));
		assertThrows(IllegalArgumentException.class, () -> c1.removeAirport(a3));
		c2.removeAirport(a1);
		assertThat(c2.getAirports().size(), equalTo(0));
		assertThat(a1.getServedCity().size(), equalTo(2));

		CitiesAndAirportsRegistry r = CitiesAndAirportsRegistry.getInstance();
		r.add(c1);
		assertThat(r.get(c1.getCode()), equalTo(c1));
		r.add(a1);
		assertThat(r.get(a1.getId()), equalTo(a1));
		assertThat(r.cities().size(), equalTo(1));
		assertThat(r.airports().size(), equalTo(1));
		assertThat(CitiesAndAirportsRegistry.getInstance(), equalTo(r));
	}

	public static void testStep()
	{
		Airport a = new Airport(new City(new CityId("c2"),"t2"), "ae2","n2");

		//Constructeur 
		assertThat(exceptionOf(() -> new Step(null,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Step(null,Duration.ZERO)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Step(a,null)), instanceOf(IllegalArgumentException.class));

		Step s = new Step(a,Duration.ZERO);
		Step s1 = new Step(a,Duration.ZERO);
		Duration d = Duration.ofDays(1);

		//Getters
		assertThat(s.getDuration(), equalTo(Duration.ZERO));
		assertThat(s.getAirport(), equalTo(a));

		//Delay
		assertThrows(IllegalArgumentException.class, () -> s.delay(null));
		s.delay(d);
		assertThat(s.getDuration(), equalTo(d));

		//next(), setNext(), hasNext()
		assertThat(s.hasNext(), equalTo(false));
		assertThat(s.next(), equalTo(null));
		s.setNext(s1);
		assertThat(s.hasNext(), equalTo(true));
		assertThat(s.next(), equalTo(s1));

		//Clone
		Step s2 = (Step)s.clone();
		assertThat(s2.getDuration(), equalTo(Duration.ZERO));
		assertThat(s.getAirport(), equalTo(a));
	}

	public static void testJump()
	{
		Airport a1 = new Airport(new City(new CityId("c1"),"t1"), "ae1","n1");
		Airport a2 = new Airport(new City(new CityId("c2"),"t2"), "ae2","n2");

		Step s1 = new Step(a1,Duration.ZERO);
		Step s2 = new Step(a2,Duration.ofDays(1));
		Step s3 = new Step(a1,Duration.ofDays(2));

		//Constructor 1
		assertThat(exceptionOf(() -> new Jump(null,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Jump(s1,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Jump(null,s1)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Jump(s2,s1)), instanceOf(IllegalArgumentException.class));

		Jump j2 = new Jump(s2,s3);

		//Constructor 2
		assertThat(exceptionOf(() -> new Jump(null,null,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Jump(s1,null,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Jump(s1,s2,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Jump(null,s2,j2)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Jump(s2,s1)), instanceOf(IllegalArgumentException.class));


		//Chain things
		assertThat(j2.hasNext(), equalTo(false));
		assertThat(j2.next(), equalTo(null));
		assertThat(j2.getPreced(), equalTo(null));
		Jump j1 = new Jump(s1,s2,j2);
		assertThat(j1.hasNext(), equalTo(true));
		assertThat(j1.next(), equalTo(j2));
		assertThat(j2.getPreced(), equalTo(j1));
		assertThat(j1.getSteps(), equalTo(s1));
		assertThrows(IllegalArgumentException.class, () -> j2.setNext(j1));
		assertThrows(IllegalArgumentException.class, () -> j1.setNext(null));
		assertThrows(IllegalArgumentException.class, () -> j1.setPreced(j2));

		//Delay and duration
		assertThat(j1.getDuration(), equalTo(Duration.ofDays(1)));
		j2.delay(Duration.ofDays(1));
		assertThat(j2.getDuration(), equalTo(Duration.ofDays(2)));

		//Clone()
		Jump j3 = (Jump) j2.clone();
		assertThat(j3.getDuration(), equalTo(j2.getDuration()));

	}

	public static void testTrip()
	{
		Airport a1 = new Airport(new City(new CityId("c1"),"t1"), "ae1","n1");
		Airport a2 = new Airport(new City(new CityId("c2"),"t2"), "ae2","n2");

		Step s1 = new Step(a1,Duration.ZERO);
		Step s2 = new Step(a2,Duration.ofDays(1));
		Step s3 = new Step(a1,Duration.ofDays(2));

		Jump j2 = new Jump(s2,s3);
		Jump j1 = new Jump(s1,s2,j2);

		assertThat(exceptionOf(() -> new Trip(null)), instanceOf(IllegalArgumentException.class));

		Trip t1 = new Trip(j1);
		
		ZonedDateTime d = ZonedDateTime.now();

		//Duration and arrival
		assertThat(t1.getDuration(), equalTo(j2.getDuration()));

		//Delay()
		Duration dur = Duration.ofDays(1);
		Trip t2 = (Trip)t1.clone();
		assertThrows(IllegalArgumentException.class, () -> t1.delay(null));
		assertThrows(IllegalArgumentException.class, () -> t1.delay(dur,(Step)null));
		assertThrows(IllegalArgumentException.class, () -> t1.delay(dur,(Jump)null));
		t2.delay(dur,j2);
		assertThat(t1.getDuration().plus(dur), equalTo(t2.getDuration()));
		t2.delay(dur,s2);
		assertThat(t1.getDuration().plus(dur).plus(dur), equalTo(t2.getDuration()));
	}

	public static void testTripBuilder()
	{
		Airport a1 = new Airport(new City(new CityId("c1"),"t1"), "ae1","n1");
		Airport a2 = new Airport(new City(new CityId("c2"),"t2"), "ae2","n2");
		Step s1 = new Step(a1,Duration.ZERO);
		Step s2 = new Step(a2,Duration.ofDays(1));
		Step s3 = new Step(a1,Duration.ofDays(2));
		Jump j2 = new Jump(s2,s3);
		Jump j1 = new Jump(s1,s2);
		Jump j4 = new Jump(s2,s3);
		Jump j3 = new Jump(s1,s2,j4);
		Trip t = new Trip(j3);

		//Constructor
		assertThat(exceptionOf(() -> new TripBuilder((Trip)null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new TripBuilder((Jump)null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new TripBuilder((Step)null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new TripBuilder((TripBuilder)null)), instanceOf(IllegalArgumentException.class));

		final TripBuilder tb = new TripBuilder();
		tb.append(s1);
		tb.append(s2);
		tb.append(s3);
		assertThat(tb.toTrip(), equalTo(t));

		//Steps 1
		final TripBuilder tb1 = new TripBuilder(s3);
		tb1.append(s1);
		assertThrows(IllegalStateException.class, () -> tb1.toTrip());
		assertThrows(IllegalStateException.class, () -> tb1.toRegularTrip());
		tb1.setAbsoluteDuration(true);
		assertThat(tb1.toTrip().getDuration(), equalTo(Duration.ofDays(2)));
		tb1.removeLast();
		assertThrows(IllegalStateException.class, () -> tb1.toRegularTrip());
		tb1.append(s1);
		tb1.removeFirst();
		assertThrows(IllegalStateException.class, () -> tb1.toRegularTrip());
		final TripBuilder tb2 = new TripBuilder(s1);
		tb2.prepend(s3);
		assertThrows(IllegalStateException.class, () -> tb2.toTrip());
		assertThrows(IllegalStateException.class, () -> tb2.toRegularTrip());
		tb2.setAbsoluteDuration(true);
		assertThat(tb2.toTrip().getDuration(), equalTo(Duration.ofDays(2)));
		tb2.removeLast();
		assertThrows(IllegalStateException.class, () -> tb2.toRegularTrip());
		tb2.append(s1);
		tb2.removeFirst();
		assertThrows(IllegalStateException.class, () -> tb2.toRegularTrip());

		//Steps 2
		final TripBuilder tb5 = new TripBuilder(a1,Duration.ofDays(2));
		tb5.append(a1,Duration.ZERO);
		assertThrows(IllegalStateException.class, () -> tb5.toTrip());
		assertThrows(IllegalStateException.class, () -> tb5.toRegularTrip());
		tb5.setAbsoluteDuration(true);
		assertThat(tb5.toTrip().getDuration(), equalTo(Duration.ofDays(2)));
		tb5.removeLast();
		assertThrows(IllegalStateException.class, () -> tb5.toRegularTrip());
		tb5.append(a1,Duration.ZERO);
		tb5.removeFirst();
		assertThrows(IllegalStateException.class, () -> tb5.toRegularTrip());
		final TripBuilder tb6 = new TripBuilder(s1);
		tb6.prepend(a1,Duration.ofDays(2));
		assertThrows(IllegalStateException.class, () -> tb6.toTrip());
		assertThrows(IllegalStateException.class, () -> tb6.toRegularTrip());
		tb6.setAbsoluteDuration(true);
		assertThat(tb6.toTrip().getDuration(), equalTo(Duration.ofDays(2)));
		tb6.removeLast();
		assertThrows(IllegalStateException.class, () -> tb6.toRegularTrip());
		tb6.append(a1,Duration.ZERO);
		tb6.removeFirst();
		assertThrows(IllegalStateException.class, () -> tb6.toRegularTrip());

		//Jump
		final TripBuilder tb7 = new TripBuilder(j2);
		tb7.append(j1);
		assertThrows(IllegalStateException.class, () -> tb7.toTrip());
		assertThrows(IllegalStateException.class, () -> tb7.toRegularTrip());
		tb7.setAbsoluteDuration(true);
		assertThat(tb7.toTrip().getDuration(), equalTo(Duration.ofDays(2)));
		final TripBuilder tb8 = new TripBuilder(j1);
		tb8.prepend(j2);
		assertThrows(IllegalStateException.class, () -> tb8.toTrip());
		assertThrows(IllegalStateException.class, () -> tb8.toRegularTrip());
		tb8.setAbsoluteDuration(true);
		assertThat(tb8.toTrip().getDuration(), equalTo(Duration.ofDays(2)));

		//Trip
		Trip t1 = new Trip(j2);
		Trip t2 = new Trip(j1);
		final TripBuilder tb9 = new TripBuilder(t1);
		tb9.setAbsoluteDuration(true);
		assertThat(tb9.toTrip().getDuration(), equalTo(t1.getDuration()));
		tb9.setAbsoluteDuration(false);
		tb9.append(t2);
		assertThrows(IllegalStateException.class, () -> tb9.toTrip());
		assertThrows(IllegalStateException.class, () -> tb9.toRegularTrip());
		tb9.setAbsoluteDuration(true);
		assertThat(tb9.toTrip().getDuration(), equalTo(Duration.ofDays(2)));
		final TripBuilder tb10 = new TripBuilder(t2);
		tb10.prepend(t1);
		assertThrows(IllegalStateException.class, () -> tb10.toTrip());
		assertThrows(IllegalStateException.class, () -> tb10.toRegularTrip());
		tb10.setAbsoluteDuration(true);
		assertThat(tb10.toTrip().getDuration(), equalTo(Duration.ofDays(2)));

		//Tripbuilder
		TripBuilder tb3 = new TripBuilder(j2);
		final TripBuilder tb11 = new TripBuilder(tb3);
		tb11.setAbsoluteDuration(true);
		assertThat(tb11.toTrip().getDuration(), equalTo(tb3.toTrip().getDuration()));
		tb11.setAbsoluteDuration(false);
		tb11.append(tb3);
		assertThrows(IllegalStateException.class, () -> tb11.toTrip());
		assertThrows(IllegalStateException.class, () -> tb11.toRegularTrip());
		tb11.setAbsoluteDuration(true);
		assertThat(tb11.toTrip().getDuration(), equalTo(Duration.ofDays(2)));
		TripBuilder tb4 = new TripBuilder(j1);
		final TripBuilder tb12 = new TripBuilder(tb4);
		tb12.prepend(tb3);
		assertThrows(IllegalStateException.class, () -> tb12.toTrip());
		assertThrows(IllegalStateException.class, () -> tb12.toRegularTrip());
		tb12.setAbsoluteDuration(true);
		assertThat(tb12.toTrip().getDuration(), equalTo(Duration.ofDays(2)));

		final TripBuilder tb13 = (TripBuilder)tb12.clone();
		tb13.setAbsoluteDuration(true);
		assertThat(tb12.toTrip().getDuration(), equalTo(tb13.toTrip().getDuration()));

	}

	public static void testFlightId()
	{
		//Constructor
		assertThat(exceptionOf(() -> new FlightId(null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new FlightId("")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new FlightId("    ")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new FlightId("	")), instanceOf(IllegalArgumentException.class));
		assertThat(new FlightId("test").getValue(), equalTo("test"));

		assertThat(new FlightId("test").toString(), equalTo(new FlightId("test").getValue()));

		//compareTo()
		assertThat(new FlightId("test").compareTo(new FlightId("test")), equalTo(0));
		assertThat(new FlightId("test").compareTo(new FlightId("test2")), equalTo(1));

		//equals()
		assertThat(new FlightId("test").compareTo(new FlightId("test2")), equalTo(false));
		assertThat(new FlightId("test").compareTo(new FlightId("test")), equalTo(true));

		//hashcode
		assertThat(new FlightId("test").hashCode(), equalTo(4));
	}

	public static void testCompany()
	{
		assertThat(exceptionOf(() -> new Company(null,null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Company("","Gwak-Airlines")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Company("    ","Gwak-Airlines")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Company("	","Gwak-Airlines")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Company("GWK",null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Company("GWK","  ")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new Company("GWK","	")), instanceOf(IllegalArgumentException.class));

		Company c = new Company("GWK","Gwak-Airline");
		assertThat(c.getName(), equalTo("Gwak-Airline"));
		c.setName("Gwak-Airlines");
		assertThrows(IllegalStateException.class, () -> c.setName(" "));
		assertThrows(IllegalStateException.class, () -> c.setName(null));
		assertThat(c.getName(), equalTo("Gwak-Airlines"));
	}

	public static void testFlightIdGenerator()
	{
		TestFlight t = new TestFlight();
		t.testFlightIdGen();
	}

	private void testFlightIdGen()
	{
		assertThat(exceptionOf(() -> new FlightIdGenerator(null)), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new FlightIdGenerator("  ")), instanceOf(IllegalArgumentException.class));
		assertThat(exceptionOf(() -> new FlightIdGenerator("	")), instanceOf(IllegalArgumentException.class));

		FlightIdGenerator fig = new FlightIdGenerator("gwk");
		assertThat(fig.next(), equalTo("gwk-0001"));
		assertThat(fig.next(), equalTo("gwk-0002"));
		fig.reset();
		assertThat(fig.next(), equalTo("gwk-0001"));
	}

	public static void testFlightAndCompany()
	{
		ZonedDateTime date = ZonedDateTime.now();
		Airport a1 = new Airport(new City(new CityId("c1"),"t1"), "ae1","n1");
		Airport a2 = new Airport(new City(new CityId("c2"),"t2"), "ae2","n2");
		Step s1 = new Step(a1,Duration.ZERO);
		Step s2 = new Step(a2,Duration.ofDays(1));
		Step s3 = new Step(a1,Duration.ofDays(2));
		Jump j2 = new Jump(s2,s3);
		Jump j1 = new Jump(s1,s2,j2);
		Trip t = new Trip(j1);
		Company c = new Company("GWK","Gwak-Airline");
		c.addFlight(date,t); 
		ArrayList<FlightId> m = c.getFlights();
		Flight f = c.getFlight(m.get(0));

		//Getter
		assertThat(f.getId().getValue(), equalTo("gwk-0001"));
		assertThat(f.getDeparture(), equalTo(date));
		assertThat(f.getTrip(), equalTo(t));
		assertThat((Jump)f.getJumps(), equalTo(j1));
		assertThat((Step)f.getSteps(), equalTo(s1));

		assertThat(f.getArrival(), equalTo(date.plus(t.getDuration())));
		assertThat(f.getDestination(), equalTo(a1));
		assertThat(f.getDuration(), equalTo(date.plus(t.getDuration())));

		//delay
		assertThrows(IllegalArgumentException.class, () -> f.delay((Duration)null));
		assertThrows(IllegalArgumentException.class, () -> f.delay((Duration)null,(Step)null));
		assertThrows(IllegalArgumentException.class, () -> f.delay((Duration)null,(Jump)null));
		f.delay(Duration.ofDays(1));
		assertThat(f.getDuration(), equalTo(date.plus(t.getDuration().plus(Duration.ofDays(1)))));
		f.delay(Duration.ofDays(1),(Step)f.getSteps());
		assertThat(f.getDuration(), equalTo(date.plus(t.getDuration().plus(Duration.ofDays(1)))));
		f.delay(Duration.ofDays(1),(Jump)f.getJumps());
		assertThat(f.getDuration(), equalTo(date.plus(t.getDuration().plus(Duration.ofDays(1)))));

		assertThrows(IllegalArgumentException.class, () -> c.regularize(null));
		assertThrows(IllegalArgumentException.class, () -> c.addFlight(null,(Trip)null));
		assertThrows(IllegalArgumentException.class, () -> c.addFlight(null,(TripBuilder)null));
		assertThrows(IllegalArgumentException.class, () -> c.addFlight(date,(Trip)null));
		assertThrows(IllegalArgumentException.class, () -> c.addFlight(date,(TripBuilder)null));
		assertThrows(IllegalArgumentException.class, () -> c.addFlight(null,t));
		assertThrows(IllegalArgumentException.class, () -> c.addRegularFlight(null,0));
		assertThrows(IllegalArgumentException.class, () -> c.addRegularFlight(date,-1));
		assertThrows(IllegalArgumentException.class, () -> c.removeFlight(null));
		assertThrows(IllegalArgumentException.class, () -> c.removeRegular(null));
		assertThrows(IllegalArgumentException.class, () -> c.removeRegular(-1));


		c.regularize(f.getId());
		assertThat(c.getRegulars().size(), equalTo(1));
		c.addRegularFlight(date,0);
		assertThat(c.getFlights().size(), equalTo(2));
		c.removeFlight(f.getId());
		assertThat(c.getFlights().size(), equalTo(1));



	}

	public static Throwable exceptionOf(Callable<?> callable) {
		try {
			callable.call();
			return null;
		} catch (Throwable t) {
			return t;
		}
	}

	private class FlightIdGenerator
	{
		private int counter;
		private String prefix;

		private FlightIdGenerator(String prefix)
		{
			this.prefix = prefix;
			this.counter = 0;
		}

		FlightId next()
		{
			StringBuilder value = new StringBuilder(this.prefix);
			value.append("-");
			if(this.counter < 9)
			{
				value.append("0");
			}
			if(this.counter < 99)
			{
				value.append("0");
			}
			if(this.counter < 999)
			{
				value.append("0");
			}
			this.counter++;
			return new FlightId(value.toString());
		}

        //Call une fois par jour
		public void reset()
		{
			this.counter = 0;
		}

	}
	

}

