package post.office;

import post.mail.Letter;
import post.mail.Address;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;

public class OfficeTest {

    private static final String huname = "Magyarország";
    private static final String enname = "Egyesült Királyság";
    private static final String bpname = "Budapest";
    private static final String szname = "Székesfehérvár";
    private static final String lname = "London";

    private static final String mtk = "Magyar Tudósok körútja";
    private static final String pps = "Pázmány Péter sétány";

    private static final PrintWriter stdout = new PrintWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8), true);
    //private static final PrintWriter stderr = new PrintWriter(new OutputStreamWriter(System.err, StandardCharsets.UTF_8), true);

    public static void testMunicipal() {
        National hu = new National(huname);
        Municipal bp = new Municipal(hu, bpname);

        assertTrue("A Municipal hirePostman() metódusa hamis értéket adott vissza, pedig az utcában nincs még postás.", bp.hirePostman(pps, 11, 8));
        assertTrue("A Municipal hirePostman() metódusa hamis értéket adott vissza, pedig az utcában nincs még postás.", bp.hirePostman(mtk, 11, 8));
        assertFalse("A Municipal hirePostman() metódusa igaz értéket adott vissza, pedig az adott utcában már van postás.", bp.hirePostman(pps, 1, 2));

        Address sender = new Address(huname, bpname, pps, (short) 2);
        Address recipient = new Address(huname, bpname, mtk, (short) 8);
        Address noSuchNumber = new Address(huname, bpname, mtk, (short) 10);
        Address noSuchStreet = new Address(huname, bpname, "almafa", (short) 0);

        Letter letterA = new Letter(sender, recipient, "letterA");
        Letter letterB = new Letter(sender, noSuchNumber, "letterB");
        Letter letterC = new Letter(noSuchStreet, recipient, "letterC");
        Letter letterD = new Letter(noSuchNumber, recipient, "letterD");

        bp.dispatch(letterA);
        assertTrue("A Municipal dispatch() metódus meghívása után egy jól cimzett levél letterA isDelivered() metódusa hamis értéket adott vissza.", letterA.isDelivered());
        assertFalse("A Municipal dispatch() metódus meghívása után egy jól cimzett levél letterA isDestroyed() metódusa igaz értéket adott vissza.", letterA.isDestroyed());

        bp.dispatch(letterB);
        bp.deliverLetters();
        assertTrue("A Municipal dispatch() majd deliverLetters() metódusok meghívása után egy visszaküldött levél letterB isDelivered() metódusa hamis értéket adott vissza.", letterB.isDelivered());
        assertFalse("A Municipal dispatch() majd deliverLetters() metódusok meghívása után egy visszaküldött levél letterA isDestroyed() metódusa igaz értéket adott vissza.", letterA.isDestroyed());
        assertTrue("A Municipal dispatch() majd deliverLetters() metódusok meghívása után egy visszaküldött levél letterB isReturningToSender() metódusa hamis értéket adott vissza.", letterB.isReturningToSender());

        letterC.backToSender();
        bp.dispatch(letterC);
        assertTrue("A Municipal dispatch() metódus meghívása után egy visszaküldött levél letterC, amelynek feladója sem található, isDestroyed() metódusa hamis értéket adott vissza.", letterC.isDestroyed());
        assertFalse("A Municipal dispatch() metódus meghívása után egy visszaküldött levél letterC, amelynek feladója sem található, isDelivered() metódusa hamis értéket adott vissza.", letterC.isDelivered());

        letterD.backToSender();
        bp.dispatch(letterD);
        assertTrue("A Municipal dispatch() metódus meghívása után egy visszaküldött levél letterD, amelynek feladója sem található, isDestroyed() metódusa hamis értéket adott vissza.", letterD.isDestroyed());
        assertFalse("A Municipal dispatch() metódus meghívása után egy visszaküldött levél letterD, amelynek feladója sem található, isDelivered() metódusa hamis értéket adott vissza.", letterD.isDelivered());

        Letter[] letters = {new Letter(sender, recipient, ""), new Letter(sender, recipient, "")};
        bp.post(letters);
        bp.deliverLetters();
        assertTrue("A Municipal post() metódusa nem tesz be minden levelet a postaládába vagy a deliverLetters() metódus nem küld ki minden levelet.", letters[0].isDelivered() && letters[1].isDelivered());

        Municipal sz = new Municipal(hu, szname);
        assertTrue("A National addSubordinate() metódusa hamis értéket adott vissza új városi hivatal esetén.", hu.addSubordinate(bp));
        hu.addSubordinate(sz);
        assertFalse("A National addSubordinate() metódusa igaz értéket adott vissza ismert városi hivatal esetén.", hu.addSubordinate(new Municipal(hu, szname)));

        sz.hirePostman("Kossuth utca", 11, 8);

        Address szRecipient = new Address(huname, szname, "Kossuth utca", (short) 11);
        Letter letterE = new Letter(sender, szRecipient, "letterE");

        bp.dispatch(letterE);
        assertTrue("A Letter isDelivered() metódusa hamis értéket adott vissza, amikor a helyesen címzett levél A város dispatch() metódusával el lett küldve B városba.", letterE.isDelivered());
    }

    public static void testNational() {
        National hu = new National(huname);
        National en = new National(enname);
        assertTrue("A National addContact() metódusa hamis értéket adott vissza, amikor új oszrágos hivatalt kapott.", hu.addContact(en));
        assertFalse("A National addContact() metódusa igaz értéket adott vissza, amikor már ismert oszrágos hivatalt kapott.", hu.addContact(new National(enname)));

        Municipal london = new Municipal(en, lname);
        en.addSubordinate(london);

        Municipal bp = new Municipal(hu, bpname);
        hu.addSubordinate(bp);

        String bakerStr = "Baker Street";

        london.hirePostman(bakerStr, 301, 300);
        bp.hirePostman(pps, 161, 160);

        Address sender = new Address(huname, bpname, pps, (short) 50);
        Address recipient = new Address(enname, lname, bakerStr, (short) 221);
        Address noSuchCountry = new Address("Alma", "Fa", "Alatt", (short) 2);
        Address noSuchCity = new Address(huname, "Piripócs", "Petőfi tér", (short) 4);
        Letter letterA = new Letter(sender, recipient, "");
        Letter letterB = new Letter(sender, noSuchCity, "");
        Letter letterC = new Letter(sender, noSuchCountry, "");
        Letter letterD = new Letter(noSuchCountry, noSuchCity, "");

        bp.dispatch(letterA);
        assertTrue("A Letter isDelivered() metódusa hamis értéket adott vissza, mikor egy helyesen címzett levél lett elküldve A országból B országba a National dispatch() metódusával.", letterA.isDelivered());

        bp.dispatch(letterB);
        assertTrue("A Letter isDelivered() metódusa hamis értéket adott vissza, mikor egy levél ismeretlen városba lett elküldve a National dispatch() metódusával.", letterB.isDelivered());
        assertFalse("A Letter isDestroyed() metódusa igaz értéket adott vissza, mikor egy levél ismeretlen városba lett elküldve a National dispatch() metódusával.", letterB.isDestroyed());

        bp.dispatch(letterC);
        assertTrue("A Letter isDelivered() metódusa hamis értéket adott vissza, mikor egy levél ismeretlen országba lett elküldve a National dispatch() metódusával.", letterC.isDelivered());
        assertFalse("A Letter isDestroyed() metódusa igaz értéket adott vissza, mikor egy levél ismeretlen országba lett elküldve a National dispatch() metódusával.", letterC.isDestroyed());

        bp.dispatch(letterD);
        assertFalse("A Letter isDelivered() metódusa igaz értéket adott vissza, mikor egy levél ismeretlen országba lett visszaküldve a National dispatch() metódusával.", letterD.isDelivered());
        assertTrue("A Letter isDestroyed() metódusa hamis értéket adott vissza, mikor egy levél ismeretlen országba lett visszaküldve a National dispatch() metódusával.", letterD.isDestroyed());
    }

    public static void assertTrue(String msg, Boolean b) {
        if (!b) {
            stdout.println("HIBA: " + msg);
            System.exit(1);
        }
    }

    public static void assertFalse(String msg, Boolean b) {
        if (b) {
            stdout.println("HIBA: " + msg);
            System.exit(1);
        }
    }

    public static void assertEquals(String msg, Object a, Object b) {
        if (!a.equals(b)) {
            stdout.println("HIBA: " + msg + ": '" + a.toString() + "' /= '" + b.toString() + "'");
            System.exit(1);
        }
    }
}
