import { passThrough } from "../../src/core/function/passThrough.js";
import { ProcessState } from "../../src/core/process/ProcessState.js";
import LabelView from '../../src/view/common/LabelView.js';
import ListView from "../../src/view/common/ListView.js";
import VirtualListView from '../../src/view/common/VirtualListView.js';
import dom from "../../src/view/DOM.js";
import EmptyView from "../../src/view/elements/EmptyView.js";

import SimpleWindow from '../../src/view/elements/SimpleWindow.js';
import View from "../../src/view/View.js";
import ComponentControlFactory from './ecs/ComponentControlFactory.js';
import EntityEditorView from './ecs/EntityEditor.js';

import EntityListView from './ecs/EntityList.js';
import { HierarchicalEntityListView } from "./ecs/HierarchicalEntityListView.js";
import GridPickCoordinateView from "./GridPickCoordinateView.js";
import { makeEntityDecorators } from "./makeEntityDecorators.js";
import ProcessView from "./process/ProcessView.js";
import ToolSettingsView from "./tools/ToolSettingsView.js";
import ToolView from './tools/ToolView.js';
import { SplitView } from "./v2/SplitView.js";


class ViewManager extends View {
    constructor() {
        super();
        const dRoot = dom('div');
        dRoot.addClass('view-manager');

        this.el = dRoot.el;

        this.storage = [];

        //store parameters of previously opened windows
        this.memory = {};
    }

    /**
     *
     * @param {View} view
     * @param {string} [title]
     * @returns {SimpleWindowView}
     */
    add(view, title = "") {
        const simpleWindow = new SimpleWindow(
            view,
            {
                draggable: true,
                closeable: false,
                resizable: true,
                title: title
            }
        );

        this.storage.push({
            original: view,
            window: simpleWindow
        });

        this.addChild(simpleWindow);

        if (this.memory.hasOwnProperty(title)) {
            const windowParams = this.memory[title];
            view.size.copy(windowParams.size);
            simpleWindow.position.copy(windowParams.position);
        }

        return simpleWindow;
    }

    exists(view) {
        return this.getInternalIndex(view) !== -1;
    }

    getInternalIndex(view) {
        for (let i = 0; i < this.storage.length; i++) {
            const el = this.storage[i];
            if (el.original === view) {
                return i;
            }
        }
        return -1;
    }

    remove(view) {
        //find the window
        const internalIndex = this.getInternalIndex(view);

        if (internalIndex === -1) {
            return false;
        }

        const el = this.storage[internalIndex];
        //cut from internal index
        this.storage.splice(internalIndex, 1);

        const vWindow = el.window;
        this.removeChild(vWindow);

        //remember window parameters
        this.memory[vWindow.title.get()] = {
            position: vWindow.position.clone(),
            size: view.size.clone()
        };

        return true;
    }
}


class EditorView extends View {
    main = new EmptyView()

    mainViewport = new EmptyView();

