var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import * as EventEmitter from 'eventemitter3';
import { SoundManager } from './sound-manager';
import { KeyboardManager } from './keyboard-manager';
export class Menu extends EventEmitter {
    constructor(title = 'Menu', menuItems = [], soundSet = null, defaultAction = null, cancelAction = null) {
        super();
        this.title = title;
        this.menuItems = menuItems;
        this.soundSet = soundSet;
        this.defaultAction = defaultAction;
        this.cancelAction = cancelAction;
        this.currentIndex = 0;
        this.DOMNodes = [];
        this.currentIndex = 0;
        this.currentItem = null;
        this.soundManager = new SoundManager(soundSet);
        this.keyboardManager = new KeyboardManager(this);
        this.init();
    }
    init() {
        this.menuItems[this.currentIndex] &&
            this.menuItems[this.currentIndex].focus();
        this.emit('init');
    }
    addItem(item) {
        this.menuItems.push(item);
        this.emit('item.add', item);
        return this;
    }
    setTitle(title) {
        this.title = title;
        return this;
    }
    setSoundSet(soundSet) {
        this.soundSet = soundSet;
        this.soundManager.setSoundSet(this.soundSet);
        return this;
    }
    setDefaultAction(id) {
        this.defaultAction = id;
        return this;
    }
    setCancelAction(id) {
        this.cancelAction = id;
        return this;
    }
    run(element) {
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                this.element = element;
                this.container = document.createElement('div');
                this.titleContainer = document.createElement('h1');
                this.titleContainer.textContent = this.title;
                this.container.appendChild(this.titleContainer);
                this.menuItems.forEach((item) => {
                    this.appendToContainer(item.getDOMNode());
                    item.on('update', this.handleItemUpdate.bind(this));
                    item.on('focus', this.onItemFocus.bind(this));
                    item.on('choose', (event) => {
                        const menuMap = this.compile();
                        this.soundManager.handleSound('choose');
                        this.emit('choose', menuMap);
                        resolve(menuMap);
                    });
                });
                element.appendChild(this.container);
                this.soundManager.handleSound('open');
                this.keyboardManager.init();
                // push some data onto the history stack so that we can use the browser's back button to exit out of the menu.
                history.pushState({ menu: true }, null, null);
            });
        });
    }
    close() {
        this.container.remove();
        this.soundManager.handleSound('close');
        this.keyboardManager.release();
        this.DOMNodes.forEach((item) => {
            this.container.removeChild(item);
        });
        this.emit('close');
    }
    appendToContainer(node) {
        this.container.appendChild(node);
        this.DOMNodes.push(node);
    }
    handleItemUpdate(value) {
        this.soundManager.handleSound(value.type, value.value);
        this.emit('update', this.compile());
    }
    onItemFocus(id) {
        this.soundManager.handleSound('focus');
        this.currentIndex = this.menuItems.indexOf(this.menuItems.find((item) => item.getID() == id));
        this.emit('focus', this.menuItems[this.currentIndex]);
    }
    focusNext() {
        if (this.currentIndex < this.menuItems.length - 1) {
            this.currentIndex++;
        }
        this.focusCurrentIndex();
    }
    focusPrevious() {
        if (this.currentIndex > 0) {
            this.currentIndex--;
        }
        this.focusCurrentIndex();
    }
    focusCurrentIndex() {
        this.menuItems[this.currentIndex].focus();
    }
    getCurrentFocus() {
        return this.menuItems[this.currentIndex];
    }
    getContainer() {
        return this.container;
    }
    clickDefaultAction() {
        if (!this.defaultAction)
            return;
        const item = this.menuItems.find((item) => item.getID() === this.defaultAction);
        item.click();
    }
    clickCancelAction() {
        if (!this.cancelAction)
            return;
        const node = this.menuItems.find((item) => item.getID() === this.cancelAction);
        node.click();
    }
    compile() {
        const menuMap = new Map();
        this.menuItems.forEach((item) => menuMap.set(item.getID(), item.getContents()));
        menuMap.set('selected', this.menuItems[this.currentIndex].getID());
        return menuMap;
    }
}
export * from './items';