package com.uca.flights;

import java.util.Set;
import java.util.HashSet;

/**
 * Represent an city
 * @Author Cesano Ugo, Colmerauer Clément
 * 
 */
public class City
{
	/**City set of "close" airports*/
	private Set<Airport> airports;
	/**City name*/
	private String       name;
	/**City identifier*/
	private CityId       code;

	//Insert other relevent fields

	/**
     * Constructor
     * @param code a city code
     * @param name the city name
     * @throws IllegalArgumentException on null or empty parameter
     */
	public City(CityId code, String name)
	{
		if(code == null)
		{
			throw new IllegalArgumentException("City id can't be null.");
		}
		if(name == null)
        {
            throw new IllegalArgumentException("Name can't be null.");
        }
        if(name.trim().isEmpty())
        {
            throw new IllegalArgumentException("Name can't be uniquely space characters.");
        }

		this.name     = name;
		this.code     = code;
		this.airports = new HashSet<Airport>();
	}

	/**
     * Getter
     * @return city name
     */
	public String getName()
	{
		return this.name;
	}

	/**
     * Setter
     * @param name the city name
     * @throws IllegalArgumentException on null or empty parameter
     */
	public void setName(String name)
	{
		if(name == null)
        {
            throw new IllegalArgumentException("Name can't be null.");
        }
        if(name.trim().isEmpty())
        {
            throw new IllegalArgumentException("Name can't be uniquely space characters.");
        }

		this.name = name;
	}

	/**
     * Getter
     * @return city identifier
     */
	public CityId getCode()
	{
		return this.code;
	}

	/**
     * Add a airport to the city set of airport
     * @param airport the airport to add, warning on already existing airport
     * @throws IllegalArgumentException on null parameter
     */
	public void addAirport(Airport airport)
	{	
		if(airport == null)
		{
			throw new IllegalArgumentException("Airport can't be null.");
		}
		if(this.airports.contains(airport))
		{
            System.err.println("Airport already linked");
		}
		else
        {
			this.airports.add(airport);
			airport.addCity(this);
        }
	}

	/**
     * Add a airport to the city set of airport, non recursive to prevent double navigability infinite loop
     * @param airport the airport to add, warning on already existing airport
     * @throws IllegalArgumentException on null parameter
     */
	void addAirportNonRec(Airport airport)
	{
		if(airport == null)
		{
			throw new IllegalArgumentException("Airport can't be null.");
		}
		if(!this.airports.contains(airport))
		{
			this.airports.add(airport);
		}
	}

	/**
     * Remove an airport from the city set of airport
     * @param airport the airport to remove
     * @throws IllegalArgumentException on null, non existing or main city parameter
     */
	public void removeAirport(Airport airport)
	{
		if(airport == null)
		{
			throw new IllegalArgumentException("Airport can't be null.");
		}
		if(!this.airports.contains(airport))
		{
            throw new IllegalArgumentException("Airport doesn't serve this city.");
		}
		else 
        {
			try
			{
				airport.removeCityNonRec(this);
				this.airports.remove(airport);
			}
			catch(IllegalArgumentException e)
			{
				throw new IllegalArgumentException("Can't remove this city from airport.");
			}
        }
	}

	/**
     * Getter
     * @return city set of airports
     */
	public Set<Airport> getAirports()
	{
		return new HashSet<Airport>(this.airports);
	}

	/**
     * Redefinition of toString
     * @return a string with name and identifier
     */
	@Override
	public String toString()
	{
		return this.code.getValue() + " " + this.name;
	}

	/**
     * Redefinition of equals
     * @param other the city to compare to
     * @return true if other has the same identifier, false else
     * @throws IllegalArgumentException on null or not city parameter
     */
	@Override 
    public boolean equals(Object other)
    {
    	if(other == null)
		{
			throw new IllegalArgumentException("City can't be null.");
		}
		if(!(other instanceof City))
		{
			throw new IllegalArgumentException("Must be compared with city.");			
		}
    	City c = (City)other;
        return this.code.equals(c.getCode());
    }

    /**
     * Redefinition of hashCode
     * @return the hashcode
     */
    @Override
    public int hashCode()
    {
        return this.code == null ? 0 : this.code.hashCode();
    }

}