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

import game77.api.Scenario;
import game77.api.ScenarioStep;

import java.util.List;
import java.util.Map;

import static game77.api.TypeOfScenario.*;
import static game77.api.TypeOfStep.*;



/*******************************************************************************
 * Třída {@code ScenarioManager} definuje sadu scénářů,
 * podle nichž je možno hrát (anebo testovat) hru, pro niž jsou určeny -
 * v tomoto případě hru inspirovanou pohádkou o Červené Karkulce.
 * Aby bylo možno jednotlivé scénáře od sebe odlišit,
 * je každý pojmenován a má přiřazen typ, podle které lze blíže určit,
 * k čemu je možno daný scénář použít.
 * Scénáře jsou definovány jako posloupnosti kroků.
 * Tato verze obsahuje vedle scénáře HAPPY ještě scénář BASIC
 * definující posloupnost kroků prověřující všechny povinné akce.
 */
public class ScenarioManager
{
/** Předpony názvů proměnných s texty používanými ve scénářích i kódu:
 *  an - answer         - Zpráva hry jako odpověď na příkaz
 *  pl - place          - Název prostoru hry
 *  ds - description    - Stručný popis aktuálního prostoru
 *  nb - neighbors      - Názvy počátečních sousedů prostoru
 *  ip - items in place - Názvy sady h-objektů v prostoru
 *  ib - items in bag   - Názvy sady h-objektů v batohu
 *  in - item name      - Název h-objektu
 *  er - error          - Odpověď na chybně zadaný příkaz
 */
static final String SUBJECT, anWELCOME,          //EMPTYsa = Empty String array,
    plHOUSE,   dsHOUSE,   nbHOUSE[],    ipHOUSE[],  EMPTYsa[],
    plWOOD,    dsWOOD,    nbWOOD[],     ipWOOD[],   ibWOOD[],
    plFOREST,  dsFOREST,  nbFOREST[],   ipFOREST[],
    plCAVE,    dsCAVE,    nbCAVE[],     ipCAVE[],
    plCOTTAGE, dsCOTTAGE, nbCOTTAGE[],  ipCOTTAGE[],
    ipSTART[], bgSTART[], ipBAG_FULL[], ibBAG_FULL[], ipWAKE_UP[],
    anGOTO, anTAKE, anPUT, anHELP, anSTOP,
    anWAKE_UP, anGREETING, anSUCCESSa, anSUCCESSb,
    anNOT_START, anEMPTY, anUNKNOWN,
    anMOVE_WA, anTAKE_WA, anPUT_DOWN_WA,
    anBAD_NEIGHBOR, anBAD_ITEM, anUNMOVABLE, anBAG_FULL, anNOT_IN_BAG,
    inGRANDMA, inWOLF,
    erNS1_WAKE_WA, erNS1_WAKE_NO_HERE, erNS1_WAKE_WRONG_ARG,
    erNS1_WAKE_2NDa, erNS1_WAKE_2NDb,
    erNS0_GREET_WAKEa, erNS0_GREET_WAKEb, erNS0_GREET_2NDa, erNS0_GREET_2NDb,
    erMS0_GREET_NOBODY, erSUCCESS_NOBODY, erSUCCESS_GREETa, erSUCCESS_GREETb
    ;

/** Definované scénáře. */
private static final Scenario BASIC, MISTAKES, HAPPY, MISTAKES_NS;

/** Startovní krok. */
public static final ScenarioStep START_STEP;

// Statický inicializační blok umožňující inicializaci statických konstant
static {

// Téma vyvíjené hry používané ve startovním kroku a v nápovědě
SUBJECT = """
        Toto je příběh o Červené Karkulce, babičce a vlkovi.
        Svými příkazy řídíte Karkulku, aby donesla bábovku a víno
        babičce v chaloupce za temným lesem.
        Karkulka musí nejprve v domečku vložit do košíku víno a bábovku,
        a potom přejít přes les a temný les do chaloupky.
        Když přijde do chaloupky, měla by položit dárky, vzbudit babičku,
        pozdravit a popřát jí k narozeninám.
        Jste-li dobrodružné typy, můžete to místo s babičkou provést
        s vlkem, který spí v temném lese.
        """;

// Společný startovní krok všech scénářů
START_STEP = new ScenarioStep(tsSTART, "",
        anWELCOME = ("Vítejte!\n" + SUBJECT
      + "\nNebudete-li si vědět rady, zadejte znak ?, jenž zobrazí nápovědu.")
        ,
        plHOUSE = "Domeček",                             //Aktuální prostor
        nbHOUSE = new String[] { plWOOD = "Les" },       //Sousedé
        ipHOUSE = new String[] { "Bábovka", "Víno", "Stůl", "Panenka", },
        EMPTYsa = new String[] { },                      //H-objekty v batohu
        null,       //Žádné příznaky na počátku neočekává
        List.of(    // Seznam "názvů" funkcí používaných pro složitější testy
            "argument_present",   //Argument je v aktuálním prostoru
            "argument_wakeable",  //Argument je buditelný
            "argument_sleeping",  //Argument spí
            "wakeable_present",   //V aktuálním prostoru je buditelný h-objekt
            "waken_present",      //V prostoru je probuzený, ale nepozdravený ho
            "greeted_present"     //V prostoru je již pozdravený h-objekt
        ),
        Map.of( //Mapa názvů příznaků a jejich výchozích hodnot.
           "grandma.sleeping",  true,   //Babička spí
           "grandma.greeted",   false,  //Babička je již pozdravená
           "wolf.sleeping",     true,   //Vlk spí
           "wolf.greeted",      false   //Vlk je již pozdravený
        )
    );

// Další atributy neinicializované ve scénářích:
    dsHOUSE = "Domeček, kde bydlí Karkulka";
    plCAVE  = "Jeskyně";
    dsCAVE  = "Jeskyně, kde v zimě přespává medvěd";
    nbCAVE  = new String[] {"Temný_les"};
    ipCAVE  = new String[] {"#Medvěd", "_Kosti"};


////////////////////////////////////////////////////////////////////////////////
BASIC = new Scenario(scBASIC,
    START_STEP,
    new ScenarioStep(1, tsGOTO, "Jdi Les",
        (anGOTO = "Karkulka se přesunula do prostoru:\n")
      + (dsWOOD = "Les s jahodami, malinami a pramenem vody"),
        plWOOD,                                          //Aktuální prostor
        nbWOOD = new String[] { "Domeček", "Temný_les" },//Sousedé
        ipWOOD = new String[] { "Maliny", "Jahody", "Studánka", },
        EMPTYsa                                          //H-objekty v batohu
    ),
    new ScenarioStep(tsTAKE, "Vezmi Maliny",
        (anTAKE = "Karkulka dala do košíku objekt: ") + "Maliny",
        plWOOD,                                          //Aktuální prostor
        nbWOOD,                                          //Sousedé
        ipSTART = new String[] { "Jahody", "Studánka", },//H-obj. v prostoru
        bgSTART = new String[] { "Maliny", }             //H-objekty v batohu
    ),
    new ScenarioStep(tsPUT_DOWN, "Polož Maliny",
        (anPUT = "Karkulka vyndala z košíku objekt: ") + "Maliny",
        plWOOD, nbWOOD, ipWOOD, EMPTYsa
    ),
    new ScenarioStep(tsTAKE, "Vezmi Maliny",
        anTAKE + "Maliny",
        plWOOD, nbWOOD, ipSTART, bgSTART
    ),
    new ScenarioStep(tsHELP, "?",
        anHELP = SUBJECT + "\nMůžete zadat tyto příkazy:\n",
        plWOOD, nbWOOD, ipSTART, bgSTART
    ),
    new ScenarioStep(tsEND, "konec",
        anSTOP = "Ukončili jste hru.\nDěkujeme, že jste si zahráli.",
        plWOOD, nbWOOD, ipSTART, bgSTART
    )
); //Konec scénáře BASIC


////////////////////////////////////////////////////////////////////////////////
MISTAKES = new Scenario(scMISTAKES,
    new ScenarioStep(-1, tsNOT_START, "Start",
        anNOT_START = "\nPrvním příkazem není startovací příkaz." +
        "\nHru, která neběží, lze spustit pouze startovacím příkazem.\n",
        "", EMPTYsa, EMPTYsa, EMPTYsa   //Před startem na stavu nezáleží
    ),
    START_STEP,
    new ScenarioStep(1, tsEMPTY, "",
        anEMPTY = "Prázdný příkaz lze použít pouze pro start hry",
        plHOUSE, nbHOUSE, ipHOUSE, EMPTYsa
    ),
    new ScenarioStep(tsUNKNOWN, "maso",
        (anUNKNOWN = "Tento příkaz neznám: ") + "maso",
        plHOUSE, nbHOUSE, ipHOUSE, EMPTYsa
    ),
    new ScenarioStep(tsMOVE_WA, "jdi",
        anMOVE_WA = "Nevím, kam mám jít.\n"
      + "Je třeba zadat jméno cílového prostoru.",
        plHOUSE, nbHOUSE, ipHOUSE, EMPTYsa
    ),
    new ScenarioStep(tsTAKE_WA, "vezmi",
        anTAKE_WA = "Nevím, co mám zvednout.\n"
      + "Je třeba zadat jméno zvedaného objektu.",
        plHOUSE, nbHOUSE, ipHOUSE, EMPTYsa
    ),
    new ScenarioStep(tsPUT_DOWN_WA, "polož",
        anPUT_DOWN_WA = "Nevím, co mám položit.\n"
      + "Je třeba zadat jméno pokládaného objektu.",
        plHOUSE, nbHOUSE, ipHOUSE, EMPTYsa
    ),
    new ScenarioStep(tsBAD_NEIGHBOR, "jdi do_háje",
        (anBAD_NEIGHBOR = "Do zadaného prostoru se odsud jít nedá: ") + "do_háje",
        plHOUSE, nbHOUSE, ipHOUSE, EMPTYsa
    ),
    new ScenarioStep(tsBAD_ITEM, "vezmi whisky",
        (anBAD_ITEM = "Zadaný objekt v prostoru není: ") + "whisky",
        plHOUSE, nbHOUSE, ipHOUSE, EMPTYsa
    ),
    new ScenarioStep(tsUNMOVABLE, "vezmi stůl",
        (anUNMOVABLE = "Zadaný objekt není možné zvednout: ") + "stůl",
        plHOUSE, nbHOUSE, ipHOUSE, EMPTYsa
    ),
    new ScenarioStep(tsTAKE, "vezmi víno",
        anTAKE + "víno",
        plHOUSE, nbHOUSE,
        new String[] { "Bábovka", "Stůl", "Panenka", }, // H-obj. v prostoru
        new String[] { "Víno", }                        // H-objekty v batohu
    )
    ,
    new ScenarioStep(tsTAKE, "vezmi bábovka",
        anTAKE + "Bábovka",
        plHOUSE, nbHOUSE,
        ipBAG_FULL = new String[] { "Stůl", "Panenka", }, // H-obj. v prostoru
        ibBAG_FULL = new String[] { "Bábovka", "Víno", }  // H-objekty v batohu
    ),
    new ScenarioStep(tsBAG_FULL, "vezmi panenka",
        (anBAG_FULL = "Zadaný objekt se už do košíku nevejde: ") + "panenka",
        plHOUSE, nbHOUSE, ipBAG_FULL, ibBAG_FULL
    ),
    new ScenarioStep(tsNOT_IN_BAG, "polož panenka",
        (anNOT_IN_BAG = "Zadaný objekt v košíku není: ") + "panenka",
        plHOUSE, nbHOUSE, ipBAG_FULL, ibBAG_FULL
    ),
    new ScenarioStep(tsEND, "konec",
        anSTOP,
        plHOUSE, nbHOUSE, ipBAG_FULL, ibBAG_FULL
    )
); //Konec scénáře MISTAKES


////////////////////////////////////////////////////////////////////////////////
HAPPY = new Scenario(scHAPPY,
    START_STEP,
    new ScenarioStep(1, tsTAKE, "Vezmi víno",
        anTAKE + "Víno",
        plHOUSE, nbHOUSE,
        new String[] { "Bábovka", "Stůl", "Panenka", }, // H-obj. v prostoru
        new String[] { "Víno", }                        // H-objekty v batohu
    ),
    new ScenarioStep(tsTAKE, "Vezmi Bábovka",
        anTAKE + "Bábovka",
        plHOUSE, nbHOUSE,
        new String[] { "Stůl", "Panenka", },            // H-obj. v prostoru
        ibWOOD = new String[] { "Bábovka", "Víno", }    // H-objekty v batohu
    ),
    new ScenarioStep(tsGOTO, "Jdi Les",
        anGOTO + dsWOOD,
        plWOOD, nbWOOD, ipWOOD, ibWOOD
    ),
    new ScenarioStep(tsGOTO, "Jdi Temný_les",
        anGOTO
      + (dsFOREST= "Temný_les s jeskyní a číhajícím vlkem"),
        plFOREST = "Temný_les",                         // Aktuální prostor
        nbFOREST = new String[] { "Les", "Jeskyně", "Chaloupka", },
        ipFOREST = new String[] { inWOLF = "Vlk", },    // H-obj. v prostoru
        ibWOOD                                          // H-objekty v batohu
    ),
    new ScenarioStep(tsGOTO, "Jdi Chaloupka",
        anGOTO
      + (dsCOTTAGE = "Chaloupka, kde bydlí " + (inGRANDMA="Babička")),
        plCOTTAGE = "Chaloupka",                        // Aktuální prostor
        nbCOTTAGE = new String[] { "Temný_les" },       // Sousedé
        ipCOTTAGE = new String[] { "Postel", "Stůl", inGRANDMA, },
        ibWOOD                                          // H-objekty v batohu
    ),
    new ScenarioStep(tsPUT_DOWN, "Polož Bábovka",
        anPUT + "Bábovka",
        plCOTTAGE,  nbCOTTAGE,
        new String[] { "Postel", "Stůl", inGRANDMA, "Bábovka", },
        new String[] { "Víno", }                        // H-objekty v batohu
    ),
    new ScenarioStep(tsPUT_DOWN, "Polož Víno",
        anPUT + "Víno",
        plCOTTAGE,  nbCOTTAGE,
        ipWAKE_UP = new String[] {"Postel","Stůl",inGRANDMA,"Bábovka","Víno",},
        EMPTYsa                                         // H-objekty v batohu
    ),
    new ScenarioStep(tsNS_1, "Probuď " + inGRANDMA,
            (anWAKE_UP = "Karkulka probudila objekt ") + inGRANDMA,
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa,
        Map.of(),    //Babička musí ještě spát - to prověří testy
        List.of("argument_present",         //Argument musí být přítomen
                "argument_wakeable",        //Argument musí být probuditelný
                "argument_sleeping"),       //Buzený objekt musí spát
        Map.of("grandma.sleeping",  false)  //Babička už je probuzena
    ),
    new ScenarioStep(tsNS_0, "Pozdrav",
        (anGREETING = "Karkulka pozdravila objekt ") + inGRANDMA,
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa,
        Map.of("grandma.greeted",   false), //B. ještě nesmí být pozdravena
        List.of("waken_present"),   //Je přítomen probuzený, nepozdravený objekt
        Map.of("grandma.greeted",   true)   //Babička už je pozdravena
    ),
    new ScenarioStep(tsSUCCESS, "Popřej",
        (anSUCCESSa = "Karkulka popřála objektu ") + inGRANDMA
      + (anSUCCESSb = " vše nejlepší k narozeninám\n"
      + "Úspěšně jste ukončili hru.\n"
      + "Děkujeme, že jste si zahráli."),
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa,
        Map.of(),   //Následující test prověřuje, je-li h-objekt pozdraven
        List.of("greeted_present"),      // Je přítomen pozdravený objekt
        null                             // Už se nic nenastavuje
    )
);  //Konec scénáře HAPPY


////////////////////////////////////////////////////////////////////////////////
// Chybový scénář pomocných akcí demonstrující průběh hry, při němž hráč
// zadává chybně příkazy k provedení povinně definovaných pomocných akcí.
MISTAKES_NS  = new Scenario(scMISTAKES_NS,
    START_STEP
    ,
    new ScenarioStep(1, tsNS0_WrongCond, "Pozdrav",
        erMS0_GREET_NOBODY = "V aktuálním prostoru není koho zdravit.",
        plHOUSE, nbHOUSE, ipHOUSE, EMPTYsa,
        null,           // Smí být pouze jeden nesplněný test - ten následuje
        List.of("waken_present"),             // Musí tam být někdo probuzený
        null
    ),
    new ScenarioStep(tsNOT_SUCCESS, "Popřej",
        erSUCCESS_NOBODY = "V aktuálním prostoru není komu popřát.",
        plHOUSE, nbHOUSE, ipHOUSE, EMPTYsa,
        null,   // Smí být pouze jeden nesplněný test -- ten následuje
        List.of("greeted_present")    // Musí tam být někdo pozdravený
    ),
    new ScenarioStep(HAPPY.steps().get(1)),   //Vezmi víno
    new ScenarioStep(HAPPY.steps().get(2)),   //Vezmi Bábovka
    new ScenarioStep(HAPPY.steps().get(3)),   //Jdi les
    new ScenarioStep(HAPPY.steps().get(4)),   //Jdi Temný_les
    new ScenarioStep(HAPPY.steps().get(5)),   //Jdi Chaloupka
    new ScenarioStep(HAPPY.steps().get(6)),   //Polož Bábovka
    new ScenarioStep(HAPPY.steps().get(7)),   //Polož Víno

    new ScenarioStep(tsNS0_WrongCond, "Pozdrav",
        (erNS0_GREET_WAKEa = "Nemá smysl zdravit, osoba ")
                           + inGRANDMA
      + (erNS0_GREET_WAKEb = " ještě není probuzená"),
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa,
        null,
        List.of("waken_present")    //Očekávaný nesplněný test
    ),
    new ScenarioStep(tsNS1_0Args, "Probuď",
        erNS1_WAKE_WA = "Nevím, koho mám probudit.\n"
                      + "Je třeba zadat jméno buzeného h-objektu.",
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa
    ),
    new ScenarioStep(tsNS1_WrongCond, "Probuď " + inWOLF,
        (erNS1_WAKE_NO_HERE = "Nelze budit nepřítomný objekt ")
                            + inWOLF,
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa,
        null,   // Smí být pouze jeden nesplněný test -- ten následuje
        List.of("argument_present")    //Očekávaný nesplněný test
    ),
    new ScenarioStep(tsNS1_WrongCond, "Probuď stůl",
        (erNS1_WAKE_WRONG_ARG = "Nelze budit předmět: ")
                              + "Stůl",
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa,
        null,   // Smí být pouze jeden nesplněný test -- ten následuje
        List.of("argument_wakeable")    //Očekávaný nesplněný test
    ),
    new ScenarioStep(tsNS_1, "Probuď " + inGRANDMA,
        anWAKE_UP + inGRANDMA,
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa,
        Map.of("grandma.sleeping",  true),  // Babička musí ještě spát
        List.of("argument_present",         // Argument musí být přítomen
                "argument_wakeable"),       // Argument musí být probuditelný
        Map.of("grandma.sleeping",  false)  // Babička už je probuzena
    ),
    new ScenarioStep(tsNS1_WrongCond, "Probuď " + inGRANDMA,
        (erNS1_WAKE_2NDa = "Nelze budit osobu ")
                         + inGRANDMA
      + (erNS1_WAKE_2NDb = ", protože je již probuzená."),
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa,
        null,   // Smí být pouze jeden nesplněný test -- ten následuje
        List.of("argument_sleeping")    //Očekávaný nesplněný test
    ),
    new ScenarioStep(tsNOT_SUCCESS, "Popřej",
        (erSUCCESS_GREETa = "Nemůžete přát osobě ")
                          + inGRANDMA
      + (erSUCCESS_GREETb = ", protože ještě nebyla pozdravena"),
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa,
        null,   // Smí být pouze jeden nesplněný test -- ten následuje
        List.of("greeted_present")    //Očekávaný nesplněný test
    ),
    new ScenarioStep(tsNS_0, "Pozdrav",
        anGREETING + inGRANDMA,
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa,
        Map.of("grandma.greeted",   false), // B. ještě nesmí být pozdravena
        List.of("waken_present"),           // Jeí přítomen probuzený objekt
        Map.of("grandma.greeted",   true)   // Babička už je pozdravena
    ),
    new ScenarioStep(tsNS0_WrongCond, "Pozdrav",
        (erNS0_GREET_2NDa = "Nemá smysl zdravit osobu ")
                          + inGRANDMA
      + (erNS0_GREET_2NDb = ", protože již byla pozdravena"),
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa,
        Map.of("grandma.greeted",   false), // B. ještě nesmí být pozdravena
        null    // Smí být pouze jeden nesplněný test -- ne už je
    ),
    new ScenarioStep(tsEND, "konec",
        anSTOP,
        plCOTTAGE, nbCOTTAGE, ipWAKE_UP, EMPTYsa
    )
);

} //Konec statického inicializačního bloku



//===== CLASS (STATIC) GETTERS AND SETTERS =====================================

    /***************************************************************************
     * Vrátí seznam definovaných scénářů.
     *
     * @return Seznam spravovaných scénářů
     */
    public static List<Scenario> scenarios()
    {
        return List.of(HAPPY, BASIC, MISTAKES, MISTAKES_NS);
    }


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

    private ScenarioManager() {}

}
