package game77.testers;
/* J:/p2_ILS/p2_Adv23s_FW/game77.testers/ArchitectureTester.java
Příliš žluťoučký kůň úpěl ďábelské ó - PŘÍLIŠ ŽLUŤOUČKÝ KŮŇ ÚPĚL ĎÁBELSKÉ Ó.
*/
import java.util.List;

import game77.api.BasicActions;
import game77.api.IBag;
import game77.api.IGame;
import game77.api.IPortal;
import game77.api.IWorld;
import game77.api.ScenarioStep;

import static game77.testers.util.FormatStrings.*;



/*******************************************************************************
 * Instance třídy {@code ArchitectureTester} testují základní architekturu hry,
 * tj. prověřují, zda portál opravdu odkazuje na instanci třídy implementující
 * interfejs {@code IGame} a zda její metody vracejí požadované objekty.
 */
public class ArchitectureTester
     extends ATester
{
//##############################################################################
//===== INSTANCE CONSTANTS (CONSTANT INSTANCE ATTRIBUTES/FIELDS) ===============

    /** Odkaz na instanci testované hry. */
    private final IGame game;

    /* Odkaz na startovní krok šťastného scénáře testované hry. */
    private final ScenarioStep startStep;



//===== INSTANCE VARIABLES (VARIABLE INSTANCE ATTRIBUTES/FIELDS) ===============

    /* Úvodní část textu řady testovacích metod. */
    private String msgStart;



//##############################################################################
//===== INSTANCE INITIALIZERS (CONSTRUCTORS) ===================================

    /***************************************************************************
     * Konstruktor rodičovského podobjektu testerů.
     *
     * @param portal Portál zprostředkující odkazy na klíčové objekty aplikace
     */
    public ArchitectureTester(IPortal portal)
    {
        super(portal);
        game        = portal.game();
        startStep   = SCENARIOS_SUMMARY.startStep;
    }



//===== INSTANCE REMAINING NON-PRIVATE METHODS =================================

    /***************************************************************************
     * Předpokládá, že testy scénářů již proběhly a uložily užitečné informace
     * do rodičovské {@code SCENARIOS_SUMMARY}.
     */
    public void run()
    {
        setMsgStart(game);
        System.out.println(msgStart + BEFORE_N + SCENARIOS_SUMMARY
                                    + AFTER_N);
        verify_isActive();
        verify_basicActions();
        verify_allActions();
        verify_executeCommand();
        verify_stop();
        verify_bag();
        verify_world();
    }



//===== INSTANCE PRIVATE AND AUXILIARY METHODS =================================

    private void setMsgStart(Object object)
    {
        String clsName = object.getClass().getName();
        msgStart = "Test třídy: " + clsName + "\n";
    }


    private void ERR(String message)
    {
        ERRs(msgStart + message);
    }


    private void no_exception(String name, Throwable th)
    {
        if (th instanceof TestException) throw (TestException)th;
        ERR("Volání metody " + name + "() "
          + "nesmí vyhazovat výjimku\n" + th);
    }


    private void verify_isActive()
    {
        try {
            if (game.isActive() == false)  return;
            ERR("Metoda isActive() nevrací false oznamující, že hra neběží");
        }
        catch (Exception ex) {
            no_exception("isActive", ex);
        }
    }


    private void verify_basicActions()
    {
        if (LEVEL.ordinal() < Level.BASIC.ordinal()) { return; }
        var          expected = SCENARIOS_SUMMARY.basicActions;
        BasicActions obtained = null;
        try { obtained = game.basicActions(); }
        catch (Exception ex) { no_exception("basicActions", ex);}
        if (! expected.equals(obtained)) {
            ERR("Názvy základních akcí dodaných metodou basicActions()\n"
              + "neodpovídají názvům definovaným ve scénáři HAPPY\n"
              + "Objednáno: " + expected + "\n"
              + "Dodáno:    " + obtained);
        }
    }


    private void verify_allActions()
    {
        if (LEVEL.ordinal() < Level.BASIC.ordinal()) {
            return;     //Před hladinou BASIC tuto metodu netestujeme
        }
        try {
            var actions = game.allActions();
            if (! (actions instanceof List)) {
                ERR("Metoda allActions() nevrací seznam dostupných akcí");
            }
        }
        catch (Exception ex) {
            no_exception("allActions", ex);
        }
    }


    private void verify_executeCommand()
    {
        if (LEVEL.compareTo(Level.START) < 0) {
            return;     //Před hladinou START tuto metodu netestujeme
        }
        String startErr =
              "Odpověď hry po odstartování příkazem executeCommand(\"\")\n";
        try {
            String expected = startStep.answer.toLowerCase();
            int    length   = expected.length();
            String answer   = game.executeCommand("");
            if (answer.length() < length) {
                ERR(startErr + "je kratší než objednává scénář HAPPY");
            }
            String obtained = answer.substring(0, length).toLowerCase();
            if (expected.equals(obtained)) { return; }
            ERR(startErr + " se liší od požadované");
        }
        catch (Exception ex) {
            no_exception("executeCommand", ex);
        }
    }


    private void verify_stop()
    {
        if (LEVEL.compareTo(Level.BASIC) < 0) {
            return;     //Před hladinou BASIC tuto metodu netestujeme
        }
        try {
            game.stop();
        }
        catch (Exception ex) {
            no_exception("stop", ex);
        }
    }


    private void verify_bag()
    {
        IBag bag = null;
        try {
            bag = game.bag();
            if (bag == null) {
                ERR("Metoda bag() nevrací požadovaný batoh");
            }
            if (game.bag() != bag) {
                ERR("Batoh vracený metodou bag() není jedináček");
            }
        }
        catch (Exception ex) {
            no_exception("bag", ex);
        }
//        if (0 <= LEVEL.compareTo(Level.WORLD)) { //Testujeme až od hladiny WORLD
//            setMsgStart(bag); {
//                verifyBag_capacity(bag);
//                verifyBag_initialize(bag);
//                verifyBag_items(bag);
//                verifyBag_item(bag);
//                verifyBag_addItem(bag);
//                verifyBag_removeItem(bag);
//                verifyBag_initializeItems(bag);
//            } setMsgStart(game);
//        }
    }

//    private void verifyBag_initializeItems(IBag bag)
//    {
//        try {
//            bag.initializeItems();
//        }
//        catch (Exception ex) {
//            no_exception("initializeItems", ex);
//        }
//    }

//    private void verifyBag_removeItem(IBag bag)
//    {
//        try {
//            bag.removeItem(null);
//        }
//        catch (Exception ex) {
//            no_exception("removeItem", ex);
//        }
//    }

//    private void verifyBag_addItem(IBag bag)
//    {
//        try {
//            bag.addItem(null);
//        }
//        catch (Exception ex) {
//            no_exception("addItem", ex);
//        }
//    }

//    private void verifyBag_item(IBag bag)
//    {
//        try {
//            bag.item("");
//        }
//        catch (Exception ex) {
//            no_exception("item", ex);
//        }
//    }

//    private void verifyBag_items(IBag bag)
//    {
//        try {
//            bag.items();
//        }
//        catch (Exception ex) {
//            no_exception("items", ex);
//        }
//    }

//    private void verifyBag_initialize(IBag bag)
//    {
//        try {
//            bag.initialize();
//        }
//        catch (Exception ex) {
//            no_exception("initialize", ex);
//        }
//    }

//    private void verifyBag_capacity(IBag bag)
//    {
//        int capacity = 0;
//        try {
//            capacity = bag.capacity();
//        }
//        catch (Exception ex) {
//            no_exception("capacity", ex);
//        }
//    }


    private void verify_world()
    {
        IWorld world = null;
        try {
            world = game.world();
            if (world == null) {
                ERR("Metoda world() nevrací požadovaný objekt");
            }
            if (game.world() != world) {
                ERR("Svět vracený metodou world() není jedináček");
            }
        }
        catch (Exception ex) {
            no_exception("world", ex);
        }
        if (0 <= LEVEL.compareTo(Level.WORLD)) { //Testujeme až od hladiny WORLD
            setMsgStart(world); {
                verifyWorld_places(world);
//                verifyWorld_currentPlace(world);
//                verifyWorld_place(world);
//                verifyWorld_setCurrentPlace(world);
//                verifyWorld_initialize(world);
            } setMsgStart(game);
        }
    }


    private void verifyWorld_places(IWorld world)
    {
        try {
            var places = world.places();
            if (places == null) {
                ERR("Metoda places() nevrací požadovanou kolekci");
            }
        }
        catch (Exception ex) {
            no_exception("initialize", ex);
        }
    }


//    private void verifyWorld_currentPlace(IWorld world)
//    {
//        try {
//            world.currentPlace();
//        }
//        catch (Exception ex) {
//            no_exception("currentPlace", ex);
//        }
//    }


//    private void verifyWorld_place(IWorld world)
//    {
//        try {
//            if (world.place("") != null) {
//                ERR("Dokud není hra rozběhnuta,\n"
//                  + "má metoda place(String) vracet prázdný odkaz - null");
//            }
//        }
//        catch (Exception ex) {
//            no_exception("place", ex);
//        }
//    }


//    private void verifyWorld_setCurrentPlace(IWorld world)
//    {
//        try {
//            world.initialize();
//        }
//        catch (Exception ex) {
//            no_exception("initialize", ex);
//        }
//    }


//    private void verifyWorld_initialize(IWorld world)
//    {
//        try {
//            world.initialize();
//        }
//        catch (Exception ex) {
//            no_exception("initialize", ex);
//        }
//    }

}
