/**
 * 编辑辅助组件
 * 每个子组件的在 map 中的 key 都由父级生成
 * 父级先在 store 中创建数据, 再直接把 mapUniqueKey 扔给子元素,数据获取绑定全部交给子元素自己
 */
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
const React = require('react');
const ReactDOM = require('react-dom');
const typings = require('./edit-helper.type');
const mobx_react_1 = require('mobx-react');
const src_1 = require('../../../../../../../common/auto-bind/src');
const Sortable = require('sortablejs');
require('./edit-helper.scss');
const hasClass = (obj, cls) => {
    return obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
};
const removeClass = (obj, cls) => {
    if (hasClass(obj, cls)) {
        var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
        obj.className = obj.className.replace(reg, ' ');
    }
};
let EditHelper_1;
let EditHelper = EditHelper_1 = class EditHelper extends React.Component {
    constructor(...args) {
        super(...args);
        this.state = new typings.State();
        // 是否正在移动组件
        this.isMovingComponent = false;
    }
    componentWillReact() {
        if (this.componentInfo.props.gaeaUniqueKey === 'gaea-layout' && this.componentInfo.parentMapUniqueKey === null && this.props.setting.showLayoutWhenDragging) {
            if (this.props.viewport.isMovingComponent || this.props.viewport.showLayoutBorder) {
                if (!hasClass(this.selfDomInstance, 'gaea-layout-active')) {
                    this.selfDomInstance.className += ' gaea-layout-active';
                }
            }
            else {
                removeClass(this.selfDomInstance, 'gaea-layout-active');
            }
        }
    }
    componentWillMount() {
        // 从 store 找到自己信息
        this.componentInfo = this.props.viewport.components.get(this.props.mapUniqueKey);
        // 获取当前要渲染的组件 class
        this.SelfComponent = this.props.application.getComponentByUniqueKey(this.componentInfo.props.gaeaUniqueKey);
    }
    componentDidMount() {
        this.selfDomInstance = ReactDOM.findDOMNode(this.selfInstance);
        this.selfDomInstance.addEventListener('mouseover', this.handleMouseOver);
        this.selfDomInstance.addEventListener('click', this.handleClick);
        // 增加统一 class
        this.selfDomInstance.className += ' _namespace';
        this.setDraggingClass();
        // 如果自己是布局元素, 给子元素绑定 sortable
        if (this.componentInfo.props.gaeaUniqueKey === 'gaea-layout') {
            // 添加可排序拖拽
            this.sortable = Sortable.create(this.selfDomInstance, {
                animation: 150,
                // 放在一个组里,可以跨组拖拽
                group: {
                    name: 'gaea-layout',
                    pull: true,
                    put: true
                },
                onStart: (event) => {
                    this.props.viewport.startDragging(this.componentInfo.layoutChilds[event.oldIndex], '', false, this.selfDomInstance, event.oldIndex);
                },
                onEnd: (event) => {
                    this.props.viewport.endDragging();
                    // 在 viewport 中元素拖拽完毕后, 为了防止 outer-move-box 在原来位置留下残影, 先隐藏掉
                    this.props.viewport.setLeaveHover();
                    this.props.viewport.setTreeLeaveHover();
                },
                onAdd: (event) => {
                    // 增加一个元素
                    const { mapUniqueKey, component } = this.props.viewport.addComponent(this.props.mapUniqueKey, event.newIndex);
                    // 取消 srotable 对 dom 的修改
                    // 删掉 dom 元素, 让 react 去生成 dom
                    if (this.props.viewport.currentMovingComponent.isNew) {
                        // 是新拖进来的, 不用管, 因为工具栏会把它收回去
                        // 为什么不删掉? 因为这个元素不论是不是 clone, 都被移过来了, 不还回去 react 在更新 dom 时会无法找到
                        // 记录新增历史
                        if (this.props.viewport.currentMovingComponent.uniqueKey === 'combo') {
                            // 新增组合
                            this.props.viewport.saveOperate({
                                type: 'addCombo',
                                mapUniqueKey: mapUniqueKey,
                                addCombo: {
                                    parentMapUniqueKey: this.props.mapUniqueKey,
                                    index: event.newIndex,
                                    componentInfo: component
                                }
                            });
                        }
                        else {
                            // 新增普通组件
                            this.props.viewport.saveOperate({
                                type: 'add',
                                mapUniqueKey: mapUniqueKey,
                                add: {
                                    uniqueId: this.props.viewport.currentMovingComponent.uniqueKey,
                                    parentMapUniqueKey: this.props.mapUniqueKey,
                                    index: event.newIndex
                                }
                            });
                        }
                    }
                    else {
                        // 如果是从某个元素移过来的（新增的,而不是同一个父级改变排序）
                        // 把这个元素还给之前拖拽的父级
                        if (this.props.viewport.dragStartParentElement.childNodes.length === 0) {
                            // 之前只有一个元素
                            this.props.viewport.dragStartParentElement.appendChild(event.item);
                        }
                        else if (this.props.viewport.dragStartParentElement.childNodes.length === this.props.viewport.dragStartIndex) {
                            // 是上一次位置是最后一个, 而且父元素有多个元素
                            this.props.viewport.dragStartParentElement.appendChild(event.item);
                        }
                        else {
                            // 不是最后一个, 而且有多个元素
                            // 插入到它下一个元素的前一个
                            this.props.viewport.dragStartParentElement.insertBefore(event.item, this.props.viewport.dragStartParentElement.childNodes[this.props.viewport.dragStartIndex]);
                        }
                        // 设置新增时拖拽源信息
                        this.props.viewport.setDragTarget(this.props.mapUniqueKey, event.newIndex);
                    }
                },
                onUpdate: (event) => {
                    // 同一个父级下子元素交换父级
                    // 取消 srotable 对 dom 的修改, 让元素回到最初的位置即可复原
                    const oldIndex = event.oldIndex;
                    const newIndex = event.newIndex;
                    if (this.props.viewport.dragStartParentElement.childNodes.length === oldIndex + 1) {
                        // 是从最后一个元素开始拖拽的
                        this.props.viewport.dragStartParentElement.appendChild(event.item);
                    }
                    else {
                        if (newIndex > oldIndex) {
                            // 如果移到了后面
                            this.props.viewport.dragStartParentElement.insertBefore(event.item, this.props.viewport.dragStartParentElement.childNodes[oldIndex]);
                        }
                        else {
                            // 如果移到了前面
                            this.props.viewport.dragStartParentElement.insertBefore(event.item, this.props.viewport.dragStartParentElement.childNodes[oldIndex + 1]);
                        }
                    }
                    this.props.viewport.sortComponents(this.props.mapUniqueKey, event.oldIndex, event.newIndex);
                    this.props.viewport.saveOperate({
                        type: 'exchange',
                        mapUniqueKey: this.props.mapUniqueKey,
                        exchange: {
                            oldIndex: oldIndex,
                            newIndex: newIndex
                        }
                    });
                },
                onRemove: (event) => {
                    // 减少了一个子元素
                    this.componentInfo.layoutChilds.splice(event.oldIndex, 1);
                    // 新增历史纪录
                    this.props.viewport.saveOperate({
                        type: 'move',
                        // 新增元素父级 key
                        mapUniqueKey: this.props.mapUniqueKey,
                        move: {
                            targetParentMapUniqueKey: this.props.viewport.dragTargetMapUniqueKey,
                            targetIndex: this.props.viewport.dragTargetIndex,
                            sourceParentMapUniqueKey: this.props.mapUniqueKey,
                            sourceIndex: event.oldIndex
                        }
                    });
                    this.props.viewport.setDragTarget(null, -1);
                }
            });
        }
    }
    componentWillUpdate(nextProps, nextState) {
        this.setDraggingClass();
        this.setSelectStyle(nextState);
    }
    componentWillUnmount() {
        // 如果是布局组件, 就销毁 sortable
        if (this.componentInfo.props.gaeaUniqueKey === 'gaea-layout') {
        }
        // 移除事件绑定
        this.selfDomInstance.removeEventListener('mouseover', this.handleMouseOver);
        this.selfDomInstance.removeEventListener('click', this.handleClick);
    }
    /**
     * 根据元素容器大小, 设置拖拽时的 class
     */
    setDraggingClass() {
        if (this.componentInfo.props.gaeaUniqueKey === 'gaea-layout' && this.componentInfo.parentMapUniqueKey !== null) {
            if (!hasClass(this.selfDomInstance, 'gaea-layout')) {
                this.selfDomInstance.className += ' gaea-layout';
            }
            const selfBoundingClientRect = this.selfDomInstance.getBoundingClientRect();
            if (selfBoundingClientRect.width < 100) {
                if (!hasClass(this.selfDomInstance, 'gaea-layout-no-width')) {
                    this.selfDomInstance.className += ' gaea-layout-no-width';
                }
            }
            else {
                removeClass(this.selfDomInstance, 'gaea-layout-no-width');
            }
            if (selfBoundingClientRect.height < 40) {
                if (!hasClass(this.selfDomInstance, 'gaea-layout-no-height')) {
                    this.selfDomInstance.className += ' gaea-layout-no-height';
                }
            }
            else {
                removeClass(this.selfDomInstance, 'gaea-layout-no-height');
            }
        }
    }
    /**
     * 设置选中时样式
     */
    setSelectStyle(nextState) {
        if (nextState.selected) {
            if (!hasClass(this.selfDomInstance, 'gaea-selected')) {
                this.selfDomInstance.className += ' gaea-selected';
            }
        }
        else {
            removeClass(this.selfDomInstance, 'gaea-selected');
        }
    }
    /**
     * 鼠标移上去
     */
    handleMouseOver(event) {
        event.stopPropagation();
        this.props.application.event.emit(this.props.application.event.viewportOrTreeComponentMouseOver, {
            mapUniqueKey: this.props.mapUniqueKey,
            type: 'component'
        });
        this.props.viewport.setHoveringComponentMapUniqueKey(this.props.mapUniqueKey);
    }
    /**
     * 让树视图高亮框移动到自己身上
     */
    outerMoveBoxToSelf() {
        this.props.viewport.setHoverComponent(this.selfDomInstance);
    }
    /**
     * 修改自己选中状态
     */
    setSelect(selected) {
        this.setState({
            selected: selected
        });
    }
    handleClick(event) {
        event.stopPropagation();
        // 设置选中组件的 uniqueKey
        this.props.viewport.setCurrentEditComponentMapUniqueKey(this.props.mapUniqueKey);
        // 把上一个组件触发非选中
        if (this.props.viewport.lastSelectMapUniqueKey !== null) {
            // 如果上个选中组件没被关
            this.props.application.event.emit(this.props.application.event.changeComponentSelectStatusEvent, {
                mapUniqueKey: this.props.viewport.lastSelectMapUniqueKey,
                selected: false
            });
        }
        // 设置自己为上一个组件
        this.props.viewport.setLastSelectMapUniqueKey(this.props.mapUniqueKey);
        // 触发选中组件 event, 各 layout 会接收, 设置子组件的 setSelect
        this.props.application.event.emit(this.props.application.event.changeComponentSelectStatusEvent, {
            mapUniqueKey: this.props.mapUniqueKey,
            selected: true
        });
    }
    render() {
        // 子元素
        let childs = null;
        // 如果是最外层布局元素, 绑定上 isMovingComponent
        if (this.componentInfo.props.gaeaUniqueKey === 'gaea-layout' && this.componentInfo.parentMapUniqueKey === null) {
            // TODO: 强绑 mobx
            this.isMovingComponent = this.props.viewport.isMovingComponent;
            const showLayoutBorder = this.props.viewport.showLayoutBorder;
        }
        // 布局元素可以有子元素
        if (this.componentInfo.props.gaeaUniqueKey === 'gaea-layout' && this.componentInfo.layoutChilds) {
            childs = this.componentInfo.layoutChilds.map(layoutChildUniqueMapKey => {
                return (<EditHelper_1.ObserveEditHelper key={layoutChildUniqueMapKey} mapUniqueKey={layoutChildUniqueMapKey} ref={`edit-${layoutChildUniqueMapKey}`}/>);
            });
        }
        let componentProps = JSON.parse(JSON.stringify(this.componentInfo.props));
        componentProps.ref = (ref) => {
            this.selfInstance = ref;
        };
        return React.createElement(this.SelfComponent, componentProps, childs);
    }
};
EditHelper.defaultProps = new typings.Props();
// 装饰器给外部用挺方便,这个专门给自己用 ^_^
EditHelper.ObserveEditHelper = mobx_react_1.inject('application', 'viewport')(mobx_react_1.observer(EditHelper));
__decorate([
    src_1.autoBindMethod
], EditHelper.prototype, "setDraggingClass", null);
__decorate([
    src_1.autoBindMethod
], EditHelper.prototype, "setSelectStyle", null);
__decorate([
    src_1.autoBindMethod
], EditHelper.prototype, "handleMouseOver", null);
__decorate([
    src_1.autoBindMethod
], EditHelper.prototype, "outerMoveBoxToSelf", null);
__decorate([
    src_1.autoBindMethod
], EditHelper.prototype, "setSelect", null);
__decorate([
    src_1.autoBindMethod
], EditHelper.prototype, "handleClick", null);
EditHelper = EditHelper_1 = __decorate([
    mobx_react_1.inject('application', 'viewport', 'setting'),
    mobx_react_1.observer
], EditHelper);
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = EditHelper;
