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

import game77.api.IAction;
import game77.api.INamed;

import java.util.Arrays;
import java.util.List;

import static game77.ck1f_basic.ScenarioManager.*;


/*******************************************************************************
 * Instance třídy {@code Action}
 * mají na starosti interpretaci příkazů zadávaných uživatelem hrajícím hru.
 * Název spouštěné akce je první slovo zadávaného příkazu;
 * další slova pak jsou interpretována jako argumenty.
 * <p>
 * Lze ale definovat i akci, která odstartuje konverzaci
 * (např. s osobou přítomnou v místnosti) a tím přepne systém do režimu,
 * v němž se zadávané texty neinterpretují jako příkazy,
 * ale předávají se hře, nejvýše nastavují nějaký vnitřní stav,
 * a to až do chvíle, kdy bude rozhovor ukončen, a hra se přepne zpět
 * do režimu klasických příkazů.
 */
public   class Action
       extends ANamed
    implements IAction
{
//===== CLASS/STATIC ATTRIBUTES/FIELDS =========================================

    static private boolean isActive = false;

    static private final List<Action> ACTIONS = List.of(
        new Action("Jdi", Action::move,
            "Přesune Karkulku do zadaného sousedního prostoru."),
        new Action("Vezmi", Action::take,
            "Vezme zadaný předmět a vloží jej do košíku.\n"
          + "Předmět musí být v aktuálním prostoru, musí být přenositelný\n"
          + "a v košíku pro něj musí být volné místo."),
        new Action("Polož", Action::put,
            "Zadaný předmět z košíku položí v aktuálním prostoru."),
        new Action("?", Action::help,
            "Zobrazí seznam dostupných akcí spolu s jejich stručnými popisy."),
        new Action("Konec", (x) -> {
                stop();
                return anSTOP;
            },
            "Předčasně ukončí hru.")
    );


//===== CLASS/STATIC METHODS ===================================================

    /***************************************************************************
     * Vrátí informaci o tom, je-li hra aktuálně spuštěná.
     *
     * @return Je-li spuštěná, vrátí {@code true}, jinak vrátí {@code false}
     */
    static public boolean isActive()
    {
        return isActive;
    }


    /***************************************************************************
     * Ukončí běh hry a uvolní případné alokované prostředky.
     */
    static public void stop()
    {
        isActive = false;
    }


    /***************************************************************************
     * Zpracuje zadaný příkaz a vrátí text zprávy pro uživatele.
     *
     * @param command Zadávaný příkaz
     * @return Textová odpověď hry na zadaný příkaz
     */
    static public String executeCommand(String command)
    {
        command = command.strip();  //Odebrání počátečních a koncových mezer
        if (command.isEmpty()) {
            return executeEmptyCommand();           //Start hry
        }
        else {
            return executeStandardCommand(command); //Běh hry
        }
    }


//===== CLASS (STATIC) PRIVATE AND AUXILIARY METHODS ===========================

    /***************************************************************************
     * Definuje reakci na prázdný příkaz.
     *
     * @return Uvítací text hry
     */
    private static String executeEmptyCommand()
    {
        isActive = true;
        initialize();
        return ScenarioManager.anWELCOME;
    }


    /***************************************************************************
     * Definuje reakci na neprázdný příkaz.
     *
     * @param command Slova zadávaného příkau
     * @return Odpověď hry
     */
    private static String executeStandardCommand(String command)
    {
        String[] words = command.split(" ");    // Rozdělení příkazu na slova
        Action  action = INamed.get(words[0], ACTIONS);     //Nalezení akce
        if (action == null) {
            return "Tento příkaz neumím zpracovat: " + command;
        }
        else {
            return action.execute(words);
        }
    }


    /***************************************************************************
     * Inicializuje aplikaci při startu další hry.
     */
    private static void initialize()
    {
        World.get().initialize();
        Bag  .get().initialize();
    }


    /** Přesune Karkulku do zadaného sousedního prostoru. */
    private static String move(String[] arguments)
    {
        String       destName = arguments[1];       //Název cílového prostoru
        World           world = World.get();                //Správce světa
        Place    currentPlace = world.currentPlace();       //Aktuální prostor
        List<Place> neighbors = currentPlace.neighbors();   //Jeho sousedé
        Place     destination = INamed.get(destName, neighbors);//Cílový prostor
        world.setCurrentPlace(destination);         //Nastavení cílového prostoru
        return anGOTO + destination.description();  //Konstrukce odpovědi
    }


    /** Vezme zadaný předmět a vloží jej do košíku. */
    private static String take(String[] arguments)
    {
        World        world = World.get();       //Správce světa
        Place currentPlace = world.currentPlace();//Aktuální prostor
        String    itemName = arguments[1];      //Název zvedaného h-objektu
        Item          item = currentPlace.item(itemName);
        Bag            bag = Bag.get();         //Batoh
        currentPlace.removeItem(item);          //Odebrání h-objektu z prostoru
        bag.addItem(item);                      //... a jeho vložení do batohu
        return anTAKE + item;                   //Konstrukce odpovědi
    }


    /** Zadaný předmět z košíku položí v aktuálním prostoru. */
    private static String put(String[]  arguments)
    {
        World        world = World.get();       //Správce světa
        Place currentPlace = world.currentPlace();//Aktuální prostor
        String    itemName = arguments[1];      //Název zvedaného h-objektu
        Bag            bag = Bag.get();         //Batoh
        Item          item = bag.item(itemName);//Přesouvaný h-objekt
        bag.removeItem(item);                   //Odebrání h-objektu z batohu
        currentPlace.addItem(item);             //... a jeho přesun do prostoru
        return anPUT + item;                    //Konstrukce odpovědi
    }


    /** Zobrazí cíl hry a seznam možných akcí spolu s jejich stručnými popisy.*/
    private static String help(String[] arguments)
    {
        StringBuilder result = new StringBuilder(SUBJECT)
                .append("\nProveditelné akce:")
                .append("\n==================\n");
        for (Action action : ACTIONS) {
            result.append(action.name()).append('\n')
                  .append(action.description()).append("\n\n");
        }
        return result.toString();
    }



//##############################################################################
//===== INSTANCE CONSTANTS (CONSTANT INSTANCE ATTRIBUTES/FIELDS) ===============

    /** Stručná charakteristika dané akce. */
    private final String description;

    /** Kód, který se má provést při zadání příslušného příkazu. */
    private final ICommand action;


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

    /***************************************************************************
     * Vytvoří novou akci se zadaným názvem, popisem a výkonným kódem.
     *
     * @param name          Název vytvářené akce
     * @param description   Popis akce pro nápovědu
     * @param action        Kód realizující danou akci
     */
    private Action(String name, ICommand action, String description)
    {
        super(name);
        this.action      = action;
        this.description = description;
    }


//===== INSTANCE GETTERS AND SETTERS ===========================================

    /***************************************************************************
     * Vrátí popis akce s vysvětlením její funkce,
     * významu jednotlivých parametrů
     * a možností (resp. účelu) použití dané akce.
     * Tento popis slouží jako nápověda k použití dané akce.
     *
     * @return Popis akce
     */
    @Override
    public String description()
    {
        return description;
    }


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

    /***************************************************************************
     * Metoda realizující reakci hry na zadání daného příkazu.
     * Předávané pole je vždy neprázdné,
     * protože jeho nultý prvek je zadaný název vyvolaného příkazu.
     * Počet argumentů je závislý na konkrétním příkazu,
     * např. příkazy <i>konec</i> a <i>nápověda</i> nemají parametry,
     * příkazy <i>jdi</i> a <i>seber</i> očekávají zadání jednoho argumentu,
     * příkaz <i>použij</i> muže mít dva argumenty atd.
     *
     * @param arguments Zadané argumenty příkazu;
     *                  jejich celkový počet muže byt pro každý příkaz jiný,
     *                  ale nultý prvek vždy obsahuje název příkazu
     * @return Text zprávy vypsané po provedeni příkazu
     */
    @Override
    public String execute(String... arguments)
    {
        return action.execute(arguments);
    }
}
