import * as React from 'react';
import { ReactRenderer } from "igniteui-react-core";
import { TypeRegistrar, delegateRemove, delegateCombine } from "igniteui-react-core";
import { DataChartStylingDefaults } from './DataChartStylingDefaults';
import { XamFunnelChart } from './XamFunnelChart';
import { isValidProp, toSpinal, getModifiedProps, initializePropertiesFromCss, NamePatcher, fromBrushCollection, toBrushCollection, ensureBool, stringToBrush, brushToString, ensureEnum } from "igniteui-react-core";
import { Visibility_$type } from "igniteui-react-core";
import { OuterLabelAlignment_$type } from './OuterLabelAlignment';
import { FunnelSliceDisplay_$type } from './FunnelSliceDisplay';
import { IgrFunnelSliceClickedEventArgs } from './igr-funnel-slice-clicked-event-args';
import { IgrFunnelSliceEventArgs } from './igr-funnel-slice-event-args';
import { Style } from "igniteui-react-core";
export class IgrFunnelChart extends React.Component {
    set height(value) {
        this._height = value;
        if (this._elRef) {
            this._elRef.style.height = value;
            this._chart.notifyResized();
        }
    }
    get height() {
        return this._height;
    }
    set width(value) {
        this._width = value;
        if (this._elRef) {
            this._elRef.style.width = value;
            this._chart.notifyResized();
        }
    }
    get width() {
        return this._width;
    }
    _getMainRef(ref) {
        this._elRef = ref;
    }
    render() {
        let div = React.createElement("div", {
            className: "ig-funnel-chart igr-funnel-chart",
            ref: this._getMainRef
        });
        return div;
    }
    constructor(props) {
        super(props);
        this._dataSource = null;
        this.mounted = false;
        this.__p = null;
        this._hasUserValues = new Set();
        this._stylingContainer = null;
        this._stylingParent = null;
        this._inStyling = false;
        this._sliceClicked = null;
        this._sliceClicked_wrapped = null;
        this._sliceEnter = null;
        this._sliceEnter_wrapped = null;
        this._sliceLeave = null;
        this._sliceLeave_wrapped = null;
        this._sliceHover = null;
        this._sliceHover_wrapped = null;
        if (this._styling) {
            NamePatcher.ensureStylablePatched(Object.getPrototypeOf(this));
        }
        this._getMainRef = this._getMainRef.bind(this);
        let container;
        if (document) {
            container = document.createElement("div");
            container.style.display = "block";
            container.style.width = "100%";
            container.style.height = "100%";
        }
        this._implementation = this.createImplementation();
        var root;
        root = container;
        var ren = new ReactRenderer(root, document, true, DataChartStylingDefaults);
        this.container = ren.getWrapper(container);
        this._wrapper = ren;
        var chart = this.i;
        this._chart = chart;
        chart.provideContainer(ren);
        this.bindData();
        if (props) {
            this.initializeProperties();
        }
        chart.notifyResized();
        ren.addSizeWatcher(() => {
            this._chart.notifyResized();
        });
    }
    destroy() {
        this._chart.destroy();
        this._wrapper.destroy();
    }
    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];
            }
        }
    }
    componentDidMount() {
        this._elRef.style.width = this._width ? this._width : "";
        this._elRef.style.height = this._height ? this._height : "";
        this._elRef.appendChild(this.container.getNativeElement());
        this._styling(this._elRef, this);
        this._chart.notifyResized();
    }
    componentWillUnmount() {
        this.destroy();
    }
    createImplementation() {
        return new XamFunnelChart();
    }
    createSeriesComponent(type) {
        if (TypeRegistrar.isRegistered(type)) {
            let s = TypeRegistrar.create(type);
            s.owner = this;
            s._provideRenderer(this._wrapper);
            return s;
        }
        else {
            //we shouldn't get here, hopefully.
            throw Error("series type not loaded: " + type);
        }
    }
    set dataSource(value) {
        this._dataSource = value;
        this.bindData();
    }
    get dataSource() {
        return this._dataSource;
    }
    bindData() {
        if (this._chart != null && this._chart !== undefined) {
            this._chart.itemsSource = this._dataSource;
        }
    }
    /**
     * Gets or sets the legend used for the current chart.
    */
    get legend() {
        if (this.i.legend != null)
            return this.i.legend.externalObject;
    }
    set legend(v) {
        if (v != undefined && v != null)
            this.i.legend = v.i;
    }
    /**
     * @hidden
     */
    get i() {
        return this._implementation;
    } /**
                                 * @hidden
                                 */
    static _createFromInternal(internal) {
        if (!internal) {
            return null;
        }
        if (!internal.$type) {
            return null;
        }
        let name = internal.$type.name;
        let externalName = "Igr" + name;
        if (!TypeRegistrar.isRegistered(externalName)) {
            return null;
        }
        return TypeRegistrar.create(externalName);
    }
    /**
 * Gets or sets the value member path for the funnel chart.
*/
    get valueMemberPath() {
        return this.i.c9;
    }
    set valueMemberPath(v) {
        this.i.c9 = v;
    }
    /**
     * Gets or sets the palette of brushes to use for coloring the slices.
    */
    get brushes() {
        return fromBrushCollection(this.i.ah);
    }
    set brushes(v) {
        this.i.ah = toBrushCollection(v);
    }
    /**
     * Gets or sets the palette of brushes to use for outlines on the slices.
    */
    get outlines() {
        return fromBrushCollection(this.i.ai);
    }
    set outlines(v) {
        this.i.ai = toBrushCollection(v);
    }
    /**
     * Gets or sets the percentage (from near 0 to 1) of space the bottom edge of the funnel should take.
    */
    get bottomEdgeWidth() {
        return this.i.bo;
    }
    set bottomEdgeWidth(v) {
        this.i.bo = +v;
    }
    /**
     * Gets or sets the InnerLabel mapping property for the current series object.
    */
    get innerLabelMemberPath() {
        return this.i.cd;
    }
    set innerLabelMemberPath(v) {
        this.i.cd = v;
    }
    /**
     * Gets or sets the OuterLabel mapping property for the current series object.
    */
    get outerLabelMemberPath() {
        return this.i.co;
    }
    set outerLabelMemberPath(v) {
        this.i.co = v;
    }
    /**
     * Gets or sets whether the inner labels are visible.
    */
    get innerLabelVisibility() {
        return this.i.ez;
    }
    set innerLabelVisibility(v) {
        this.i.ez = ensureEnum(Visibility_$type, v);
    }
    /**
     * Gets or sets whether the outer labels are visible.
    */
    get outerLabelVisibility() {
        return this.i.e0;
    }
    set outerLabelVisibility(v) {
        this.i.e0 = ensureEnum(Visibility_$type, v);
    }
    /**
     * Gets or sets which side of the chart the outer labels should appear.
    */
    get outerLabelAlignment() {
        return this.i.au;
    }
    set outerLabelAlignment(v) {
        this.i.au = ensureEnum(OuterLabelAlignment_$type, v);
    }
    /**
     * Gets or sets how the heights of the funnel slices should be configured.
    */
    get funnelSliceDisplay() {
        return this.i.ak;
    }
    set funnelSliceDisplay(v) {
        this.i.ak = ensureEnum(FunnelSliceDisplay_$type, v);
    }
    /**
     * Gets or sets the formatter function for inner labels. Function should return string and it takes 3 parameters: 1st-value of item to format, 2nd-index of item within data, 3rd-reference to the funnel chart.
    */
    get formatInnerLabel() {
        return this.i.bw;
    }
    set formatInnerLabel(v) {
        this.i.bw = v;
    }
    /**
     * Gets or sets the formatter function for outer labels. Function should return string and it takes 3 parameters: 1st-value of item to format, 2nd-index of item within data, 3rd-reference to the funnel chart.
    */
    get formatOuterLabel() {
        return this.i.bx;
    }
    set formatOuterLabel(v) {
        this.i.bx = v;
    }
    /**
     * Gets or sets how long the animations should take to run.
    */
    get transitionDuration() {
        return this.i.by;
    }
    set transitionDuration(v) {
        this.i.by = +v;
    }
    /**
     * Gets or sets if the funnel should be rendered inverted.
    */
    get isInverted() {
        return this.i.bd;
    }
    set isInverted(v) {
        this.i.bd = ensureBool(v);
    }
    /**
     * Gets or sets whether to use a Bezier curve to define the funnel.
    */
    get useBezierCurve() {
        return this.i.be;
    }
    set useBezierCurve(v) {
        this.i.be = ensureBool(v);
    }
    /**
     * Gets or sets whether to allow slices to be selected.
    */
    get allowSliceSelection() {
        return this.i.a8;
    }
    set allowSliceSelection(v) {
        this.i.a8 = ensureBool(v);
    }
    /**
     * Gets or sets whether to use the unselected style on unselected slices.
    */
    get useUnselectedStyle() {
        return this.i.bg;
    }
    set useUnselectedStyle(v) {
        this.i.bg = ensureBool(v);
    }
    /**
     * Gets or sets the fill brush.
    */
    get selectedSliceFill() {
        return this.i.ex ? this.i.ex.fill : null;
    }
    set selectedSliceFill(v) {
        this.ensureSelectedSliceStyle();
        this.i.ex.fill = v;
    }
    /**
     * Gets or sets the stroke brush.
    */
    get selectedSliceStroke() {
        return this.i.ex ? this.i.ex.stroke : null;
    }
    set selectedSliceStroke(v) {
        this.ensureSelectedSliceStyle();
        this.i.ex.stroke = v;
    }
    /**
     * Gets or sets the stroke thickness.
    */
    get selectedSliceStrokeThickness() {
        return this.i.ex ? this.i.ex.strokeThickness : NaN;
    }
    set selectedSliceStrokeThickness(v) {
        this.ensureSelectedSliceStyle();
        this.i.ex.strokeThickness = +v;
    }
    /**
     * Gets or sets the opacity.
    */
    get selectedSliceOpacity() {
        return this.i.ex ? this.i.ex.opacity : NaN;
    }
    set selectedSliceOpacity(v) {
        this.ensureSelectedSliceStyle();
        this.i.ex.opacity = +v;
    }
    ensureSelectedSliceStyle() {
        if (this.i.ex) {
            return;
        }
        this.i.ex = new Style();
    }
    /**
     * Gets or sets the fill brush.
    */
    get unselectedSliceFill() {
        return this.i.ey ? this.i.ey.fill : null;
    }
    set unselectedSliceFill(v) {
        this.ensureUnselectedSliceStyle();
        this.i.ey.fill = v;
    }
    /**
     * Gets or sets the stroke brush.
    */
    get unselectedSliceStroke() {
        return this.i.ey ? this.i.ey.stroke : null;
    }
    set unselectedSliceStroke(v) {
        this.ensureUnselectedSliceStyle();
        this.i.ey.stroke = v;
    }
    /**
     * Gets or sets the stroke thickness.
    */
    get unselectedSliceStrokeThickness() {
        return this.i.ey ? this.i.ey.strokeThickness : NaN;
    }
    set unselectedSliceStrokeThickness(v) {
        this.ensureUnselectedSliceStyle();
        this.i.ey.strokeThickness = +v;
    }
    /**
     * Gets or sets the opacity.
    */
    get unselectedSliceOpacity() {
        return this.i.ey ? this.i.ey.opacity : NaN;
    }
    set unselectedSliceOpacity(v) {
        this.ensureUnselectedSliceStyle();
        this.i.ey.opacity = +v;
    }
    ensureUnselectedSliceStyle() {
        if (this.i.ey) {
            return;
        }
        this.i.ey = new Style();
    }
    /**
     * Gets or sets the LegendItemBadgeTemplate to use for the legend items.
    */
    get legendItemBadgeTemplate() {
        return this.i.legendItemBadgeTemplate;
    }
    set legendItemBadgeTemplate(v) {
        this.i.legendItemBadgeTemplate = v;
    }
    /**
     * Gets or sets whether to use the outer labels to identify the legend items.
    */
    get useOuterLabelsForLegend() {
        return this.i.bf;
    }
    set useOuterLabelsForLegend(v) {
        this.i.bf = ensureBool(v);
    }
    /**
     * Gets or sets the text style for inner labels
    */
    get textStyle() {
        return this.i.cz;
    }
    set textStyle(v) {
        this.i.cz = v;
    }
    /**
     * Gets or sets the text style for outer labels
    */
    get outerLabelTextStyle() {
        return this.i.cr;
    }
    set outerLabelTextStyle(v) {
        this.i.cr = v;
    }
    /**
     * Gets or sets the thickness of outline around slices.
    */
    get outlineThickness() {
        return this.i.bq;
    }
    set outlineThickness(v) {
        this.i.bq = +v;
    }
    /**
     * Gets or sets the scaling value used to affect the pixel density of the control.
     * A higher scaling ratio will produce crisper visuals at the expense of memory.  Lower values will cause the control
     * to appear blurry.
    */
    get pixelScalingRatio() {
        return this.i.bs;
    }
    set pixelScalingRatio(v) {
        this.i.bs = +v;
    }
    /**
     * Gets or sets the brush used for the outer labels.
    */
    get outerLabelTextColor() {
        return brushToString(this.i.et);
    }
    set outerLabelTextColor(v) {
        this.i.et = stringToBrush(v);
    }
    /**
     * Gets or sets the brush used for the inner labels.
    */
    get textColor() {
        return brushToString(this.i.eu);
    }
    set textColor(v) {
        this.i.eu = stringToBrush(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("FunnelChart");
        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;
    }
    /**
 * Use to force the funnel chart to finish any deferred work before printing or evaluating its visual.
 * This should only be called if the visual of the funnel chart needs to be synchronously saved or evaluated.
 * Calling this method too often will hinder the performance of the funnel chart.

*/
    flush() {
        this.i.dd();
    }
    /**
     * Provides container for funnel chart
    
    */
    provideContainer(container) {
        this.i.provideContainer(container);
    }
    /**
     * Notifies the controller and view about a size change.
    
    */
    notifyResized() {
        this.i.notifyResized();
    }
    notifySetItem(source_, index, oldItem, newItem) {
        this.i.dm(source_, index, oldItem, newItem);
    }
    /**
     * Manually notifies the chart's data source that the data it has bound to has been cleared and needs to be re-examined.
     * This should not be called if the data that the chart is bound to is already observable.
    
    */
    notifyClearItems(source_) {
        this.i.dh(source_);
    }
    notifyInsertItem(source_, index, newItem) {
        this.i.dj(source_, index, newItem);
    }
    notifyRemoveItem(source_, index, oldItem) {
        this.i.dk(source_, index, oldItem);
    }
    /**
     * Toggle selection of item at index.
    
    */
    toggleSelection(index) {
        this.i.dz(index);
    }
    /**
     * Exports and serializes the chart visuals.
    
    */
    exportSerializedVisualData() {
        let iv = this.i.b7();
        return (iv);
    }
    /**
     * Event which is raised when a slice is clicked.
     * Function takes first argument null and second argument ui.
     * Use ui.owner to obtain reference to igFunnelChart.
     * Use ui.index to obtain index of clicked slice.
     * Use ui.item to obtain reference to clicked slice item.
     * Use ui.selected to check if slice became selected.
    */
    get sliceClicked() {
        return this._sliceClicked;
    }
    set sliceClicked(ev) {
        if (this._sliceClicked_wrapped !== null) {
            this.i.sliceClicked = delegateRemove(this.i.sliceClicked, this._sliceClicked_wrapped);
            this._sliceClicked_wrapped = null;
            this._sliceClicked = null;
        }
        this._sliceClicked = ev;
        this._sliceClicked_wrapped = (o, e) => {
            let outerArgs = new IgrFunnelSliceClickedEventArgs();
            outerArgs._provideImplementation(e);
            if (this.beforeSliceClicked) {
                this.beforeSliceClicked(this, outerArgs);
            }
            if (this._sliceClicked) {
                this._sliceClicked(this, outerArgs);
            }
        };
        this.i.sliceClicked = delegateCombine(this.i.sliceClicked, this._sliceClicked_wrapped);
        ;
    }
    /**
     * Raised when a funnel slice is entered.
    */
    get sliceEnter() {
        return this._sliceEnter;
    }
    set sliceEnter(ev) {
        if (this._sliceEnter_wrapped !== null) {
            this.i.sliceEnter = delegateRemove(this.i.sliceEnter, this._sliceEnter_wrapped);
            this._sliceEnter_wrapped = null;
            this._sliceEnter = null;
        }
        this._sliceEnter = ev;
        this._sliceEnter_wrapped = (o, e) => {
            let outerArgs = new IgrFunnelSliceEventArgs();
            outerArgs._provideImplementation(e);
            if (this.beforeSliceEnter) {
                this.beforeSliceEnter(this, outerArgs);
            }
            if (this._sliceEnter) {
                this._sliceEnter(this, outerArgs);
            }
        };
        this.i.sliceEnter = delegateCombine(this.i.sliceEnter, this._sliceEnter_wrapped);
        ;
    }
    /**
     * Raised when a funnel slice is left.
    */
    get sliceLeave() {
        return this._sliceLeave;
    }
    set sliceLeave(ev) {
        if (this._sliceLeave_wrapped !== null) {
            this.i.sliceLeave = delegateRemove(this.i.sliceLeave, this._sliceLeave_wrapped);
            this._sliceLeave_wrapped = null;
            this._sliceLeave = null;
        }
        this._sliceLeave = ev;
        this._sliceLeave_wrapped = (o, e) => {
            let outerArgs = new IgrFunnelSliceEventArgs();
            outerArgs._provideImplementation(e);
            if (this.beforeSliceLeave) {
                this.beforeSliceLeave(this, outerArgs);
            }
            if (this._sliceLeave) {
                this._sliceLeave(this, outerArgs);
            }
        };
        this.i.sliceLeave = delegateCombine(this.i.sliceLeave, this._sliceLeave_wrapped);
        ;
    }
    /**
     * Raised when a funnel slice is hovered.
    */
    get sliceHover() {
        return this._sliceHover;
    }
    set sliceHover(ev) {
        if (this._sliceHover_wrapped !== null) {
            this.i.sliceHover = delegateRemove(this.i.sliceHover, this._sliceHover_wrapped);
            this._sliceHover_wrapped = null;
            this._sliceHover = null;
        }
        this._sliceHover = ev;
        this._sliceHover_wrapped = (o, e) => {
            let outerArgs = new IgrFunnelSliceEventArgs();
            outerArgs._provideImplementation(e);
            if (this.beforeSliceHover) {
                this.beforeSliceHover(this, outerArgs);
            }
            if (this._sliceHover) {
                this._sliceHover(this, outerArgs);
            }
        };
        this.i.sliceHover = delegateCombine(this.i.sliceHover, this._sliceHover_wrapped);
        ;
    }
}
