import { Injectable } from '@angular/core';
// import { Chart } from 'chart.js';
import { Chart } from 'chart.js';

@Injectable()
export class BBCustomChartService {

    public initChart(chartType: any, chartContext: any, data: any, options: any, plugins: any) {

        let chartOptions = {
            type: chartType,
            data: data,
            options: options,
            plugins: plugins
        };
        console.log("BBCustomChartService.initChart chartOptions ::==>>>", chartOptions);
        return new Chart(chartContext, chartOptions);
    }

    public getPlugins(chartType: any, options: any, that: any) {
        var plugins: any = [];
        if (options.chartCenterText && (chartType == 'pie' || chartType == 'doughnut')) {
            plugins = [{
                afterDraw: this.addTextInsideDoughnut.bind(that)
            }]
        }
        if (options.displayTopBar && (chartType == 'bar' || chartType == 'horizontalBar')) {  
            plugins = [{
                afterDatasetsDraw: this.addTextAfterBars.bind(that)
            }]
        }
        if(options.displayMultiLineLbl && (chartType == 'bar' || chartType == 'horizontalBar'))
        {
            if(plugins.length > 0 ) {
                plugins[0]['beforeInit'] = this.addMultiLineLbl.bind(that);
            }
            else {
                plugins = [{
                    beforeInit: this.addMultiLineLbl.bind(that)
                }]    
            }
        }
        console.log("BBCustomChartService.getPlugins plugins for ", chartType, " ==>", plugins);
        return plugins;
    }

    // Add text at center of pie or doughnut chart
    public addTextInsideDoughnut(chart: any) {
        var options = this as any['options'];
        var data = this as any['data'];
        //console.log('addTextInsideDoughnut >> ', chart, options, data);

        var dataText1 = options['chartCenterText'], 
        dataText2 = options['chartCenterText2'],
        dataText3 = options['chartCenterText3'],
        dataText4 = options['chartCenterText4'];

        var chartCenterTextColor1 = options['chartCenterTextColor1'],
        chartCenterTextColor2 = options['chartCenterTextColor2'],
        chartCenterTextColor3 = options['chartCenterTextColor3'],
        chartCenterTextColor4 = options['chartCenterTextColor4'];

        var chartCenterTextFont1 = options['chartCenterTextFont1'],
        chartCenterTextFont2 = options['chartCenterTextFont2'],
        chartCenterTextFont3 = options['chartCenterTextFont3'],
        chartCenterTextFont4 = options['chartCenterTextFont4'];

        if( dataText1.indexOf('+') != -1 )
        {
            dataText1 = eval(dataText1);
        }
        else if( dataText1.indexOf('sum') != -1 )
        {
            dataText1 = eval('BBCustomChartService.' + dataText1);
        }
        
        if( dataText2 && dataText2.indexOf('+') != -1 )
        {
            dataText2 = eval(dataText2);
        }
        if( dataText3 && dataText3.indexOf('+') != -1 )
        {
            dataText3 = eval(dataText3);
        }
        if( dataText4 && dataText4.indexOf('+') != -1 )
        {
            dataText4 = eval(dataText4);
        }       

        var width = chart.width,
            height = chart.height,
            ctx = chart.ctx;
        ctx.restore();

        var middleX = width / 2,
            middleY = height / 2;

        console.log('middleX >>', middleX, 'middleY >>', middleY, 'ctx >>', ctx);

        var fontWeight = '100';
        if( dataText1 && dataText2 && dataText3 && dataText4 )
        {
            ctx.font = chartCenterTextFont1 || "60px sans-serif";
            ctx.textAlign = 'center';
            ctx.fontWeight = '900'; 
            ctx.fillStyle =  chartCenterTextColor1 ||'black';
            ctx.fillText(dataText1, middleX, middleY - 15);
    
            ctx.font = chartCenterTextFont2 || "20px sans-serif";
            ctx.textAlign = 'center';
            ctx.fontWeight = fontWeight; 
            ctx.fillStyle = chartCenterTextColor2 || 'gray';
            ctx.fillText(dataText2, middleX, middleY);

            ctx.font = chartCenterTextFont3 || "20px sans-serif";
            ctx.textAlign = 'center';
            ctx.fontWeight = '900'; 
            ctx.fillStyle = chartCenterTextColor3 || 'black';
            ctx.fillText(dataText3, middleX, middleY + 25);

            ctx.font = chartCenterTextFont4 || "20px sans-serif";
            ctx.textAlign = 'center';
            ctx.fontWeight = fontWeight; 
            ctx.fillStyle = chartCenterTextColor4 || 'gray';
            ctx.fillText(dataText4, middleX, middleY + 40);
        }
        else if( dataText1 && dataText2 && dataText3 )
        {
            ctx.font = chartCenterTextFont1 || "60px sans-serif";
            ctx.textAlign = 'center';
            ctx.fillStyle =  chartCenterTextColor1 ||'black';
            ctx.fillText(dataText1, middleX, middleY);
    
            ctx.font = chartCenterTextFont2 || "20px sans-serif";
            ctx.textAlign = 'center';
            ctx.fillStyle = chartCenterTextColor2 || 'gray';
            ctx.fillText(dataText2, middleX, middleY + 10);

            ctx.font = chartCenterTextFont3 || "20px sans-serif";
            ctx.textAlign = 'center';
            ctx.fillStyle = chartCenterTextColor3 || 'gray';
            ctx.fillText(dataText3, middleX, middleY + 20);
        }
        else if ( dataText1 && dataText2 )
        {
            ctx.font = chartCenterTextFont1 || "60px sans-serif";
            ctx.textAlign = 'center';
            ctx.fillStyle =  chartCenterTextColor1 ||'black';
            ctx.fillText(dataText1, middleX, middleY);
    
            ctx.font = chartCenterTextFont2 || "20px sans-serif";
            ctx.textAlign = 'center';
            ctx.fillStyle = chartCenterTextColor2 || 'gray';
            ctx.fillText(dataText2, middleX, middleY + 20);
        }
        else
        {
            ctx.font = chartCenterTextFont1 || "medium 18px Roboto,sans-serif";
            ctx.textAlign = 'center';
            ctx.fillStyle = chartCenterTextColor1 || 'black';
            ctx.fillText(dataText1, middleX, middleY + 6);
        }

        ctx.save();
    }

