/**
 * Created by rburson on 4/27/16.
 */

import * as React from 'react'
import {
    CvState,
    CvProps,
    CvBaseMixin,
    CvNavigationResult,
    CvEvent,
    CvContext,
    CvStateChangeResult,
    CvQueryPaneCallback,
    CvQueryPane,
    CvValueProvider,
    CvValueAdapter,
    CvValueListener,
    CvActionHandlerParams,
    CvProp,
    CvAction,
    CvActionCallback,
    CvActionFiredResult, ColorUtil
} from 'catreact'
import {
    FormContext, GraphContext, GraphDef, GraphDataPointDef, ObjUtil, EntityRec, ArrayUtil, Log, Prop, PropDef,
    PropFormatter
} from 'catavolt-sdk'

import {
    LineChart,
    BarChart,
    PieChart,
    ScatterChart,
    Line,
    Bar,
    Pie,
    Scatter,
    XAxis,
    YAxis,
    ZAxis,
    CartesianGrid,
    Tooltip,
    Legend,
    Dot,
    ResponsiveContainer,
    Cell,
    ReferenceLine
} from 'recharts'


const CV_GRADIENT_COLORS = [     // From Flex
    ['#A1AECF', '#47447A'],  // Blue
    ['#EF7651', '#994C34'],  // Red
    ['#E9C836', '#AA9127'],  // Yellow
    ['#6FB35F', '#497B54'],  // Green
    ['#BA9886', '#AE775B'],  // Dingy Red

    ['#8B8989', '#8B6969'],  // Snow       Gry

    ['#9400D3', '#4B0082'],  // DarkViolet Blu
    ['#FFC1C1', '#EEB4B4'],  // RosyBrown  Red
    ['#FFFF00', '#EEEE00'],  // Yellow     Ylw
    ['#7FFFD4', '#76EEC6'],  // Aquamarine Grn

    ['#CAE1FF', '#BCD2EE'],  // LtSteelBl  Blu
    ['#FF6A6A', '#EE6363'],  // IndianRed  Red
    ['#FFD700', '#EEC900'],  // Gold       Gld
    ['#00FF00', '#32CD32'],  // Lime       Grn

    ['#1C86EE', '#104E8B'],  // DodgerBlu  Blu
    ['#FF3030', '#EE3B3B'],  // FireBrick  Red
    ['#EEE685', '#BDB76B'],  // Khaki      Brn
    ['#ADFF2F', '#A2CD5A'],  // YellowGrn  Grn

    ['#EE00EE', '#CD00CD'],  // Magenta    Prp
    ['#00F5FF', '#00E5EE'],  // Turquoise  Trq
    ['#FFFACD', '#EEE8AA'],  // LemonChifn Brn
    ['#54FF9F', '#2E8B57'],  // SeaGreen   Grn

    ['#4876FF', '#436EEE'],  // RoyalBlue  Blu
    ['#FFAEB9', '#CD8C95'],  // LightPink  Pnk
    ['#EEB422', '#CD9B1D'],  // Goldenrod  Gld
    ['#7FFF00', '#76EE00'],  // Chartreuse Grn

    ['#6959CD', '#473C8B'],  // SlateBlue  Blu
    ['#FFBBFF', '#EEAEEE'],  // Plum       Prp
    ['#EEEE00', '#CDCD00'],  // Yellow     Ylw
    ['#00FF00', '#32CD32'],  // Lime       Grn

    ['#AB82FF', '#9F79EE'],  // MedPurple  Blu
    ['#EE7AE9', '#DA70D6'],  // Orchid     Prp
    ['#FFF68F', '#CDC673'],  // Khaki      Brn
    ['#76EEC6', '#66CDAA'],  // SpringGrn  Grn

    ['#0000FF', '#0000EE'],  // Blue       Blu
    ['#EE82EE', '#CD96CD'],  // Violet     Prp
    ['#FFE7BA', '#F5DEB3'],  // Wheat      Gry
    ['#008B8B', '#008080']]; // DarkCyan   Trq

// const CV_GRAPH_DEFAULT_COLORS =  ['#1E6FF2', '#F29500', '#15BFA2', '#6F5F5A'];
const CV_GRAPH_DEFAULT_COLORS:string[] =  CV_GRADIENT_COLORS.map((g:string[])=>{ return g[1]});  // Convert from gradient to flat


