import List from '../../../src/core/collection/list/List.js';
import Signal from '../../../src/core/events/signal/Signal.js';
import ObservedValue from '../../../src/core/model/ObservedValue.js';
import LabelView from '../../../src/view/common/LabelView.js';
import VirtualListView from '../../../src/view/common/VirtualListView.js';
import dom from "../../../src/view/DOM.js";
import ButtonView from '../../../src/view/elements/button/ButtonView.js';
import EmptyView from "../../../src/view/elements/EmptyView.js";
import View from "../../../src/view/View.js";

import SelectionAddAction from '../../actions/concrete/SelectionAddAction.js';
import SelectionRemoveAction from '../../actions/concrete/SelectionRemoveAction.js';

class EntityView extends EmptyView {
    /**
     *
     * @param entity
     * @param {EntityComponentDataset} entityDataset
     * @constructor
     */
    constructor(entity, entityDataset) {
        super({
            classList: [
                'entity-view'
            ]
        });


        this.model = entity;

        const lId = new LabelView(entity, { classList: ['id'] });
        lId.position.setX(0);
        this.addChild(lId);

        this.isSelected = new ObservedValue(false);

        const dCheckBox = dom('div');
        dCheckBox.addClass('selection');

        this.isSelected.onChanged.add(function (v) {
            dCheckBox.setClass('selected', v);
        });

        if (this.on === undefined) {
            this.on = {};
        }

        const signals = this.on;

        signals.selected = new Signal();

        dCheckBox.on('click', function () {
            signals.selected.send0();
        });

        this.el.appendChild(dCheckBox.el);
    }
}


class EntityListView extends View {
    /**
     *
     * @param {Editor} editor
     * @param { (function(entity:number, ecd:EntityComponentDataset, view:View):void)[]} decorators
     */
    constructor({
                    editor,
                    decorators = []
                }) {
        super();

        this.el = document.createElement('div');
        this.addClass('entity-list-view');

        if (this.on === undefined) {
            this.on = {};
        }

        this.on.interaction = new Signal();

        const hiddenEntities = new List();

        const self = this;
        this.editor = editor;

        function makeElement(entity) {
            const entityManager = editor.engine.entityManager;
            const entityDataset = entityManager.dataset;

            const entityView = new EntityView(entity, entityDataset);

            const decorator_count = decorators.length;

            for (let i = 0; i < decorator_count; i++) {
                const decorator = decorators[i];

                decorator(entity, entityDataset, entityView);
            }

            if (editor.selection.contains(entity)) {
                entityView.isSelected.set(true);
            }

            entityView.on.selected.add(function () {
                const actions = self.editor.actions;
                actions.mark();
                const value = !entityView.isSelected.get();
                if (value) {
                    actions.do(new SelectionAddAction([entity]));
                } else {
                    actions.do(new SelectionRemoveAction([entity]));
                }
            });

            entityView.el.addEventListener('click', function () {
                self.on.interaction.dispatch(entity);
            });

            return entityView;
        }

        const entityList = new List();


        const list = new VirtualListView(entityList, {
            lineSize: 20,
            elementFactory: makeElement
        });

        list.size.set(150, 600);

        const actionAdd = {
            name: "Add",
            action: function () {
                const dataset = editor.engine.entityManager.dataset;

                if (dataset !== null) {
                    dataset.createEntity();
                }
            }
        };

        const vToolBar = new EmptyView();

        const vAddButton = new ButtonView(actionAdd);
        vAddButton.size.set(100, 20);

        vToolBar.addChild(vAddButton);

        this.addChildAt(list, 0, 0, 0, 0);
        this.addChildAt(vToolBar, 0, 1, 0, 0);


        function addOne(entity) {
            //exclude editor-owned entities
            if (editor.isEditorEntity(entity)) {
                hiddenEntities.add(entity);

            } else {
                entityList.add(entity);
            }
        }

        function removeOne(entity) {
            const hiddenIndex = hiddenEntities.indexOf(entity);
            if (hiddenIndex !== -1) {
                hiddenEntities.remove(hiddenIndex);
            } else {
                entityList.removeOneOf(entity);
            }
        }

        function selectOne(entity) {
            list.renderedViews.forEach(function (v) {
                if (v.model === entity) {
                    v.isSelected.set(true);
                }
            });
        }

        function deselectOne(entity) {
            list.renderedViews.forEach(function (v) {
                if (v.model === entity) {
                    v.isSelected.set(false);
                }
            });
        }

        this.handlers = {
            addOne: addOne,
            removeOne: removeOne,
            selectOne: selectOne,
            deselectOne: deselectOne,
            reset: function () {
                //reset all
                entityList.reset();
                hiddenEntities.reset();
            }
        };

        const layout = () => {
            const size = this.size;

            list.size.set(size.x, size.y - 20);
            vToolBar.size.set(size.x, 20);
            vToolBar.position.set(0, list.size.y + list.position.y);
        }

        const handlers = this.handlers;

        //listen for selection
        this.bindSignal(editor.selection.on.added, handlers.selectOne);
        this.bindSignal(editor.selection.on.removed, handlers.deselectOne);
        this.size.onChanged.add(layout);
        this.on.linked.add(layout);
    }

    layout() {

    }

    link() {
        super.link();

        const entityManager = this.editor.engine.entityManager;

        const handlers = this.handlers;

        //list all active
        const dataset = entityManager.dataset;
        dataset.traverseEntityIndices(function (id) {
            handlers.addOne(id);
        });

        //propagate current selection
        this.editor.selection.forEach(handlers.selectOne);


        dataset.onEntityCreated.add(handlers.addOne);
        dataset.onEntityRemoved.add(handlers.removeOne);

    }

    unlink() {
        super.unlink();

        const entityManager = this.editor.engine.entityManager;
        const dataset = entityManager.dataset;

        const handlers = this.handlers;

        //clear out entity list
        this.handlers.reset();

        dataset.onEntityCreated.remove(handlers.addOne);
        dataset.onEntityRemoved.remove(handlers.removeOne);
    }
}


export default EntityListView;