    public addMultiLineLbl(chart: any)
    {
        console.log('addMultiLineLbl .. ', chart);
        chart.data.labels.forEach(function(e: any, i: any, a: any) 
        {
            console.log('>>All the params ... ', e ,i, a);
            if (/-/.test(e)) {
                a[i] = e.split('-');
            }
        });

    }

    public addTextAfterBars(chart: any) {

        console.log('addTextAfterBars >>>');

        var chartType = this as any['chartType'];
        var options = this as any['options'];
        console.log('options >> ', options);
 		var chartText = options['chartText'];         
        var chartTextColor = options['topBarValueColor'];
        console.log('addTextAfterBars >> ', chart, chartType, options, this);
        
        // To only draw at the end of animation, check for easing === 1
        var isDataString = options['dataString'];  
        console.log('isDataString >>>>', isDataString );


        if (chartType === 'bar' || chartType === 'horizontalBar') {
            var isHorizontal = (chartType === 'horizontalBar');
            if( isHorizontal ) {
                var stackedBar = options['scales']['yAxes'][0]['stacked'];
            }
            var maxCountLimitArr = [];
            var ctx: any = chart.ctx;
             //this.data.datasets[0].data.forEach(function(data, index) {
            console.log('datasets >>>', chart.data.datasets);
            console.log(chart.data.datasets.length);

            if( stackedBar ) {
                var len = chart.data.datasets.length;
                console.log('stacked true');
            chart.data.datasets.forEach(function (dataset:any, i:any) {
                    console.log('i >>>>', i, 'dataset >>>', dataset);
                    if ( i == ( len - 1 ) ) {
                        console.log('##################%%%%%%%%%%%%%');
                var meta = chart.getDatasetMeta(i);
                        console.log('meta >>>', meta);
                if (!meta.hidden) {
                            //meta.data.forEach(function (element, index) {
                            for ( var j = 0 ; j < meta.data.length; j ++ ) {
                            var element = meta.data[j];
                            var index = j;
                            console.log('element >>', element, 'j >>>', j);

                        // Draw the text in black, with the specified font
                            ctx.fillStyle = chartTextColor || 'rgb(0, 0, 0)'; 

                        //var fontSize = 16;
                        var fontSize = chartText['fontSize'] || 16;
                        var fontStyle = 'bold';
                        var fontFamily = 'Arial, Helvetica, sans-serif';
                        // ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
                        ctx.font = (Chart as any).helpers.fontString(fontSize, fontStyle, fontFamily);
                        // this.newMethod(ctx, fontSize, fontStyle, fontFamily);

                        // Just naively convert to string for now
                            //var dataString = dataset.data[index].toString();
                            //var noOfBars = chartTextArr.length;
                           // var barChartCanvasHeight = ( noOfBars < 5 ) ? ( options.height || 400 ) : ( ( noOfBars * 30 ) + 100 );
                            var dataString = dataset.chartTextArr[index].toString();
                            console.log('dataString >>', dataString);

                            /*
                            dataset.chartTextArr.forEach(function (dataset) {
                                console.log('dataset !!!! >>', dataset);
                                dataset.bars.forEach(function (bar) {
                                    console.log(bar);
                                    ctx.fillText(bar.value, bar.x , bar.y  );
                                });
                            })*/

                        // Make sure alignment settings are correct
                        ctx.textAlign = 'center';
                        ctx.textBaseline = 'top';

                        //var padding = 10;
                        var padding = chartText['padding'] || 10;
                        var position = element.tooltipPosition();
                            console.log('position >>', position);
                        var posX = position.x;
                        var posY = position.y;
                            console.log('posX >>', posX, 'posY >>', posY);
                        //console.log('position', posX, posY);
                        if (isHorizontal) {
                                posX = posX + (fontSize / 2) + padding; //fontSize = 16 padding = 8
                                posY = posY - (fontSize / 2);

                              //  143.4093832057627 23.166666666666668
                                // posX =  144;
                                //posY = 24;
                                //posX = meta.data[index]._model.x;
                                //posY = meta.data[index]._model.y;
                            }
                            else {
                                posX = posX - (fontSize / 2);
                                posY = posY + (fontSize / 2) + padding;
                            }
                            //var dataStringEvaluated = eval(chartText['text']);  //chartText: "formattedValue(dataString, 'RS' )",
                            var dataStringEvaluated = dataString;
                            console.log('dataStringEvaluated %%% >>', dataStringEvaluated);
                            console.log('position', posX, posY, fontSize, padding, isHorizontal);
                            ctx.fillText(dataStringEvaluated, posX, posY);
                        }
                        //);
                    }    
                    }
                    
                });
            }
            else{
            chart.data.datasets.forEach(function (dataset: any, i: any) {
            var meta = chart.getDatasetMeta(i);
            console.log('meta >> ', meta);
            if (!meta.hidden) {
                meta.data.forEach(function (element: any, index: any) {
                    // Draw the text in black, with the specified font
                    ctx.fillStyle = chartTextColor || 'rgb(0, 0, 0)'; 
                    console.log('chartText >> ' , chartText );
                    //var fontSize = 16;
                    var fontSize = chartText['fontSize'] || 16;
                    var fontStyle = 'normal';
                    var fontFamily = chartText['fontFamily'] || 'Helvetica Neue';
                    console.log('fontFamily >> ', fontFamily);
                    // ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
                    ctx.font = (Chart as any).helpers.fontString(fontSize, fontStyle, fontFamily);
                    // this.newMethod(ctx, fontSize, fontStyle, fontFamily);

                    // Just naively convert to string for now
                    //var dataString = dataset.data[index].toString();
                   // var dataString = dataset.chartTextArr[index].toString();
                    //console.log('dataString >>', dataString);
                    var dataString;
                     console.log('dataString >> ', dataString);
                     console.log('dataset >>', dataset);

                    if( isDataString == true ) {
                        dataString = dataset.chartTextArr[index].toString();
                    }else {
                        dataString = dataset.data[index].toString();
                    }

                    // Make sure alignment settings are correct
                    ctx.textAlign = 'left';
                    ctx.textBaseline = 'top';

                    //var padding = 10;
                    var padding = chartText['padding'] || 10;
                    console.log('element >>', element);
                    console.log('element >>', element.tooltipPosition());                    

                    var position = element.tooltipPosition();
                    var posX = position.x;
                    var posY = position.y;
                    console.log('position', posX, posY);
                    if (isHorizontal) {
                            posX = posX + (fontSize / 2) + padding;
                            posY = posY - (fontSize / 2);
                        }
                        else {
                            posX = posX - (fontSize / 2);
                        posY = posY + (fontSize / 2) - padding;
                    }
                    if( isDataString == true ) {
                        var dataStringEvaluated = dataString;  
                        }
                    else{
                        var dataStringEvaluated = eval(chartText['text']);  //chartText: "formattedValue(dataString, 'RS' )",
                    }
                    //var dataStringEvaluated = eval(chartText['text']);  //chartText: "formattedValue(dataString, 'RS' )",
                    console.log('position', posX, posY, fontSize, padding, isHorizontal);
                        ctx.fillText(dataStringEvaluated, posX, posY);
                    });
                }
            });
        }
    }
    }