/* Base mixin for Charts */
// http://recharts.org/api/#/en-US/api
// https://www.w3.org/TR/SVG/styling.html   For styling
export const CvChart = {

    axisType: function(graphContext:GraphContext, propName:string, data:Array<any>) {
        const propDef:PropDef = graphContext.propDefAtName(propName);
        let numeric = true;
        if(propDef) {
            numeric = propDef.isNumericType;
        } else {
            //fallback to a sample value
            numeric = typeof this._getSampleValue(data, propName) === 'number';
        }
        return numeric ? 'number' : 'category';
    },

    colorForDataPointDef: function (dataPointDef:GraphDataPointDef, i:number) {
        return this._zeroFill(dataPointDef.seriesColor) || this.props.defaultSeriesColors[i % this.props.defaultSeriesColors.length];
    },

    getMetaValues: function(graphDef:GraphDef, data:Array<any>) {
        
        const minX = graphDef.xAxisRangeFrom ? graphDef.xAxisRangeFrom : 0;
        const maxX = graphDef.xAxisRangeTo ? graphDef.xAxisRangeTo : 'auto';
        const minY = graphDef.yAxisRangeFrom ? graphDef.yAxisRangeFrom : 0;
        const maxY = graphDef.yAxisRangeTo ? graphDef.yAxisRangeTo : 'auto';
        const xAxisLabel = graphDef.xAxisLabel;
        const yAxisLabel = graphDef.yAxisLabel;
        
        return {minX:minX, maxX:maxX, minY:minY, maxY:maxY, xAxisLabel:xAxisLabel, yAxisLabel:yAxisLabel};
    },

    handleClick(id) {
        if(this.props.clickHandler) {
            this.props.clickHandler(id);
        }
    },

    _applyAlpha: function(c, a:number):string {
        return ColorUtil.toColorFromNumWithAlpha(Number("0x" + c.substr(1)), a);
    },

    _getSampleValue(data:Array<any>, name:string):any {
        if(data && data.length > 0) {
            return data[0][name];
        }
    },

    _zeroFill(color:string):string {   // charts fail with a color like: #ff so convert to #0000ff;
        if (color && color.length > 1) {
            color = color.charAt(0) === '#' ? color.substring(1) : color;
            while (color.length < 6) { color = '0' + color }
            return '#' + color;
        }
        return null;
    }

}

/* Base props for Charts */
export interface CvChartProps extends CvProps {
    graphContext:GraphContext;
    data:Array<any>;
    identPropName:string;
    defaultSeriesColors:Array<string>;
    clickHandler:(id:string)=>void;
}

/* Cartesian style line chart */
export const CvLineChart = React.createClass<CvChartProps, {}>({

    mixins: [CvChart],

    render: function () {
        const graphContext = this.props.graphContext;
        const graphDef = graphContext.graphDef;
        const {minX, maxX, minY, maxY, xAxisLabel, yAxisLabel} = this.getMetaValues(graphDef, this.props.data);
        const yPropDef:PropDef = graphContext.propDefAtName(graphDef.dataPointDefs[0].name);  // First will do
        const xType = this.axisType(this.props.graphContext, graphDef.identityDataPointDef.name, this.props.data);
        const yType = this.axisType(this.props.graphContext, graphDef.dataPointDefs[0].name, this.props.data);
        const yAxisFormat = (value) => {
            return PropFormatter.formatValueForRead(value, yPropDef);
        };

        return (
            <div className="cv-component-container cv-graph-container">
                <ResponsiveContainer width="99%" height="95%">
                    <LineChart data={this.props.data} margin={{top: 20, right: 50, left: 20, bottom: 5}}>
                        <XAxis dataKey={this.props.identPropName} domain={[minX, maxX]} label={xAxisLabel} type={xType}/>
                        <YAxis tickFormatter={yAxisFormat} domain={[minY, maxY]} label={yAxisLabel} allowDataOverflow={true} type={yType}/>
                        <CartesianGrid strokeDasharray="3 3"/>
                        <Tooltip/>
                        <Legend />
                        {graphDef.dataPointDefs.map((dataPointDef:GraphDataPointDef, i:number)=>{
                            const seriesColor = this.colorForDataPointDef(dataPointDef, i);
                            const legendKey = dataPointDef.legendKey || dataPointDef.name;
                            return <Line key={i} type="monotone" dataKey={dataPointDef.name} name={legendKey}
                                         dot={true} activeDot={true} stroke={seriesColor}
                                         onClick={(data)=>{this.handleClick(data.id)}}/>
                            })}
                    </LineChart>
                </ResponsiveContainer>
            </div>
        );
    },

});

