"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 StringUtils_1 = require("../../helpers/StringUtils");
var DEFAULT_HOST_ELEMENT_TAG_NAME = 'div';
var HAIKU_FORWARDED_PROPS = {
    haikuOptions: 'options',
    haikuStates: 'states',
    haikuInitialStates: 'states',
    haikuEventHandlers: 'eventHandlers',
    haikuTimelines: 'timelines',
    haikuVanities: 'vanities',
};
var VALID_PROPS = {
    tagName: 'string',
    id: 'string',
    className: 'string',
    style: 'object',
    width: 'string',
    height: 'string',
    onComponentWillMount: 'func',
    onComponentWillUnmount: 'func',
    onComponentDidMount: 'func',
    onHaikuComponentWillInitialize: 'func',
    onHaikuComponentDidMount: 'func',
    onHaikuComponentDidInitialize: 'func',
    onHaikuComponentWillUnmount: 'func',
    haikuAdapter: 'func',
    haikuCode: 'object',
};
var REACT_ELEMENT_PROPS_TO_OMIT = {
    onComponentWillMount: true,
    onComponentWillUnmount: true,
    onComponentDidMount: true,
    onHaikuComponentWillInitialize: true,
    onHaikuComponentDidMount: true,
    onHaikuComponentDidInitialize: true,
    onHaikuComponentWillUnmount: true,
    haikuAdapter: true,
    haikuCode: true,
};
for (var eventKey in EventsDict_1.default) {
    VALID_PROPS[eventKey] = EventsDict_1.default[eventKey];
}
for (var fwdPropKey in HAIKU_FORWARDED_PROPS) {
    VALID_PROPS[fwdPropKey] = 'object';
}
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.componentWillMount = function () {
            if (this.props.onComponentWillMount) {
                this.props.onComponentWillMount(this);
            }
        };
        HaikuReactComponentInternal.prototype.componentWillUnmount = function () {
            if (this.props.onComponentWillUnmount) {
                this.props.onComponentWillUnmount(this);
            }
            if (this.haiku) {
                this.haiku.callUnmount();
            }
        };
        HaikuReactComponentInternal.prototype.componentDidMount = function () {
            this.attemptMount();
        };
        HaikuReactComponentInternal.prototype.attemptMount = function () {
            if (this.mount) {
                this.createContext(this.props);
                if (this.props.onComponentDidMount) {
                    this.props.onComponentDidMount(this, this.mount);
                }
            }
        };
        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) {
                    var haikuConfigFinalKey = HAIKU_FORWARDED_PROPS[verboseKeyName];
                    if (haikuConfigFinalKey) {
                        haikuConfig[haikuConfigFinalKey] = rawProps[verboseKeyName];
                    }
                    else {
                        haikuConfig[verboseKeyName] = 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.createEventPropWrapper = function (eventListener) {
            return function _eventPropWrapper(proxy, event) {
                return eventListener.call(this, proxy, event, this.haiku);
            }.bind(this);
        };
        HaikuReactComponentInternal.prototype.buildHostElementPropsFromRawProps = function (rawProps) {
            var propsForHostElement = {};
            for (var key in rawProps) {
                if (VALID_PROPS[key]) {
                    if (EventsDict_1.default[key]) {
                        propsForHostElement[key] = this.createEventPropWrapper(rawProps[key]);
                    }
                    else if (!HAIKU_FORWARDED_PROPS[key]) {
                        if (!REACT_ELEMENT_PROPS_TO_OMIT[key]) {
                            propsForHostElement[key] = rawProps[key];
                        }
                    }
                }
            }
            var stylesForHostElement = propsForHostElement.style || {};
            delete propsForHostElement.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) }, propsForHostElement);
        };
        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 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