/// <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" />
/// <reference path="../../../Elements/Modules/InventoryHandler.ts" />

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

    /**
     * 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 "drop " + (this.getNoun(0) != undefined ? this.getNoun(0).getPrintedName() : "");
    }
}

ActionDrop.check.addRule(
    new Rule({
        name : "Check Dropping - Are you Wearing it?",
        firstPriority : Rule.PRIORITY_LOWEST,
        code : async (rulebook : RulebookRunner<ActionDrop>) => {
            let action = <ActionGo> rulebook.noun;
            let actor = action.actor;
            let thing = (<Thing>action.getNoun(0));

            if (Thing.WearRelation.getLeft(thing) == actor || Thing.WieldRelation.getLeft(thing) == actor){
                if (action.actor == WorldState.player) {
                    action.say.add("(first taking off the ", thing, ")", Say.LINE_BREAK);
                }
                let takingAction = new ActionRemove(actor, thing);
                await takingAction.execute();
                action.say.add(takingAction.say);
                if (Thing.WearRelation.getLeft(thing) == actor || Thing.WieldRelation.getLeft(thing) == actor) {
                    return false;
                }
                action.say.add(Say.LINE_BREAK);
            }
        }
    })
);

ActionDrop.check.addRule(
    new Rule({
        name : "Check Dropping - Do you have it??",
        firstPriority : Rule.PRIORITY_LOWEST,
        code : (rulebook : RulebookRunner<ActionDrop>) => {
            let action = <ActionGo> rulebook.noun;
            let actor = action.actor;
            let thing = (<Thing>action.getNoun(0));

            if (Thing.CarryRelation.getLeft(thing) != actor){
                if (actor == WorldState.player) {
                    action.say.add("You don't have it.");
                }
                return false;
            }
        }
    })
);

ActionDrop.carry.addRule(
    new Rule({
        name : "Dropping - Place the noun on the floor",
        code : (rulebook : RulebookRunner<ActionDrop>) => {
            let action = <ActionGo> rulebook.noun;
            let actor = action.actor;
            let thing = (<Thing>action.getNoun(0));

            Thing.EnclosedRelation.unsetRight(thing);

            actor.getRoom().place(thing);

            if (actor == WorldState.player) {
                action.say.add(new SayBold((<Thing> action.getNoun(0)).getPrintedName() + ": "), "Dropped.");
            } else {
                action.say.add(new SayThe(), actor, " drops ", new SayThe(), (<Thing> action.getNoun(0)), " on the floor.");
            }
        }
    })
);

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

            if (Thing.CarryRelation.getLeft(thing) == WorldState.player || Thing.WieldRelation.getLeft(thing) == WorldState.player || Thing.WearRelation.getLeft(thing) == WorldState.player) {
                Elements.HyperlinkHandler.addAvailableAction("Drop", new ActionDrop(WorldState.player, thing));
            }
        }
    }
));

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

            Elements.InventoryHandler.printThingLink("D", new ActionDrop(WorldState.player, thing));
        }
    }
));