/* Cartesian style bar chart */
export interface CvBarChartProps extends CvChartProps {
    stack?:boolean;
}

export const CvBarChart = React.createClass<CvBarChartProps, {}>({

    mixins: [CvChart],

    render: function () {
        const graphContext = this.props.graphContext;
        const graphDef = graphContext.graphDef;
        const {minX, maxX, minY, maxY, xAxisLabel, yAxisLabel} = this.getMetaValues(graphDef, this.props.data);
        const yPropDef:PropDef = graphContext.propDefAtName(graphDef.dataPointDefs[0].name);  // First will do
        const xType = this.axisType(this.props.graphContext, graphDef.identityDataPointDef.name, this.props.data);
        const yType = this.axisType(this.props.graphContext, graphDef.dataPointDefs[0].name, this.props.data);
        const yAxisFormat = (value) => {
            return PropFormatter.formatValueForRead(value, yPropDef);
        };

        return (
            <div className="cv-graph-container">
                <ResponsiveContainer width="99%" height="95%">
                    <BarChart data={this.props.data} margin={{top: 20, right: 50, left: 20, bottom: 5}}>
                        <XAxis dataKey={this.props.identPropName} domain={[minX, maxX]} label={xAxisLabel} />
                        <YAxis tickFormatter={yAxisFormat} domain={[minY, maxY]} label={yAxisLabel} />
                        <CartesianGrid strokeDasharray="3 3"/>
                        <Tooltip/>
                        <Legend/>
                        {graphDef.dataPointDefs.map((dataPointDef:GraphDataPointDef, i1:number)=>{
                            const legendKey = dataPointDef.legendKey || dataPointDef.name;
                            const seriesColor = this.colorForDataPointDef(dataPointDef, i1);
                            const props = {
                                    dataKey:dataPointDef.name,
                                    name:legendKey,
                                    fill:seriesColor,
                                    onClick:(data)=>{this.handleClick(data.id)},
                                    key:i1
                                  };
                            if(this.props.stack) props['stackId'] = 'a';
                            return <Bar {...props}>
                                {
                                    this.props.data.map((data, i2) => {  // Check for annotation color
                                        const c = data.annoColor ? data.annoColor : seriesColor;
                                        return <Cell key={`cell-${i2}`} fill={c}/>
                                    })
                                }
                            </Bar>
                         })}
                    </BarChart>
                </ResponsiveContainer>
            </div>
        );
    }

});

/* Cartesian style Scatter chart */
export interface CvScatterChartProps extends CvChartProps {
    bubble?:boolean;
}
export const CvScatterChart = React.createClass<CvScatterChartProps, {}>({

    mixins: [CvChart],

    render: function () {

        const graphDef = this.props.graphContext.graphDef;
        const {minX, maxX, minY, maxY, xAxisLabel, yAxisLabel} = this.getMetaValues(graphDef, this.props.data);
        //note: to support multiple 'scatter series' the data set has to be broken in corresponding discrete sets
        //for now, we're taking the first dataPointDef only
        const dataPointDef = graphDef.dataPointDefs[0];
        
        const xType = this.axisType(this.props.graphContext, dataPointDef.xAxisName, this.props.data);
        const yType = this.axisType(this.props.graphContext, dataPointDef.name, this.props.data);

        if(dataPointDef) {
            const legendKey = dataPointDef.legendKey || dataPointDef.name;
            if (graphDef.displayQuadrantLines) {
                var xRef = <ReferenceLine x={(maxX+minX)/2} stroke="lightGrey" strokeWidth="8" />;
                var yRef = <ReferenceLine y={(maxY+minY)/2} stroke="lightGrey" strokeWidth="8"/>;
            }
            return (
                <div className="cv-graph-container">
                    <ResponsiveContainer width="99%" height="95%"  >
                        <ScatterChart margin={{top: 20, right: 50, left: 20, bottom: 5}} >
                            <XAxis dataKey={dataPointDef.xAxisName} name={dataPointDef.xAxisName} domain={[minX, maxX]} label={xAxisLabel} ref="xAxis"  />
                            <YAxis dataKey={dataPointDef.name} name={legendKey} domain={[minY, maxY]} label={yAxisLabel} ref="yAxis"/>
                            { xRef }
                            { yRef }
                            {(()=>{
                                if(this.props.bubble) {
                                    if(dataPointDef.bubbleRadiusName) {
                                        return <ZAxis dataKey={dataPointDef.bubbleRadiusName} name={dataPointDef.bubbleRadiusName} range={[10000, 50000]}/>
                                    } else {
                                        return <ZAxis dataKey={dataPointDef.bubbleRadiusName} name={dataPointDef.bubbleRadiusName} range={[10000, 10000]}/>
                                    }
                                } else {
                                    return <ZAxis/>
                                 }
                            })()}
                            <CartesianGrid/>
                            <Tooltip cursor={{strokeDasharray: '3 3'}} formatter={this._formatterFunction} labelFormatter={this._labelFormatterFunction}/>
                            <Scatter data={this.props.data}  onClick={(data)=>{this.handleClick(data.id)}}>
                                {
                                    this.props.data.map((data, i2) => {  // Check for annotation color
                                        let f = data.annoColor ? data.annoColor : this.colorForDataPointDef(dataPointDef, 0);
                                        if (dataPointDef.bubbleRadiusName) { f = this._applyAlpha(f, .4) };
                                        return <Cell key={`cell-${i2}`} fill={f} />
                                    })
                                }
                            </Scatter>
                        </ScatterChart>
                    </ResponsiveContainer>
                </div>
            );
        } else {
            return null;
        }
    },

    _labelFormatterFunction: function(a,b,c,d) {
        return "here";
    },

    _formatterFunction: function(a,b,c,d) {
        return "here";
    }

});


