package post.office;

import java.util.ArrayList;
import post.mail.Letter;

/**
 * Definiáljuk szintén az office csomagban a National osztályt, mely az országos
 * hivatalt fogja ábrázolni! Egy országos hivatal ismeri más országok országos
 * hivatalait, és a saját országának városi hivatalait.
 *
 * @author Daniel3ICE
 */
public class National {

    /**
     * Továbbítja egy városi hivatalnak, ha a levelet az országon belül kell
     * kézbesíteni, vagy pedig egy másik országos hivatalnak, ha a levél
     * címzettje külföldi. Ezt több lépésben végezzük el:
     * <ol style="list-style-type: decimal">
     * <li>Először is kérdezzük le a levél <code>whereToDeliver()</code>
     * metódusával, hogy hova is kell elvinni a levelet!</li>
     * <li>Vizsgáljuk meg, hogy a célország azonos-e az országgal, ahol a
     * hivatal található! Két eset lehetséges:
     * <ol style="list-style-type: lower-alpha">
     * <li>Ha a két ország azonos, keressük ki a <code>findSubordinate()</code>
     * metódussal annak a városnak a hivatalát, ahova a levelet el kell vinni!
     * Ha találtunk ilyen hivatalt, akkor megkérjük, hogy kézbesítse a levelet
     * azáltal, hogy meghívjuk a városi hivatal <code>dispatch()</code>
     * metódusát. Ha nincs ilyen hivatal, akkor a cím minden bizonnyal rossz, és
     * a <code>returnOrDestroy()</code> metódussal visszaküldjük vagy
     * megsemmisítjük a levelet.</li>
     * <li>Ha a cél egy másik ország, akkor keressük meg annak az országnak az
     * országos hivatalát a <code>findContact()</code> metódussal! Ha találtunk
     * ilyen hivatalt, akkor megkérjük, hogy kézbesítse a levelet azáltal, hogy
     * meghívjuk a <code>dispatch()</code> metódusát. Ha nincs ilyen hivatal,
     * akkor a cím minden bizonnyal rossz, és a <code>returnOrDestroy()</code>
     * metódussal visszaküldjük vagy megsemmisítjük a levelet.</li>
     * </ol></li>
     * </ol>
     *
     * @param l paraméterül vár egy kézbesítendő levelet
     */
    public void dispatch(Letter l) {
        String targetNation = l.whereToDeliver().getCountry();
        String targetCity = l.whereToDeliver().getCity();
        /*DEBUG3ICE*/
        System.out.print("National.dispatch called with " + this + " on " + l + " where country=" + targetNation);

        if (this.country.equals(targetNation)) {
            /*DEBUG3ICE*/
            System.out.print(" - same country - ");
            Municipal m = findSubordinate(targetCity);
            if (m == null) {
                /*DEBUG3ICE*/
                System.out.println("No such subordinate, returning to sender (or destroying).");
                returnOrDestroy(l);
            } else {
                /*DEBUG3ICE*/
                System.out.println("Dispatching via " + m);
                m.dispatch(l);
            }
        } else {
            /*DEBUG3ICE*/
            System.out.print(" - different country - ");
            National n = findContact(targetNation);
            if (n == null) {
                /*DEBUG3ICE*/
                System.out.println("No such contact, returning to sender (or destroying).");
                returnOrDestroy(l);
            } else {
                /*DEBUG3ICE*/
                System.out.println("Dispatching via " + n);
                n.dispatch(l);
            }
        }
    }

    /**
     * Egy publikus konstruktort, mely inicializálja a country tagot. A contacts
     * és a subordinates sorozatok legyenek kezdetben üresek.
     *
     * @param country paraméterül várja az ország nevét, ahol a hivatal
     * található
     */
    public National(String country) {
        this.country = country;
        contacts = new ArrayList<>();
        subordinates = new ArrayList<>();
    }

    public final String country;
    private final ArrayList<National> contacts;
    private final ArrayList<Municipal> subordinates;

    public String getCountry() {
        return country;
    }

    private National findContact(String nation) {
        //kikeresi a hozzá tartozó National referenciát a contacts sorozatból.
        for (National c : contacts) {
            if (c.getCountry().equals(nation)) {
                return c;
            }
        }
        //Ha nincs ilyen referencia, adjunk vissza null-t!
        return null;
    }

    public boolean addContact(National nation) {
        //Vizsgáljuk meg a findContact() metódussal, hogy az ismert országos hivatalok között szerepel-e olyan,
        //amelyik ugyanabban az országban található, mint a paraméterül adott hivatal!
        if (findContact(nation.getCountry()) == null) {
            contacts.add(nation);
            return true;
        } else {
            return false;
        }
    }

    private Municipal findSubordinate(String city) {
        for (Municipal s : subordinates) {
            if (s.getSettlement().equals(city)) {
                return s;
            }
        }
        return null;
    }

    public boolean addSubordinate(Municipal city) {
        if (findSubordinate(city.getSettlement()) == null) {
            subordinates.add(city);
            return true;
        } else {
            return false;
        }
    }

    private void returnOrDestroy(Letter l) {
        if (l.isReturningToSender()) {
            l.destroy();
        } else {
            l.backToSender();
            dispatch(l);
        }
    }

    @Override
    public String toString() {
        return "Nat(" + country + ")";
    }
}
