var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
    if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
    return cooked;
};
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    }
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
import React from 'react';
import styled from 'react-emotion';
import BloqFactory from './BloqFactory';
import Canvas from './Canvas';
var SNAP_DISTANCE = 32;
var Container = styled.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n  display: flex;\n  flex: 1;\n  overflow: hidden;\n"], ["\n  display: flex;\n  flex: 1;\n  overflow: hidden;\n"])));
var Toolbar = styled.div(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n  width: 300px;\n  background-color: #fafafa;\n  padding: 12px;\n  border-right: 1px solid rgba(0, 0, 0, 0.15);\n  z-index: 2;\n"], ["\n  width: 300px;\n  background-color: #fafafa;\n  padding: 12px;\n  border-right: 1px solid rgba(0, 0, 0, 0.15);\n  z-index: 2;\n"])));
var ToolbarBloqWrap = styled.div(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n  position: relative;\n  margin-top: 20px;\n  height: ", "px;\n"], ["\n  position: relative;\n  margin-top: 20px;\n  height: ", "px;\n"])), function (props) { return props.height; });
var CanvasBloqWrap = styled.div(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n  position: ", ";\n"], ["\n  position: ", ";\n"])), function (props) { return (props.isTop ? 'absolute' : 'relative'); });
var BloqChildrenWrap = styled.div(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n  position: absolute;\n  top: 48px;\n  left: 16px;\n"], ["\n  position: absolute;\n  top: 48px;\n  left: 16px;\n"])));
var BloqsEditor = /** @class */ (function (_super) {
    __extends(BloqsEditor, _super);
    function BloqsEditor(props) {
        var _this = _super.call(this, props) || this;
        _this.state = {
            draggingBloq: null,
            activeSnapArea: null,
            snapAreas: [],
            offsetX: 0,
            offsetY: 0,
            bloqsPreview: [],
        };
        _this.canvas = React.createRef();
        _this.bloqRefs = {};
        _this.onToolbarBloqMouseDown = function (e, toolbarBloq) {
            var bloqs = _this.props.bloqs;
            _this.startDraggingBloq(bloqs, toolbarBloq, e);
        };
        _this.onCanvasBloqMouseDown = function (e, bloq) {
            var _a = _this.props, bloqs = _a.bloqs, onBloqsChange = _a.onBloqsChange;
            e.stopPropagation();
            var newBloqs = bloqs
                .filter(function (rootBloq) { return rootBloq.id !== bloq.id; })
                .map(function (rootBloq) { return _this.deleteBloq(rootBloq, bloq); });
            onBloqsChange(newBloqs);
            _this.startDraggingBloq(newBloqs, bloq, e);
        };
        _this.onDragItem = function (x, y) {
            var _a;
            var draggingBloq = _this.state.draggingBloq;
            var bloqs = _this.props.bloqs;
            var activeSnapArea = _this.getActiveSnapArea(x, y);
            var bloqsPreview;
            if (activeSnapArea) {
                if (activeSnapArea !== _this.state.activeSnapArea) {
                    var areaBloq_1;
                    if (activeSnapArea.type === 'next') {
                        areaBloq_1 = __assign({}, activeSnapArea.bloq, { next: __assign({}, draggingBloq, { isGhost: true, x: 0, y: 0, next: activeSnapArea.bloq.next }) });
                    }
                    else if (activeSnapArea.type === 'children') {
                        var _b = activeSnapArea.bloq.children, children = _b === void 0 ? [] : _b;
                        areaBloq_1 = __assign({}, activeSnapArea.bloq, { children: [
                                __assign({}, draggingBloq, { isGhost: true, x: 0, y: 0, next: children[0] }),
                            ] });
                    }
                    else if (activeSnapArea.type === 'content') {
                        var bloq = activeSnapArea.bloq, contentItem = activeSnapArea.contentItem;
                        areaBloq_1 = __assign({}, bloq, { data: __assign({}, bloq.data, (_a = {}, _a[contentItem.dataField] = __assign({}, draggingBloq, { isGhost: true, x: 0, y: 0 }), _a)) });
                    }
                    bloqsPreview = bloqs.map(function (rootBloq) {
                        return _this.replaceBloq(rootBloq, areaBloq_1);
                    });
                }
                else {
                    bloqsPreview = _this.state.bloqsPreview;
                }
            }
            else {
                bloqsPreview = bloqs;
            }
            _this.setState(function (prevState) { return (__assign({}, prevState, { activeSnapArea: activeSnapArea, draggingBloq: __assign({}, prevState.draggingBloq, { x: x,
                    y: y }), bloqsPreview: bloqsPreview })); });
        };
        _this.onDragItemStop = function (x, y) {
            var _a = _this.state, draggingBloq = _a.draggingBloq, activeSnapArea = _a.activeSnapArea;
            var _b = _this.props, bloqs = _b.bloqs, onBloqsChange = _b.onBloqsChange;
            var newBloq = __assign({}, draggingBloq, { id: uuid(), x: activeSnapArea ? 0 : x, y: activeSnapArea ? 0 : y, data: {} });
            if (activeSnapArea) {
                if (activeSnapArea.type === 'next') {
                    newBloq.next = activeSnapArea.bloq.next;
                    activeSnapArea.bloq.next = newBloq;
                }
                if (activeSnapArea.type === 'children') {
                    activeSnapArea.bloq.children = [newBloq];
                }
                if (activeSnapArea.type === 'content') {
                    var bloq = activeSnapArea.bloq, contentItem = activeSnapArea.contentItem;
                    bloq.data[contentItem.dataField] = newBloq;
                }
            }
            _this.setState(function (prevState) { return (__assign({}, prevState, { draggingBloq: null, activeSnapArea: null })); });
            onBloqsChange(activeSnapArea ? bloqs : bloqs.concat([newBloq]));
        };
        _this.replaceBloq = function (rootBloq, bloq) {
            var _a = rootBloq.children, children = _a === void 0 ? [] : _a, next = rootBloq.next;
            if (rootBloq.id === bloq.id) {
                return bloq;
            }
            else {
                return __assign({}, rootBloq, { next: next && _this.replaceBloq(rootBloq.next, bloq), children: children[0]
                        ? [_this.replaceBloq(children[0], bloq)]
                        : children });
            }
        };
        _this.deleteBloq = function (rootBloq, bloq) {
            if (rootBloq.next) {
                if (rootBloq.next.id === bloq.id) {
                    return __assign({}, rootBloq, { next: null });
                }
                else {
                    return __assign({}, rootBloq, { next: _this.deleteBloq(rootBloq.next, bloq) });
                }
            }
            return rootBloq;
        };
        _this.onBloqChange = function (bloq) {
            var _a = _this.props, bloqs = _a.bloqs, onBloqsChange = _a.onBloqsChange;
            onBloqsChange(bloqs.map(function (rootBloq) { return _this.replaceBloq(rootBloq, bloq); }));
        };
        _this.renderCanvasBloq = function (bloq, isDragging, isTop) {
            if (isTop === void 0) { isTop = true; }
            var next = bloq.next, _a = bloq.children, children = _a === void 0 ? [] : _a;
            return (React.createElement(CanvasBloqWrap, { onMouseDown: function (e) { return _this.onCanvasBloqMouseDown(e, bloq); }, isTop: isTop },
                React.createElement(_this.Bloq, { bloq: bloq, onChange: _this.onBloqChange, isDragging: isDragging, ref: _this.getBloqRef(bloq) }),
                next && _this.renderCanvasBloq(next, false, false),
                children.length > 0 && (React.createElement(BloqChildrenWrap, null, _this.renderCanvasBloq(children[0])))));
        };
        _this.Bloq = BloqFactory(props.getBloqType, props.getBloqOptions);
        return _this;
    }
    BloqsEditor.prototype.getSnapAreas = function (bloq, offsetX, offsetY) {
        var getBloqType = this.props.getBloqType;
        var areas = [];
        var bloqType = getBloqType(bloq.type) || {};
        var bloqHeight = this.Bloq.getHeight(bloq);
        var _a = bloq.children, children = _a === void 0 ? [] : _a;
        if (bloq.next) {
            areas = areas.concat(this.getSnapAreas(bloq.next, offsetX, offsetY + bloqHeight));
        }
        areas.push({
            x: offsetX - SNAP_DISTANCE,
            y: offsetY + bloqHeight - SNAP_DISTANCE,
            width: SNAP_DISTANCE * 2,
            height: SNAP_DISTANCE * 2,
            type: 'next',
            bloq: bloq,
        });
        if (bloqType.type === 'codeblock') {
            areas.push({
                x: offsetX + 16 - SNAP_DISTANCE,
                y: offsetY + 40 - SNAP_DISTANCE,
                width: SNAP_DISTANCE * 2,
                height: SNAP_DISTANCE * 2,
                type: 'children',
                bloq: bloq,
            });
            if (children[0]) {
                areas = areas.concat(this.getSnapAreas(children[0], offsetX + 24, offsetY + 40));
            }
        }
        var bloqRef = this.getBloqRef(bloq);
        var contentRects = bloqRef && bloqRef.current ? bloqRef.current.getContentRects() : [];
        bloqType.content.forEach(function (contentItem, i) {
            if (contentItem.type === 'bloq') {
                areas.push({
                    x: contentRects[i].x - SNAP_DISTANCE,
                    y: offsetY - SNAP_DISTANCE,
                    width: SNAP_DISTANCE * 2,
                    height: SNAP_DISTANCE * 2,
                    type: 'content',
                    contentItem: contentItem,
                    bloq: bloq,
                });
            }
        });
        return areas;
    };
    BloqsEditor.prototype.getActiveSnapArea = function (bloqX, bloqY) {
        var snapAreas = this.state.snapAreas;
        return snapAreas.find(function (_a) {
            var x = _a.x, y = _a.y, width = _a.width, height = _a.height;
            return bloqX > x && bloqX < x + width && bloqY > y && bloqY < y + height;
        });
    };
    BloqsEditor.prototype.getBloqRef = function (bloq) {
        if (!bloq || !bloq.id)
            return;
        if (!this.bloqRefs[bloq.id]) {
            this.bloqRefs[bloq.id] = React.createRef();
        }
        return this.bloqRefs[bloq.id];
    };
    BloqsEditor.prototype.startDraggingBloq = function (bloqs, bloq, e) {
        var _this = this;
        var snapAreas = bloqs.reduce(function (areas, bloq) { return areas.concat(_this.getSnapAreas(bloq, bloq.x, bloq.y)); }, []);
        var _a = e.currentTarget.getBoundingClientRect(), elementX = _a.x, elementY = _a.y;
        var offsetX = e.clientX - elementX;
        var offsetY = e.clientY - elementY;
        var _b = this.canvas.current.getItemPosition(e, offsetX, offsetY), x = _b.x, y = _b.y;
        this.setState(function (prevState) { return (__assign({}, prevState, { snapAreas: snapAreas, draggingBloq: __assign({}, bloq, { x: x, y: y }), offsetX: offsetX,
            offsetY: offsetY, bloqsPreview: bloqs })); });
    };
    BloqsEditor.prototype.render = function () {
        var _this = this;
        var _a = this.state, draggingBloq = _a.draggingBloq, bloqsPreview = _a.bloqsPreview, offsetX = _a.offsetX, offsetY = _a.offsetY;
        var _b = this.props, bloqs = _b.bloqs, toolbarBloqs = _b.toolbarBloqs, getBloqOptions = _b.getBloqOptions, getBloqType = _b.getBloqType;
        var canvasBloqs = draggingBloq ? bloqsPreview : bloqs;
        return (React.createElement(Container, null,
            React.createElement(Toolbar, null, toolbarBloqs.map(function (bloq, i) { return (React.createElement(ToolbarBloqWrap, { height: _this.Bloq.getHeight(bloq), onMouseDown: function (e) { return _this.onToolbarBloqMouseDown(e, bloq); }, key: i },
                React.createElement(_this.Bloq, { bloq: bloq }))); })),
            React.createElement(Canvas, { ref: this.canvas, items: canvasBloqs, draggingItem: draggingBloq, renderItem: this.renderCanvasBloq, dragOffsetX: offsetX, dragOffsetY: offsetY, onDragItem: this.onDragItem, onDragItemStop: this.onDragItemStop })));
    };
    return BloqsEditor;
}(React.Component));
export default BloqsEditor;
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5;
//# sourceMappingURL=BloqsEditor.js.map