/* Pie chart */
export interface CvPieChartProps extends CvChartProps {
}

export const CvPieChart = React.createClass<CvPieChartProps, {}>({

    mixins: [CvChart],

    render: function () {
        const graphContext = this.props.graphContext;
        const graphDef = graphContext.graphDef;
        //note: to support multiple 'pie levels' the data set has to be broken in corresponding discrete sets
        //for now, we're taking the first dataPointDef only
        const dataPointDef = graphDef.dataPointDefs[0];

        if(dataPointDef) {
            const propDef:PropDef = graphContext.propDefAtName(dataPointDef.name);
            const legendKey = dataPointDef.legendKey || dataPointDef.name;
            return (
                <div className="cv-graph-container">
                    <ResponsiveContainer width="99%" height="95%">
                        <PieChart margin={{top: 20, right: 50, left: 20, bottom: 5}} onClick={(data)=>{this.handleClick(data.id)}}>
                            <Tooltip cursor={{strokeDasharray: '3 3'}}/>
                            <Legend/>
                            <Pie data={this.props.data}
                                 nameKey={this.props.identPropName} valueKey={dataPointDef.name} label={(v)=>{return PropFormatter.formatValueForRead(v.value, propDef)}}>
                                {this.props.data.map((data, i:number)=>{  // Check for annotation color
                                    const color = data.annoColor ? data.annoColor : this.colorForDataPointDef(dataPointDef, i);
                                    return <Cell key={`cell-${i}`} fill={color}/>
                                })}
                            </Pie>
                        </PieChart>
                    </ResponsiveContainer>
                </div>
            );
        } else {
            return null;
        }
    }

});

export interface CvGraphPanelState extends CvState {
}

export interface CvGraphPanelProps extends CvProps {
    paneRef?:number;
    formContext?:FormContext;
    graphContext:GraphContext;
    navigationListeners?:Array<(event:CvEvent<CvNavigationResult>)=>void>;
    selectionListener?:CvValueListener<Array<string>>;
    actionListeners?:Array<(event:CvEvent<CvActionFiredResult>)=>void>
    stateChangeListeners?:Array<(event:CvEvent<CvStateChangeResult>)=>void>;
    navTarget?:string;
    defaultSeriesColors?:Array<string>;
    actionProvider?:CvValueProvider<CvActionHandlerParams>;
}


/*
 ***************************************************
 * Render a Graph
 ***************************************************
 */