    /*newMethod(ctx: any, fontSize: any, fontStyle: string, fontFamily: string) 
    {
        throw new Error('Method not implemented');
    }*/

    public evaluateConditionalColor(data: any, conditions: any) : any
    {
        var colors = this.getRandomColor();
        var condition = conditions.filter( (condition: any) => {
            if(eval(condition.expression)) {
                return condition;
            }
        });
        //console.log( 'data : ', data, condition, colors)
        if(condition && condition[0])
        {
            colors = condition[0].colors;
        }
        //console.log( 'data : ', data, condition, colors)
        return colors;
    }
    /*
    1. #0077ff :  [0, 119, 255] Light Blue
    2. #07e883 : [7, 232, 131] Light Green
    3. #47bdef :  [71, 189, 239] Light Sky Blue
    4. #e807ac : [232, 7, 172]   Pink
    5. #e89607 : [232, 150, 7]  Orange
    6. #ff6200 :  [255, 98, 0]  Red
    7. #ffb54d :   [255,  181, 77] Light Orange
    */
    public static defaultColors: Array<number[]> = [
        [0, 119, 255],// Light Blue
        [7, 232, 131],// Light Green
        [71, 189, 239],// Light Sky Blue
        [232, 7, 172],//   Pink
        [232, 150, 7],//  Orange
        [255, 98, 0],//  Red
        [255,  181, 77],// Light Orange
        [255, 0, 0],
        [0, 75, 0],
        [33, 109, 255],  //non-receipt
        [255, 8, 98],
        [167, 148, 224],
        [167, 0, 224],
        [72, 0, 224],
        [255, 0, 224],
        [38, 255, 224],
        [38, 0, 55],
        [148, 159, 177],
        [255, 255, 148]
    ];