    /**
     *
     * @param {Editor} editor
     * @constructor
     */
    constructor(editor) {
        super(editor);

        const dRoot = dom('div');
        dRoot.addClass('editor-view');

        this.el = dRoot.el;

        /**
         *
         * @type {Editor}
         */
        this.editor = editor;

        /**
         *
         * @type {View|null}
         */
        this.gameView = null;

        const decorators = makeEntityDecorators();


        const entity_list_view = new HierarchicalEntityListView();

        entity_list_view.dataset = editor.engine.entityManager.dataset;
        entity_list_view.on.interact.add(inspectEntity);

        const entityListView = new EntityListView({ editor, decorators });
        this.entityListView = entityListView;

        //entity editor
        const controllerFactory = new ComponentControlFactory();
        const entityEditor = new EntityEditorView(controllerFactory, editor);

        this.entityEditor = entityEditor;

        function inspectEntity(entity) {
            const em = editor.engine.entityManager;
            entityEditor.entityManager.set(em);
            entityEditor.model.set(entity);

            entity_list_view.selection = [entity];
        }

        this.bindSignal(editor.selection.on.added, function (entity) {
            if (editor.selection.length === 1) {
                //when first thing is selected - inspect it automatically
                inspectEntity(entity);
            }
        });

        entityListView.on.interaction.add(inspectEntity);
        this.entityListView = entityListView;

        const toolSettings = new ToolSettingsView({});
        this.toolSettings = toolSettings;

        const toolBar = new ListView(editor.toolEngine.tools, {
            elementFactory: function (tool) {
                const toolView = new ToolView({ tool, editor });

                toolView.el.addEventListener('click', function () {
                    editor.toolEngine.activate(tool.name);
                    toolSettings.setTool(tool);
                });

                const activeTool = editor.toolEngine.active;

                function handleActivation() {
                    toolView.el.classList.toggle('active', activeTool.getValue() === tool);
                }

                toolView.on.linked.add(handleActivation);
                toolView.bindSignal(activeTool.onChanged, handleActivation);

                return toolView;
            },
            classList: ['editor-tool-bar']
        });
        this.toolBar = toolBar;

        //tool bar
        const processBar = new ListView(editor.processEngine.processes, {
            elementFactory: function (process) {
                const toolView = new ProcessView(process);
                toolView.el.addEventListener('click', function () {
                    if (process.__state.getValue() !== ProcessState.Running) {
                        editor.processEngine.startByName(process.name);
                    } else {
                        editor.processEngine.stopByName(process.name);
                    }
                });

                return toolView;
            },
            classList: ['editor-process-bar']
        });
        this.processBar = processBar;

        //selection list
        const selectionView = new VirtualListView(editor.selection, {
            elementFactory: function (entity) {
                const labelView = new LabelView(entity, { format: passThrough });
                labelView.el.addEventListener('click', function () {
                    inspectEntity(entity);
                });
                return labelView;
            },
            classList: ['selected-entities']
        });

        selectionView.size.set(70, 120);
        this.selectionView = selectionView;


        this.coordinateView = new GridPickCoordinateView(editor);

        //
        this.bindSignal(this.size.onChanged, this.layout.bind(this));


        this.mainViewport.addChild(this.coordinateView);
        this.mainViewport.addChild(this.selectionView);
        this.mainViewport.addChild(this.toolBar);
        this.mainViewport.addChild(this.processBar);
        this.mainViewport.addChild(this.toolSettings);


        const split = SplitView.from({
            fraction: 0.2,
            a: entity_list_view,
            b: SplitView.from({
                fraction: 0.7,
                a: this.mainViewport,
                b: this.entityEditor,
            })
        });
        this.main.addChild(split);

        this.main.size.onChanged.add(split.size.set, split.size);

        this.addChild(this.main);
    }

    layout() {
        const size = this.size;

        this.main.size.copy(size);
        if (this.gameView !== null) {
            this.toolBar.size.set(this.gameView.size.x, 36);
            this.toolBar.position.set(this.gameView.position.x + 5, this.gameView.position.y + this.gameView.size.y - (this.toolBar.size.y + 5));

            // this.processBar.size.set(this.gameView.size.x, 36);
            // this.processBar.position.set(this.toolBar.position.x, 5);

        }
    }

    link() {
        super.link();

        //hijack game view from the engine
        this.gameView = this.editor.engine.gameView;
        this.mainViewport.addChild(this.gameView);

        this.mainViewport.size.onChanged.add(this.gameView.size.set, this.gameView.size);

        this.layout();
    }

    unlink() {
        super.unlink();
        if (this.gameView !== null) {
            //release game view
            this.mainViewport.removeChild(this.gameView);
            this.mainViewport.size.onChanged.remove(this.gameView.size.set, this.gameView.size);
            this.gameView = null;
        }
    }
}


export default EditorView;