export const CvGraphPanel = React.createClass<CvGraphPanelProps, CvGraphPanelState>({

    mixins: [CvBaseMixin],

    componentDidMount: function () {
    },

    getDefaultProps: function () {
        return {
            paneRef: null,
            formContext: null,
            graphContext: null,
            navigationListeners: [],
            selectionListener: null,
            stateChangeListeners: [],
            actionListeners: [],
            defaultSeriesColors: CV_GRAPH_DEFAULT_COLORS,
            navTarget: null,
            actionProvider: null
        }
    },

    getInitialState: function () {
        return {}
    },
    

    render: function () {

        const {} = this.state;

        const graphPaneProps = {
            paneRef: this.props.paneRef,
            formContext: this.props.formContext,
            queryContext: this.props.graphContext,
            stateChangeListeners: this.props.stateChangeListeners,
            actionListeners: this.props.actionListeners,
            actionProvider: this.props.actionProvider
        }

        return (
            <CvQueryPane {...graphPaneProps} queryRenderer={(cvContext:CvContext, callback:CvQueryPaneCallback)=>{
                    const graphContext:GraphContext = cvContext.scopeCtx.scopeObj;
                    return <CvGraph graphContext={graphContext}
                                    lastRefreshTime={graphContext.lastRefreshTime}
                                    navigationListeners={this.props.navigationListeners}
                                    selectionListener={this.props.selectionListener}
                                    actionListeners={this.props.actionListeners}
                                    stateChangeListeners={this.props.stateChangeListeners}
                                    navTarget={this.props.navTarget}
                                    defaultSeriesColors={this.props.defaultSeriesColors}
                    />
            }}/>
        );
    },

});


export interface CvGraphState extends CvState {
}

export interface CvGraphProps extends CvProps {
    graphContext:GraphContext;
    lastRefreshTime:Date,
    navigationListeners?:Array<(event:CvEvent<CvNavigationResult>)=>void>;
    selectionListener?:CvValueListener<Array<string>>;
    actionListeners?:Array<(event:CvEvent<CvActionFiredResult>)=>void>
    stateChangeListeners?:Array<(event:CvEvent<CvStateChangeResult>)=>void>;
    navTarget?:string;
    defaultSeriesColors?:Array<string>;
}