    public static sum(arr: any) : any{
        var _sum = arr.reduce((accumulator: any, currentValue: any) => {
            return accumulator + currentValue;
        });
        console.log(arr, _sum);
        return _sum;
    }

    private rgba(colour: Array<number>, alpha: number): string {
        return 'rgba(' + colour.concat(alpha).join(',') + ')';
    }

    private getRandomInt(min: number, max: number): number {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    public formatLineColor(colors: Array<number>): Color {
        return {
            backgroundColor: this.rgba(colors, 0.4),
            borderColor: this.rgba(colors, 1),
            pointBackgroundColor: this.rgba(colors, 1),
            pointBorderColor: '#fff',
            pointHoverBackgroundColor: '#fff',
            pointHoverBorderColor: this.rgba(colors, 0.8)
        };
    }

    public formatBarColor(colors: Array<number>, opacityFinal: any): Color {
        return {
            backgroundColor: this.rgba(colors, opacityFinal),
            borderColor: this.rgba(colors, 1),
            hoverBackgroundColor: this.rgba(colors, 0.8),
            hoverBorderColor: this.rgba(colors, 1)
        };
    }

    public formatPieColors(colors: Array<number[]>, opacityFinal: any, borderWidth?: any, borderColor?: any): Colors {
        return {
            backgroundColor: colors.map((color: number[]) => this.rgba(color, opacityFinal)),
            borderColor: colors.map(() => borderColor || '#fff'),
            borderWidth: borderWidth || 0,
            pointBackgroundColor: colors.map((color: number[]) => this.rgba(color, 1)),
            pointBorderColor: colors.map(() => '#fff'),
            pointHoverBackgroundColor: colors.map((color: number[]) => this.rgba(color, 1)),
            pointHoverBorderColor: colors.map((color: number[]) => this.rgba(color, 1))
        };
    }

    public formatPolarAreaColors(colors: Array<number[]>, opacityFinal: any): Color {
        return {
            backgroundColor: colors.map((color: number[]) => this.rgba(color, opacityFinal)),
            borderColor: colors.map((color: number[]) => this.rgba(color, 1)),
            hoverBackgroundColor: colors.map((color: number[]) => this.rgba(color, 0.8)),
            hoverBorderColor: colors.map((color: number[]) => this.rgba(color, 1))
        };
    }

    private getRandomColor(): number[] {
        return [this.getRandomInt(0, 255), this.getRandomInt(0, 255), this.getRandomInt(0, 255)];
    }

    /**
     * Generate colors for line|bar charts
     * @param index
     * @returns {number[]|Color}
     */
    private generateColor(index: number): number[] {
        return BBCustomChartService.defaultColors[index] || this.getRandomColor();
    }

    /**
     * Generate colors for pie|doughnut charts
     * @param count
     * @returns {Colors}
     */
    private generateColors(count: number): Array<number[]> {
        let colorsArr: Array<number[]> = new Array(count);
        for (let i = 0; i < count; i++) {
            colorsArr[i] = BBCustomChartService.defaultColors[i] || this.getRandomColor();
        }
        return colorsArr;
    }

    /**
     * Generate colors by chart type
     * @param chartType
     * @param index
     * @param count
     * @returns {Color} 
     */
    public getColors(chartType: string, index: number, count: number, opacity: number): any {
        console.log("BBCustomChartService.getColors for chartType ", chartType);
        if (chartType === 'pie' || chartType === 'doughnut') {
            return this.formatPieColors(this.generateColors(count), opacity);
        }

        if (chartType === 'polarArea') {
            return this.formatPolarAreaColors(this.generateColors(count), opacity);
        }

        if (chartType === 'line' || chartType === 'radar') {
            return this.formatLineColor(this.generateColor(index));
        }

        if (chartType === 'bar' || chartType === 'horizontalBar') {
            return this.formatBarColor(this.generateColor(index), opacity);
        }
        return this.generateColor(index);
    }

    public containsObject(obj: any, list: any) {
        var i;
        if (list) {
            for (i = 0; i < list.length; i++) {
                if (list[i].label == obj.label) {
                    return true;
                }
            }
            return false;
        }
    }
    
    public getGradient(ctx: any, color: any)
    {
        var gradient;
        switch(color){
        case 'blue':
            gradient= ctx.createLinearGradient(200, 0, 0, -200);
            gradient.addColorStop(1, '#007bab');   
            gradient.addColorStop(0, '#00c9ff');
            break;
        case 'violet':
            gradient= ctx.createLinearGradient(200, 0, 0, -200);
            gradient.addColorStop(1, '#7053cc');   
            gradient.addColorStop(0, '#c3b3f7');
            break;
        case 'green':
            gradient= ctx.createLinearGradient(200, 0, 0, -200);
            gradient.addColorStop(1, '#01a27f');   
            gradient.addColorStop(0, '#00e1af');
            break;
        case 'orange':
            gradient= ctx.createLinearGradient(200, 0, 0, -200);
            gradient.addColorStop(1, '#e47842');   
            gradient.addColorStop(0, '#ffac83');
            break;
        case 'gray':
            gradient= ctx.createLinearGradient(200, 0, 0, -200);
            gradient.addColorStop(1, '#333333');   
            gradient.addColorStop(0, '#666666');
            break;
        case 'default':
            gradient= ctx.createLinearGradient(200, 0, 0, -200);
            gradient.addColorStop(1, '#333333');   
            gradient.addColorStop(0, '#666666');
            break;      
        }
        return gradient;
    }
}


// private helper functions
export interface Color {
    backgroundColor?: string | string[];
    borderWidth?: number | number[];
    borderColor?: string | string[];
    borderCapStyle?: string;
    borderDash?: number[];
    borderDashOffset?: number;
    borderJoinStyle?: string;

    pointBorderColor?: string | string[];
    pointBackgroundColor?: string | string[];
    pointBorderWidth?: number | number[];

    pointRadius?: number | number[];
    pointHoverRadius?: number | number[];
    pointHitRadius?: number | number[];

    pointHoverBackgroundColor?: string | string[];
    pointHoverBorderColor?: string | string[];
    pointHoverBorderWidth?: number | number[];
    pointStyle?: string | string[];

    hoverBackgroundColor?: string | string[];
    hoverBorderColor?: string | string[];
    hoverBorderWidth?: number;
}

// pie | doughnut
export interface Colors extends Color {
    data?: number[];
    label?: string;
}
