/src/objecteditor.ts
import FragmentManager from './fragmentmanager';
import { GameObject } from './object';
import { ID } from './id';
import gs from './gamestate';

export default class ObjectEditor {
    container: FragmentManager
    listRef: HTMLSelectElement
    idRef: HTMLInputElement
    nameRef: HTMLInputElement
    descriptionRef: HTMLTextAreaElement
    originalID: ID

    constructor() {
        this.container = new FragmentManager(`
            <div class="box vflex">
                <h1>Object Editor</h1>
                <div class="hflex flex-auto">
                    <div class="vflex" style="width: 200px; margin-right: 8px">
                        <select multiple name="objectlist" class="flex-auto" style="width: calc(100% - 8px)">
                        </select>
                        <div class="hflex">
                            <button id="object-add" class="flex-auto">+</button>
                            <button id="object-remove" class="flex-auto">-</button>
                        </div>
                    </div>
                    <div class="vflex flex-auto">
                        <h2>ID</h2>
                        <input name="id">
                        <h2>Name</h2>
                        <input name="name">
                        <h2>Description</h2>
                        <textarea name="description" class="flex-auto"></textarea>
                    </div>
                </div>
                <div class="hflex">
                    <button id="object-editor-close">Close</button>
                </div>
            </div>
        `);
        this.container.mountInto('object-editor-container');

        this.container.elem.addEventListener('keydown', function(e: KeyboardEvent) {
            e.cancelBubble = true;
        });

        this.listRef = <HTMLSelectElement>this.container.q('[name="objectlist"]');
        this.idRef = <HTMLInputElement>this.container.q('[name="id"]');
        this.nameRef = <HTMLInputElement>this.container.q('[name="name"]');
        this.descriptionRef = <HTMLTextAreaElement>this.container.q('[name=description]');

        const closeButton = this.container.q('#object-editor-close');
        closeButton.addEventListener('click', this.closeHandler.bind(this));

        const objectAddButton = this.container.q('#object-add');
        objectAddButton.addEventListener('click', this.createObject.bind(this));

        const objectRemoveButton = this.container.q('#object-remove');
        objectRemoveButton.addEventListener('click', this.deleteObject.bind(this));

        this.listRef.addEventListener('change', event => {
            const id = (<HTMLInputElement>event.target).value;
            this.commitObject();
            this.selectObject(id);
        });
    }

    open(object?: GameObject) {
        this.refreshObjectList();

        if (object) {
            this.selectObject(object.id);
        }

        this.container.elem.classList.add('visible');
        this.nameRef.focus();
    }

    refreshObjectList() {
        while (this.listRef.firstChild)
            this.listRef.removeChild(this.listRef.firstChild);

        for (let [k, v] of gs.objects) {
            const option = document.createElement('option');
            option.value = k;
            option.innerText = v.name;
            this.listRef.appendChild(option);
        }
    }

    selectObject(id?: ID) {
        if (id) {
            if (!gs.objects.has(id)) {
                throw new Error('Invalid object ID: ' + id);
            }
        }

        for (let i = 0; i < this.listRef.children.length; i++) {
            const child = <HTMLOptionElement>this.listRef.children[i];
            child.selected = child.value == id;
        }

        if (id) {
            const object = gs.objects.get(id);

            this.idRef.value = this.originalID = object.id;
            this.nameRef.value = object.name || 'Unnamed Object';
            this.descriptionRef.value = object.description || '';
        } else {
            this.originalID = undefined;
            this.idRef.value = '';
            this.nameRef.value = '';
            this.descriptionRef.value = '';
        }
    }

    createObject() {
        this.commitObject();
        const obj = new GameObject();
        obj.name = 'Unnamed Object';
        gs.addObject(obj);
        this.refreshObjectList();
        this.selectObject(obj.id);
    }

    deleteObject() {
        this.commitObject();
        const objID = this.originalID;
        const obj = gs.objects.get(objID);
        if (window.confirm("Really delete " + obj.name + "?")) {
            gs.removeObject(objID);
            this.refreshObjectList();
            this.selectObject(null);
        }
    }

    commitObject() {
        if (!this.originalID) return;
        const obj = gs.objects.get(this.originalID);
        obj.name = this.nameRef.value;
        obj.description = this.descriptionRef.value;

        const objID = this.idRef.value
        if (objID != this.originalID) {
            gs.removeObject(this.originalID);
            obj.id = objID;
            gs.addObject(obj);
            this.refreshObjectList();
            this.selectObject(objID);
        } else {
            this.refreshObjectList();
        }
    }

    close() {
        this.closeHandler();
    }

    closeHandler() {
        this.commitObject();
        this.container.elem.classList.remove('visible');
    }
}