export const CvGraph = React.createClass<CvGraphProps, CvGraphState>({

    mixins: [CvBaseMixin],

    componentDidMount: function () {
    },

    getDefaultProps: function () {
        return {
            graphContext: null,
            lastRefreshTime: null,
            navigationListeners: [],
            selectionListener: null,
            stateChangeListeners: [],
            actionListeners: [],
            defaultSeriesColors: CV_GRAPH_DEFAULT_COLORS,
            navTarget: null,
        }
    },

    getInitialState: function () {
        return {}
    },


    render: function () {

        const graphContext:GraphContext = this.props.graphContext;
        const selectionAdapter:CvValueAdapter<Array<string>> = new CvValueAdapter<Array<string>>();
        const selectionListener:CvValueListener<Array<string>> = selectionAdapter.createValueListener();

        return <CvAction actionId={graphContext.graphDef.defaultActionId}
                         paneContext={graphContext}
                         navigationListeners={this.props.navigationListeners}
                         actionListeners={this.props.actionListeners}
                         stateChangeListeners={this.props.stateChangeListeners}
                         selectionProvider={selectionAdapter}
                         renderer={(cvContext:CvContext, callback?:CvActionCallback)=>{

                             const clickHandler = (id:string) => {
                                 selectionListener([id]);
                                 // Because the selectionListener is setting state that needs to be read by the callback,
                                 // don't fire the callback until the state is set.  Accomplished by setting some dummy
                                 // state.
                                 this.setState({}, ()=>{callback.fireAction()});
                             }

                             const graphDef:GraphDef = graphContext.graphDef;
                             const records:Array<EntityRec> = ArrayUtil.copy<EntityRec>(graphContext.scroller.buffer);
                             const points:Array<any> = graphDef.graphType === GraphDef.GRAPH_TYPE_PIE ?
                                 this._generateDataForPieChart(graphContext, records) : this._generateData(graphContext, records);
                             const identPropName = graphDef.identityDataPointDef.name;
                             const plotTypes = graphDef.dataPointDefs.map((dataPointDef:GraphDataPointDef)=>{ return dataPointDef.plotType }).filter((v:string)=>{ return !!v; });
                             if(graphDef.graphType === GraphDef.GRAPH_TYPE_CARTESIAN) {
                                 if (plotTypes.length === 0 || plotTypes.indexOf(GraphDef.PLOT_TYPE_BAR) > -1){
                                     return <CvBarChart graphContext={graphContext} data={points} identPropName={identPropName}
                                                        defaultSeriesColors={this.props.defaultSeriesColors} clickHandler={clickHandler}/>
                                 } else if(plotTypes.indexOf(GraphDef.PLOT_TYPE_LINE) > -1) {
                                     return <CvLineChart graphContext={graphContext} data={points} identPropName={identPropName}
                                                         defaultSeriesColors={this.props.defaultSeriesColors} clickHandler={clickHandler}/>
                                 } else if(plotTypes.indexOf(GraphDef.PLOT_TYPE_STACKED) > -1) {
                                     return <CvBarChart graphContext={graphContext} data={points} identPropName={identPropName}
                                                        defaultSeriesColors={this.props.defaultSeriesColors} stack={true} clickHandler={clickHandler}/>
                                 } else if(plotTypes.indexOf(GraphDef.PLOT_TYPE_SCATTER) > -1) {
                                     return <CvScatterChart graphContext={graphContext} data={points} identPropName={identPropName}
                                                            defaultSeriesColors={this.props.defaultSeriesColors} clickHandler={clickHandler}/>
                                 }else if(plotTypes.indexOf(GraphDef.PLOT_TYPE_BUBBLE) > -1 ) {
                                     return <CvScatterChart graphContext={graphContext} data={points} identPropName={identPropName}
                                                            defaultSeriesColors={this.props.defaultSeriesColors} bubble={true} clickHandler={clickHandler}/>
                                 } else {
                                     return null;
                                 }
                             } else if(graphDef.graphType === GraphDef.GRAPH_TYPE_PIE) {
                                 return <CvPieChart graphContext={graphContext} data={points} identPropName={identPropName}
                                                    defaultSeriesColors={this.props.defaultSeriesColors} clickHandler={clickHandler}/>
                             } else {
                                 return null;
                             }

                         }}/>

    },

    shouldComponentUpdate(nextProps, nextState) {

        /*
         This is an 'inclusive' change list - updates DO NOT happen by default
         Desired updates should be explicitly added here
         */

        //update if we have new list data
        if (nextProps.lastRefreshTime) {
            if (this.props.lastRefreshTime) {
                if (nextProps.lastRefreshTime.getTime() > this.props.lastRefreshTime.getTime()) {
                    return true;
                }
            } else {
                return true;
            }
        }
        return false;
    },


    _formatProp: function(prop:Prop, propDef:PropDef) {
        if(propDef && !propDef.isNumericType) {
            return PropFormatter.formatValueForRead(prop.value, propDef);
        } else if(typeof prop.value !== 'number') {
            return PropFormatter.formatValueForRead(prop.value, null);
        } else {
            return Number(prop.value);
        }
    },

    _generateData: function(graphContext:GraphContext, records:Array<EntityRec>):Array<any> {

        const graphDef:GraphDef = graphContext.graphDef;
        //prop for 1 axis (or dimension)
        const identPropName = graphDef.identityDataPointDef.name;
        const points = records.map((record:EntityRec)=>{
            const item = {}
            item['id'] = record.objectId;
            item[identPropName] = this._formatProp(record.propAtName(identPropName), graphContext.propDefAtName(identPropName));
            item['annoColor'] = record.foregroundColor;
            //possible props for other axes (or dimensions)
            graphDef.dataPointDefs.forEach((dataPointDef:GraphDataPointDef)=>{
                const propName = dataPointDef.name;
                if(propName) item[propName] = this._formatProp(record.propAtName(propName), graphContext.propDefAtName(propName));
                const xAxisName = dataPointDef.xAxisName;
                if(xAxisName) item[xAxisName] = this._formatProp(record.propAtName(xAxisName), graphContext.propDefAtName(xAxisName));
                const radiusName = dataPointDef.bubbleRadiusName;
                if(radiusName) item[radiusName] = Number(record.propAtName(radiusName).value);
            });
            return item;
        });
        return points;
    },

    _generateDataForPieChart: function(graphContext:GraphContext, records:Array<EntityRec>) {

        /* The pie chart requires the primary series to be numeric */
        const graphDef:GraphDef = graphContext.graphDef;
        //prop for 1 axis (or dimension)
        const identPropName = graphDef.identityDataPointDef.name;
        const points = records.map((record:EntityRec)=>{
            const item = {}
            item['id'] = record.objectId;
            item[identPropName] = this._formatProp(record.propAtName(identPropName), graphContext.propDefAtName(identPropName));
            item['annoColor'] = record.foregroundColor;
            graphDef.dataPointDefs.forEach((dataPointDef:GraphDataPointDef)=>{
                const propName = dataPointDef.name;
                //force numeric typing
                if(propName) item[propName] = Number(record.propAtName(propName).value);
            });
            return item;
        });
        return points;
    },

});







