'use strict';

Object.defineProperty(exports, "__esModule", {
    value: true
});

var _jsx = function () { var REACT_ELEMENT_TYPE = typeof Symbol === "function" && Symbol.for && Symbol.for("react.element") || 0xeac7; return function createRawReactElement(type, props, key, children) { var defaultProps = type && type.defaultProps; var childrenLength = arguments.length - 3; if (!props && childrenLength !== 0) { props = {}; } if (props && defaultProps) { for (var propName in defaultProps) { if (props[propName] === void 0) { props[propName] = defaultProps[propName]; } } } else if (!props) { props = defaultProps || {}; } if (childrenLength === 1) { props.children = children; } else if (childrenLength > 1) { var childArray = Array(childrenLength); for (var i = 0; i < childrenLength; i++) { childArray[i] = arguments[i + 3]; } props.children = childArray; } return { $$typeof: REACT_ELEMENT_TYPE, type: type, key: key === undefined ? null : '' + key, ref: null, props: props, _owner: null }; }; }();

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _reactDom = require('react-dom');

var _reactDom2 = _interopRequireDefault(_reactDom);

var _styles = require('../helpers/styles');

var _TeleportWrapper = require('./TeleportWrapper');

var _TeleportWrapper2 = _interopRequireDefault(_TeleportWrapper);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var idCount = 0;
var relationships = {};

/**
 * Context for Teleport component
 */

var TeleportContext = function (_React$Component) {
    _inherits(TeleportContext, _React$Component);

    function TeleportContext(props) {
        var _ref;

        _classCallCheck(this, TeleportContext);

        for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
            args[_key - 1] = arguments[_key];
        }

        var _this = _possibleConstructorReturn(this, (_ref = TeleportContext.__proto__ || Object.getPrototypeOf(TeleportContext)).call.apply(_ref, [this, props].concat(args)));

        _this.state = {
            shownComponents: []
        };

        _this._componentID = Math.random().toString(32).slice(2, 10) + ':' + ++idCount;
        _this._componentsBank = {};
        _this._shownComponents = [];
        _this._refs = {};
        _this._parentDOMNode = null;
        _this._isMount = false;
        return _this;
    }

    _createClass(TeleportContext, [{
        key: 'componentDidMount',
        value: function componentDidMount() {
            var selfDOMNode = _reactDom2.default.findDOMNode(this);
            this._parentDOMNode = selfDOMNode.parentNode;

            this._registerRelationship();
            this._isMount = true;
        }
    }, {
        key: 'getChildContext',
        value: function getChildContext() {
            var _this2 = this;

            return {
                teleport: {
                    move: function move(id, component, callback) {
                        _this2._componentsBank[id] = component;
                        _this2._shownComponents.push(id);

                        _this2.setState({
                            shownComponents: _this2._shownComponents
                        }, callback);
                    },
                    remove: function remove(componentID, callback) {
                        _this2._shownComponents = _this2._shownComponents.filter(function (id) {
                            return id !== componentID;
                        });
                        _this2._componentsBank[componentID] = null;
                        _this2._refs[componentID] = null;

                        _this2.setState({ shownComponents: _this2._shownComponents }, callback);
                    },
                    update: function update(id, newChildren, callback) {
                        var component = _this2._refs[id];

                        component && component.isMount() && component.update(newChildren, callback);
                    },
                    isAdded: function isAdded(componentID) {
                        return _this2._shownComponents.some(function (id) {
                            return id === componentID;
                        });
                    },
                    getRootDOMNode: function getRootDOMNode() {
                        return _reactDom2.default.findDOMNode(_this2).getElementsByClassName((0, _styles.css)(styles.teleportRoot))[0];
                        //return this.refs.rootDOMNode || null;
                    },
                    getBoundingClientRect: function getBoundingClientRect() {
                        var node = _this2._parentDOMNode;

                        if (!node) {
                            return null;
                        }

                        if (!_this2._boundingClientRect) {
                            _this2._boundingClientRect = node.getBoundingClientRect();
                        }

                        return _this2._boundingClientRect;
                    },
                    getContextLevel: function getContextLevel() {
                        var data = relationships[_this2._componentID];

                        if (!data) {
                            throw new Error('TeleportContext: Context with id "' + _this2._componentID + '" is not mount');
                        }

                        return data.level;
                    }
                }
            };
        }
    }, {
        key: 'isMount',
        value: function isMount() {
            return this._isMount;
        }
    }, {
        key: '_registerRelationship',
        value: function _registerRelationship() {
            var parentID = findParentContext(this._parentDOMNode);

            relationships[this._componentID] = relationships[this._componentID] || {};

            relationships[this._componentID] = {
                level: relationships[parentID] ? relationships[parentID].level + 1 : 1,
                parentID: parentID
            };
        }
    }, {
        key: 'render',
        value: function render() {
            var _this3 = this;

            var props = this.props;

            return _react2.default.cloneElement(props.children, {
                'data-teleport': this._componentID,
                children: [_jsx('div', {
                    className: (0, _styles.css)(styles.teleportRoot)
                }, void 0, this.state.shownComponents.map(function (id) {
                    return _react2.default.createElement(
                        _TeleportWrapper2.default,
                        { key: id, ref: function ref(c) {
                                return c && (_this3._refs[id] = c);
                            } },
                        _this3._componentsBank[id]
                    );
                }))].concat(_toConsumableArray(_react2.default.Children.toArray(props.children.props.children)))
            });
        }
    }]);

    return TeleportContext;
}(_react2.default.Component);

exports.default = TeleportContext;


TeleportContext.childContextTypes = {
    teleport: _react.PropTypes.shape({
        move: _react.PropTypes.func,
        remove: _react.PropTypes.func,
        update: _react.PropTypes.func,
        isAdded: _react.PropTypes.func,
        getRootDOMNode: _react.PropTypes.func,
        getBoundingClientRect: _react.PropTypes.func,
        getContextLevel: _react.PropTypes.func
    })
};

function findParentContext(parentDOMNode) {
    if (!parentDOMNode || typeof parentDOMNode.getAttribute !== 'function') {
        return null;
    }

    var componentID = parentDOMNode.getAttribute('data-teleport');

    if (componentID) {
        return componentID;
    }

    return findParentContext(parentDOMNode.parentNode);
}

var styles = _styles.StyleSheet.create({
    teleportRoot: {
        position: 'absolute',
        top: 0,
        left: 0
    }
});