/src/script/menu.ts
import { ScriptInstruction, InstructionPromise, InstructionStatus, executeInstructions } from './';
import gs from '../gamestate';

enum MenuOptionType {
    Item,
    Buy,
    Exit,
}

enum MenuConditionType {
    Flag,
    Object,
}

interface MenuOptionCommon {
    kind: MenuOptionType
    label: string
    condition?: {
        negate: boolean,
        type: MenuConditionType,
        name: string,
    }
}

interface MenuItem extends MenuOptionCommon {
    kind: MenuOptionType.Item
    instructions: ScriptInstruction[]
}

interface MenuBuy extends MenuOptionCommon {
    kind: MenuOptionType.Buy
    object: string
    value: number
}

interface MenuExit extends MenuOptionCommon {
    kind: MenuOptionType.Exit
}

type MenuOption = MenuItem | MenuBuy | MenuExit

export class MenuInstruction implements ScriptInstruction {
    options: MenuOption[]

    constructor(options: any[]) {
        this.options = options.map(o => {
            const condition = o[0] && {
                negate: o[0][2] != null,
                type: o[0][3][0].value == '$' ? MenuConditionType.Flag : MenuConditionType.Object,
                name: o[0][3][1].value,
            };
            switch(o[1].value) {
                case 'item':
                    return <MenuItem>{
                        kind: MenuOptionType.Item,
                        label: o[3],
                        instructions: o[5],
                        condition,
                    };
                case 'buy':
                    const obj = gs.objects.get(o[3][1].value);
                    if (!obj) {
                        throw new Error('Object with id ' + o[3][1].value + ' doesn\'t exist in this world.');
                    }

                    let label;
                    if (o[5].value == 0) {
                        label = 'Take ' + obj.name;
                    } else {
                        label = 'Buy ' + obj.name + ' ($' + o[5].value + ')';
                    }

                    return <MenuBuy>{
                        kind: MenuOptionType.Buy,
                        label,
                        object: o[3][1].value,
                        value: o[5].value,
                        condition,
                    };
                case 'exit':
                    return <MenuExit>{
                        kind: MenuOptionType.Exit,
                        label: o[3],
                        condition,
                    };
                default:
                    throw new Error('Unknown menu item type: ' + o[1].value);
            }
        });
    }

    execute(): InstructionPromise {
        return new Promise( (resolve, reject) => {
            gs.actions.clear();
            for (let o of this.options) {
                if (o.condition) {
                    switch(o.condition.type) {
                    case MenuConditionType.Flag:
                        // TODO flags
                        break;
                    case MenuConditionType.Object:
                        let status = gs.playerInventory.has(o.condition.name) && gs.playerInventory.get(o.condition.name) > 0;
                        if (o.condition.negate) {
                            status = !status;
                        }
                        console.log(o.condition, status);
                        if (!status) continue;
                        break;
                    }
                }
                gs.actions.addAction(o.label, () => {
                    gs.actions.clear();
                    switch(o.kind) {
                        case MenuOptionType.Item:
                            resolve(executeInstructions(o.instructions));
                            break;
                        case MenuOptionType.Buy:
                            console.log('Buy', o.object, 'for', o.value);
                            gs.addInventory(o.object);
                            const objectName = gs.objects.get(o.object).name;
                            if (o.value == 0) {
                                gs.print("You have taken the", objectName);
                            } else {
                                gs.print("You have bought a", objectName, "for", '$' + o.value);
                            }
                            resolve({ status: InstructionStatus.OK });
                            break;
                        case MenuOptionType.Exit:
                            resolve({ status: InstructionStatus.OK });
                            break;
                    }
                });
            }
        });
    }
}