"use strict";
var __extends = (this && this.__extends) || (function () {
    var 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 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) || 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;
};
Object.defineProperty(exports, "__esModule", { value: true });
var React = require("react");
var ReactDOM = require("react-dom");
var EventsDict_1 = require("./EventsDict");
var Config_1 = require("../../Config");
var StringUtils_1 = require("../../helpers/StringUtils");
var DEFAULT_HOST_ELEMENT_TAG_NAME = 'div';
var HAIKU_CONFIG_PROPS_RENAME_MAPPING = {
    haikuOptions: 'options',
    haikuStates: 'states',
    haikuInitialStates: 'states',
    haikuEventHandlers: 'eventHandlers',
    haikuTimelines: 'timelines',
    haikuVanities: 'vanities',
};
function HaikuReactDOMAdapter(haikuComponentFactory, optionalRawBytecode) {
    var HaikuReactComponentInternal = (function (_super) {
        __extends(HaikuReactComponentInternal, _super);
        function HaikuReactComponentInternal(props) {
            var _this = _super.call(this, props) || this;
            _this.state = {
                randomId: 'haiku-reactroot-' + StringUtils_1.randomString(24),
            };
            return _this;
        }
        HaikuReactComponentInternal.prototype.componentWillReceiveProps = function (nextPropsRaw) {
            if (this.haiku) {
                var haikuConfig = this.buildHaikuCompatibleConfigFromRawProps(nextPropsRaw);
                this.haiku.assignConfig(haikuConfig);
            }
        };
        HaikuReactComponentInternal.prototype.componentWillUnmount = function () {
            if (this.haiku) {
                this.haiku.callUnmount();
            }
        };
        HaikuReactComponentInternal.prototype.componentDidMount = function () {
            this.attemptMount();
        };
        HaikuReactComponentInternal.prototype.attemptMount = function () {
            if (this.mount) {
                this.createContext(this.props);
            }
        };
        HaikuReactComponentInternal.prototype.buildHaikuCompatibleConfigFromRawProps = function (rawProps) {
            var haikuConfig = {
                ref: this.mount,
                vanities: {
                    'controlFlow.placeholder': function _controlFlowPlaceholderReactVanity(element, surrogate, value, context, component) {
                        visit(this.mount, function (node) {
                            var flexId = flexIdIfSame(element, node);
                            if (flexId) {
                                if (!component._didElementRenderSurrogate(element, surrogate)) {
                                    if (typeof surrogate.type === 'string' ||
                                        (typeof surrogate.type === 'function' && surrogate.type.isHaikuAdapter)) {
                                        var div = document.createElement('div');
                                        node.parentNode.replaceChild(div, node);
                                        node = div;
                                        element.elementName = 'div';
                                    }
                                    node.style.visibility = 'hidden';
                                    ReactDOM.render(surrogate, node);
                                    window.requestAnimationFrame(function () {
                                        component._markElementSurrogateAsRendered(element, surrogate);
                                        node.style.visibility = 'visible';
                                    });
                                    component._markHorizonElement(element);
                                    component._markForFullFlush();
                                }
                            }
                        });
                    }.bind(this),
                },
            };
            if (rawProps) {
                for (var verboseKeyName in rawProps) {
                    if (EventsDict_1.default[verboseKeyName]) {
                        continue;
                    }
                    var haikuConfigRemappedKey = HAIKU_CONFIG_PROPS_RENAME_MAPPING[verboseKeyName];
                    var haikuConfigFinalKey = haikuConfigRemappedKey || verboseKeyName;
                    if (haikuConfigFinalKey === 'options') {
                        for (var optionsSubKey in rawProps[verboseKeyName]) {
                            haikuConfig[optionsSubKey] = rawProps[verboseKeyName][optionsSubKey];
                        }
                    }
                    else {
                        haikuConfig[haikuConfigFinalKey] = rawProps[verboseKeyName];
                    }
                }
            }
            return haikuConfig;
        };
        HaikuReactComponentInternal.prototype.createContext = function (rawProps) {
            var haikuConfig = this.buildHaikuCompatibleConfigFromRawProps(rawProps);
            var haikuAdapter;
            if (rawProps.haikuAdapter) {
                if (rawProps.haikuCode) {
                    haikuAdapter = rawProps.haikuAdapter(rawProps.haikuCode);
                }
                else if (optionalRawBytecode) {
                    haikuAdapter = rawProps.haikuAdapter(optionalRawBytecode);
                }
                else {
                    throw new Error('A Haiku code object is required if you supply a Haiku adapter');
                }
            }
            else {
                haikuAdapter = haikuComponentFactory;
            }
            if (!haikuAdapter) {
                throw new Error('A Haiku adapter is required');
            }
            if (!this.haiku) {
                this.haiku = haikuAdapter(this.mount, haikuConfig);
            }
            else {
                this.haiku.callRemount(haikuConfig);
            }
        };
        HaikuReactComponentInternal.prototype.buildHostElementPropsFromRawProps = function (rawProps) {
            var _this = this;
            var propsForReactHostElement = {};
            var _loop_1 = function (key) {
                if (willReactProbablyHandleProp(rawProps[key], key)) {
                    if (EventsDict_1.default[key]) {
                        propsForReactHostElement[key] = function (proxy) {
                            return rawProps[key].call(_this, proxy, proxy && proxy.nativeEvent, _this.haiku);
                        };
                    }
                    else {
                        propsForReactHostElement[key] = rawProps[key];
                    }
                }
            };
            for (var key in rawProps) {
                _loop_1(key);
            }
            var stylesForHostElement = rawProps.style || {};
            return __assign({ id: this.state.randomId, style: __assign({ position: 'relative', margin: 0, padding: 0, border: 0, width: '100%', height: '100%', transform: 'matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)' }, stylesForHostElement) }, propsForReactHostElement);
        };
        HaikuReactComponentInternal.prototype.assignMountFromRef = function (element) {
            this.mount = element;
        };
        HaikuReactComponentInternal.prototype.render = function () {
            var _this = this;
            var hostElementProps = this.buildHostElementPropsFromRawProps(this.props);
            hostElementProps.ref = function (element) {
                _this.assignMountFromRef(element);
            };
            return React.createElement(hostElementProps.tagName || DEFAULT_HOST_ELEMENT_TAG_NAME, hostElementProps);
        };
        HaikuReactComponentInternal.React = React;
        HaikuReactComponentInternal.ReactDOM = ReactDOM;
        HaikuReactComponentInternal.isHaikuAdapter = true;
        return HaikuReactComponentInternal;
    }(React.Component));
    return HaikuReactComponentInternal;
}
exports.default = HaikuReactDOMAdapter;
function willReactProbablyHandleProp(prop, key) {
    if (prop && typeof prop === 'object') {
        return false;
    }
    if (typeof prop === 'function') {
        if (EventsDict_1.default[key]) {
            return true;
        }
        return false;
    }
    return !Config_1.DEFAULTS.hasOwnProperty(key);
}
function visit(el, visitor) {
    if (el) {
        visitor(el);
        if (el.children) {
            for (var i = 0; i < el.children.length; i++) {
                visit(el.children[i], visitor);
            }
        }
    }
}
function flexIdIfSame(virtual, dom) {
    if (virtual.attributes) {
        if (virtual.attributes['haiku-id']) {
            if (dom.getAttribute('haiku-id') === virtual.attributes['haiku-id']) {
                return virtual.attributes['haiku-id'];
            }
        }
        if (virtual.attributes.id) {
            if (dom.getAttribute('id') === virtual.attributes.id) {
                return virtual.attributes.id;
            }
        }
    }
    return null;
}
//# sourceMappingURL=HaikuReactDOMAdapter.js.map