import * as React from 'react';
import { toRect, ensureEnum, brushToString, stringToBrush, ensureBool, initializePropertiesFromCss, NamePatcher, isValidProp, toSpinal, getModifiedProps } from "./componentUtil";
import { ReactRenderer, PortalManager } from "./react-renderer";
import { delegateCombine, delegateRemove } from "./type";
import { Popup } from './Popup';
import { IgrOnPopupEventArgs } from './igr-on-popup-event-args';
import { IgrOnClosedEventArgs } from './igr-on-closed-event-args';
import { IgrFocusEventArgs } from './igr-focus-event-args';
import { PopupAnimationType_$type } from "./PopupAnimationType";
import { PopupPointerPosition_$type } from "./PopupPointerPosition";
export class IgrPopup extends React.Component {
    set height(value) {
        this._height = value;
        if (this._elRef) {
            this._elRef.style.height = value;
            this.i.notifySizeChanged();
        }
    }
    get height() {
        return this._height;
    }
    set width(value) {
        this._width = value;
        if (this._elRef) {
            this._elRef.style.height = value;
            this.i.notifySizeChanged();
        }
    }
    get width() {
        return this._width;
    }
    _getMainRef(ref) {
        this._elRef = ref;
        this.verifyReferences();
    }
    verifyReferences() {
        if (this._elRef) {
            this.requestRender = this.requestRender.bind(this);
            this._portalManager = new PortalManager("popupContent", this.requestRender);
            this._reactRenderer = new ReactRenderer(this._elRef, document, true, {}, this._portalManager);
            // render needs to fire again after the portalManager is created. 
            this.requestRender();
            this.i.provideRenderer(this._reactRenderer);
        }
    }
    render() {
        let propChildren = this.props.children;
        let children = [];
        React.Children.forEach(propChildren, (ch) => {
            children.push(React.cloneElement(ch));
        });
        if (this._portalManager)
            this._portalManager.onRender(children);
        let div = React.createElement("div", {
            ref: this._getMainRef,
            children: children
        });
        return div;
    }
    requestRender() {
        if (this._initialized)
            this.setState({});
    }
    constructor(props) {
        super(props);
        this._reactRenderer = null;
        this._implementation = null;
        this.__p = null;
        this._hasUserValues = new Set();
        this._stylingContainer = null;
        this._stylingParent = null;
        this._inStyling = false;
        this._onClosed = null;
        this._onClosed_wrapped = null;
        this._onPopup = null;
        this._onPopup_wrapped = null;
        this._popupGotFocus = null;
        this._popupGotFocus_wrapped = null;
        this._popupLostFocus = null;
        this._popupLostFocus_wrapped = null;
        if (this._styling) {
            NamePatcher.ensureStylablePatched(Object.getPrototypeOf(this));
        }
        this._implementation = this.createImplementation();
        this._getMainRef = this._getMainRef.bind(this);
        if (props) {
            this.initializeProperties();
        }
        this._initialized = true;
    }
    shouldComponentUpdate(nextProps, nextState) {
        const mod = getModifiedProps(this.props, nextProps);
        for (const p of Object.keys(mod)) {
            if (isValidProp(this, p)) {
                this[p] = mod[p];
            }
        }
        return true;
    }
    initializeProperties() {
        for (const p of Object.keys(this.props)) {
            if (isValidProp(this, p)) {
                this[p] = this.props[p];
            }
        }
    }
    // supports angular themes or custom properties set in CSS
    updateStyle() {
        this._styling(this._elRef, this);
    }
    destroy() {
        this.i.destroy();
        if (this._reactRenderer)
            this._reactRenderer.destroy();
    }
    componentWillUnmount() {
    }
    componentDidMount() {
        this._elRef.style.width = this._width ? this._width : "";
        this._elRef.style.height = this._height ? this._height : "";
        this.initializeContent();
    }
    initializeContent() {
        this._styling(this._elRef, this);
        this.updateStyle();
    }
    createImplementation() {
        return new Popup();
    }
    get i() {
        return this._implementation;
    }
    get isFocusable() {
        return this.i.aq;
    }
    set isFocusable(v) {
        this.i.aq = ensureBool(v);
    }
    /**
     * Gets or sets the duration of the Popup and Closeup animations in milliseconds.
    */
    get animationDuration() {
        return this.i.a6;
    }
    set animationDuration(v) {
        this.i.a6 = +v;
    }
    /**
     * Gets or sets whether the popup and closeup animations are animated.
    */
    get animationEnabled() {
        return this.i.al;
    }
    set animationEnabled(v) {
        this.i.al = ensureBool(v);
    }
    /**
     * Gets or sets the type of animation to use when the popup opens and closes.
    */
    get animationType() {
        return this.i.o;
    }
    set animationType(v) {
        this.i.o = ensureEnum(PopupAnimationType_$type, v);
    }
    /**
     * Gets or sets the elevation to use for the button regardless of type.
    */
    get elevation() {
        return this.i.a8;
    }
    set elevation(v) {
        this.i.a8 = +v;
    }
    /**
     * Gets or sets the elevation of the border shadow
    */
    get actualElevation() {
        return this.i.a4;
    }
    set actualElevation(v) {
        this.i.a4 = +v;
    }
    /**
     * Gets / sets the isShown state of the panel.
    */
    get isShown() {
        return this.i.av;
    }
    /**
     * Gets or sets the color to use for the check mark when the checkbox is checked.
    */
    get actualUmbraShadowColor() {
        return brushToString(this.i.cm);
    }
    set actualUmbraShadowColor(v) {
        this.i.cm = stringToBrush(v);
    }
    /**
     * Gets or sets the color to use for the check mark when the checkbox is checked.
    */
    get actualPenumbraShadowColor() {
        return brushToString(this.i.cl);
    }
    set actualPenumbraShadowColor(v) {
        this.i.cl = stringToBrush(v);
    }
    /**
     * Gets or sets the color to use for the check mark when the checkbox is checked.
    */
    get actualAmbientShadowColor() {
        return brushToString(this.i.ck);
    }
    set actualAmbientShadowColor(v) {
        this.i.ck = stringToBrush(v);
    }
    /**
     * Gets or sets the background color of the popup.
    */
    get background() {
        return brushToString(this.i.cn);
    }
    set background(v) {
        this.i.cn = stringToBrush(v);
    }
    get cornerRadius() {
        return this.i.ay;
    }
    set cornerRadius(v) {
        this.i.ay = +v;
    }
    /**
     * Gets or sets whether to disable hit testing on the popup.
    */
    get isHitTestVisible() {
        return this.i.ar;
    }
    set isHitTestVisible(v) {
        this.i.ar = ensureBool(v);
    }
    /**
     * Gets or sets whether to disable hit testing during the open and close animations.
    */
    get disableHitTestDuringAnimation() {
        return this.i.an;
    }
    set disableHitTestDuringAnimation(v) {
        this.i.an = ensureBool(v);
    }
    /**
     * Gets or sets whether to show a pointer off the side of the popup towards the popup target.
    */
    get isPointerEnabled() {
        return this.i.as;
    }
    set isPointerEnabled(v) {
        this.i.as = ensureBool(v);
    }
    /**
     * Gets or sets the pointer position.
    */
    get pointerPosition() {
        return this.i.t;
    }
    set pointerPosition(v) {
        this.i.t = ensureEnum(PopupPointerPosition_$type, v);
    }
    /**
     * Gets or sets the pointer background color.
    */
    get pointerBackground() {
        return brushToString(this.i.cr);
    }
    set pointerBackground(v) {
        this.i.cr = stringToBrush(v);
    }
    /**
     * Gets or sets the pointer size.
    */
    get pointerSize() {
        return this.i.a1;
    }
    set pointerSize(v) {
        this.i.a1 = +v;
    }
    /**
     * Gets whether the popup is in the middle of opening or not.
    */
    get isShowing() {
        return this.i.at;
    }
    set isShowing(v) {
        this.i.at = ensureBool(v);
    }
    /**
     * Gets whether the popup is in the middle of closing or not.
    */
    get isClosing() {
        return this.i.ap;
    }
    set isClosing(v) {
        this.i.ap = ensureBool(v);
    }
    findByName(name) {
        if (this.findEphemera) {
            if (name && name.indexOf("@@e:") == 0) {
                return this.findEphemera(name);
            }
        }
        return null;
    }
    get hasUserValues() {
        return this._hasUserValues;
    }
    __m(propertyName) {
        if (!this._inStyling) {
            this._hasUserValues.add(propertyName);
        }
    }
    _styling(container, component, parent) {
        if (this._inStyling) {
            return;
        }
        this._inStyling = true;
        this._stylingContainer = container;
        this._stylingParent = component;
        let genericPrefix = "";
        let typeName = this.i.$type.name;
        if (typeName.indexOf("Xam") === 0) {
            typeName = typeName.substring(3);
        }
        genericPrefix = toSpinal("Popup");
        let additionalPrefixes = [];
        let prefix = toSpinal(typeName);
        additionalPrefixes.push(prefix + "-");
        let b = this.i.$type.baseType;
        while (b && b.name != "Object" &&
            b.name != "Base" &&
            b.name != "Control" &&
            b.Name != "DependencyObject" &&
            b.Name != "FrameworkElement") {
            typeName = b.name;
            if (typeName.indexOf("Xam") === 0) {
                typeName = typeName.substring(3);
            }
            let basePrefix = toSpinal(typeName);
            additionalPrefixes.push(basePrefix + "-");
            b = b.baseType;
        }
        if (parent) {
            let parentTypeName = parent.i.$type.name;
            if (parentTypeName.indexOf("Xam") === 0) {
                parentTypeName = parentTypeName.substring(3);
            }
            let parentPrefix = toSpinal(parentTypeName);
            additionalPrefixes.push(parentPrefix + "-" + genericPrefix + "-");
            additionalPrefixes.push(parentPrefix + "-" + prefix + "-");
        }
        initializePropertiesFromCss(container, this, genericPrefix + "-", this.hasUserValues, false, additionalPrefixes);
        if (this._otherStyling) {
            this._otherStyling(container, component, parent);
        }
        this._inStyling = false;
    }
    /**
 * Closes the popup.

*/
    close() {
        this.i.bx();
    }
    showRelativeToExclusionRect(exclusionRect, popupDirection, popupAlignment) {
        this.i.showRelativeToExclusionRect(toRect(exclusionRect), (popupDirection == null ? null : popupDirection), (popupAlignment == null ? null : popupAlignment));
    }
    /**
     * Exports visual information about the current state of the grid.
    
    */
    exportVisualModel() {
        let iv = this.i.a9();
        return (iv);
    }
    /**
     * Returns a serialized copy of the exported visual model
    
    */
    exportSerializedVisualModel() {
        let iv = this.i.bl();
        return (iv);
    }
    get onClosed() {
        return this._onClosed;
    }
    set onClosed(ev) {
        if (this._onClosed_wrapped !== null) {
            this.i.onClosed = delegateRemove(this.i.onClosed, this._onClosed_wrapped);
            this._onClosed_wrapped = null;
            this._onClosed = null;
        }
        this._onClosed = ev;
        this._onClosed_wrapped = (o, e) => {
            let outerArgs = new IgrOnClosedEventArgs();
            outerArgs._provideImplementation(e);
            if (this.beforeOnClosed) {
                this.beforeOnClosed(this, outerArgs);
            }
            if (this._onClosed) {
                this._onClosed(this, outerArgs);
            }
        };
        this.i.onClosed = delegateCombine(this.i.onClosed, this._onClosed_wrapped);
        ;
    }
    /**
     * Fires when the popup is shown
    */
    get onPopup() {
        return this._onPopup;
    }
    set onPopup(ev) {
        if (this._onPopup_wrapped !== null) {
            this.i.onPopup = delegateRemove(this.i.onPopup, this._onPopup_wrapped);
            this._onPopup_wrapped = null;
            this._onPopup = null;
        }
        this._onPopup = ev;
        this._onPopup_wrapped = (o, e) => {
            let outerArgs = new IgrOnPopupEventArgs();
            outerArgs._provideImplementation(e);
            if (this.beforeOnPopup) {
                this.beforeOnPopup(this, outerArgs);
            }
            if (this._onPopup) {
                this._onPopup(this, outerArgs);
            }
        };
        this.i.onPopup = delegateCombine(this.i.onPopup, this._onPopup_wrapped);
        ;
    }
    /**
     * Fired when the open popup gains focus.
    */
    get popupGotFocus() {
        return this._popupGotFocus;
    }
    set popupGotFocus(ev) {
        if (this._popupGotFocus_wrapped !== null) {
            this.i.popupGotFocus = delegateRemove(this.i.popupGotFocus, this._popupGotFocus_wrapped);
            this._popupGotFocus_wrapped = null;
            this._popupGotFocus = null;
        }
        this._popupGotFocus = ev;
        this._popupGotFocus_wrapped = (o, e) => {
            let outerArgs = new IgrFocusEventArgs();
            outerArgs._provideImplementation(e);
            if (this.beforePopupGotFocus) {
                this.beforePopupGotFocus(this, outerArgs);
            }
            if (this._popupGotFocus) {
                this._popupGotFocus(this, outerArgs);
            }
        };
        this.i.popupGotFocus = delegateCombine(this.i.popupGotFocus, this._popupGotFocus_wrapped);
        ;
    }
    /**
     * Fired when the open popup loses focus.
    */
    get popupLostFocus() {
        return this._popupLostFocus;
    }
    set popupLostFocus(ev) {
        if (this._popupLostFocus_wrapped !== null) {
            this.i.popupLostFocus = delegateRemove(this.i.popupLostFocus, this._popupLostFocus_wrapped);
            this._popupLostFocus_wrapped = null;
            this._popupLostFocus = null;
        }
        this._popupLostFocus = ev;
        this._popupLostFocus_wrapped = (o, e) => {
            let outerArgs = new IgrFocusEventArgs();
            outerArgs._provideImplementation(e);
            if (this.beforePopupLostFocus) {
                this.beforePopupLostFocus(this, outerArgs);
            }
            if (this._popupLostFocus) {
                this._popupLostFocus(this, outerArgs);
            }
        };
        this.i.popupLostFocus = delegateCombine(this.i.popupLostFocus, this._popupLostFocus_wrapped);
        ;
    }
}
