/// <reference path="../Things/Clothing.ts" />
/// <reference path="../Action.ts" />
/// <reference path="../Rule.ts" />
/// <reference path="../Rulebook.ts" />
/// <reference path="../../../Elements/Classes/Say/SayBold.ts" />
/// <reference path="../../../Elements/Modules/HyperlinkHandler.ts" />

class ActionWear extends Action {
    public static check: Rulebook<ActionWear> = new Rulebook("Check Wearing");
    public static carry: Rulebook<ActionWear> = new Rulebook("Carry out Wearing");

    /**
     * Needs to return a string explaining what the player will do if he does this action.
     * For instance, ActionTaking should return something like return "take " + this.nouns[0].getName(),
     *   which would read as "take thing".
     *   remember that things implement PRINTABLE interface, so you can get their names.
     * @returns {Say}
     */
    public getCommandText () {
        return "wear " + (this.getNoun(0) != undefined ? this.getNoun(0).getPrintedName() : "");
    }

    public getClothing () : Clothing{
        return this.getNoun(0);
    }

    public static checkIsWearable = ActionWear.check.createAndAddRule({
        name : "Is noun a clothing",
        firstPriority : Rule.PRIORITY_HIGHEST,
        code : (runner : RulebookRunner<ActionWear>) => {
            let action = runner.noun;
            let noun = action.getClothing();
            if (!(noun instanceof Clothing)) {
                if (action.actor == WorldState.player) {
                    action.say.add("You can only wear Clothing.");
                }
                return false;
            }
        }
    });

    public static checkIsHeld = ActionWear.check.createAndAddRule({
        name : "Is noun held",
        firstPriority : Rule.PRIORITY_HIGH,
        code : async (runner : RulebookRunner<ActionWear>) => {
            let action = runner.noun;
            let noun = action.getClothing();
            if (!Thing.CarryRelation.isRight(action.actor, noun)) {
                if (action.actor == WorldState.player) {
                    action.say.add("(first taking the ", noun, ")", Say.LINE_BREAK);
                }
                let takingAction = new ActionTake(action.actor, noun);
                await takingAction.execute();
                action.say.add(takingAction.say);
                if (!Thing.CarryRelation.isRight(action.actor, noun)) {
                    return false;
                }
            }
        }
    });

    public static carryDefault = ActionWear.carry.createAndAddRule({
        name : "Set Clothing as Worn",
        firstPriority : Rule.PRIORITY_MEDIUM,
        code : (runner : RulebookRunner<ActionWear>) => {
            let action = runner.noun;
            let noun = action.getClothing();
            Thing.WearRelation.setRelation(action.actor, noun);

            let actor = action.actor;
            let thing = (<Thing>action.getNoun(0));

            if (actor == WorldState.player) {
                action.say.add(new SayBold(thing, ": "), "Worn.");
            } else {
                action.say.add(new SayThe(), actor, " puts on ", new SayThe(), thing, ".");
            }
        }
    });
}

/**
 * Hyperlinking
 */
Elements.HyperlinkHandler.HyperlinkingRulebook.addRule(new Rule(
    {
        name : "Hyperlink - Wear",
        firstPriority : Rule.PRIORITY_HIGHEST,
        code : (rulebook : RulebookRunner<Thing>) => {
            let thing = <Thing> rulebook.noun;

            if (thing instanceof Clothing && !(Thing.WearRelation.isRight(WorldState.player, thing))) {
                Elements.HyperlinkHandler.addAvailableAction("Wear", new ActionWear(WorldState.player, thing));
            }
        }
    }
));

/**
 Inventory
 */
Elements.InventoryHandler.LinkingThing.addRule(new Rule(
    {
        name : "Inventory - Wear",
        firstPriority : Rule.PRIORITY_LOWEST,
        code : (rulebook : RulebookRunner<Thing>) => {
            let thing = <Thing> rulebook.noun;

            if (thing instanceof Clothing && !(Thing.WearRelation.isRight(WorldState.player, thing))) {
                Elements.InventoryHandler.printThingLink("W", new ActionWear(WorldState.player, thing));
            }
        }
    }
));