odoo.define("project_report.GraphRenderer", function(require) {
var GraphRenderer = require("web.GraphRenderer");
var AbstractRenderer = require('web.AbstractRenderer');
var config = require('web.config');
var core = require('web.core');
var dataComparisonUtils = require('web.dataComparisonUtils');
var fieldUtils = require('web.field_utils');

var _t = core._t;
var DateClasses = dataComparisonUtils.DateClasses;
var qweb = core.qweb;

var CHART_TYPES = ['pie', 'bar', 'horizontalBar', 'line'];
// #d62728 into #794dd6
var COLORS = ["#1f77b4", "#ff7f0e", "#aec7e8", "#ffbb78", "#2ca02c", "#98df8a", "#794dd6",
    "#ff9896", "#9467bd", "#c5b0d5", "#8c564b", "#c49c94", "#e377c2", "#f7b6d2",
    "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5"];
var COLOR_NB = COLORS.length;

function hexToRGBA(hex, opacity) {
    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    var rgb = result.slice(1, 4).map(function (n) {
        return parseInt(n, 16);
    }).join(',');
    return 'rgba(' + rgb + ',' + opacity + ')';
}

// used to format values in tooltips and yAxes.
var FORMAT_OPTIONS = {
    // allow to decide if utils.human_number should be used
    humanReadable: function (value) {
        return Math.abs(value) >= 1000;
    },
    // with the choices below, 1236 is represented by 1.24k
    minDigits: 1,
    decimals: 2,
    // avoid comma separators for thousands in numbers when human_number is used
    formatterCallback: function (str) {
        return str;
    },
};

var NO_DATA = [_t('No data')];
NO_DATA.isNoData = true;

// Hide top legend when too many items for device size
var MAX_LEGEND_LENGTH = 25 * (1 + config.device.size_class);


    GraphRenderer.include({
        init: function(parent, state, params) {
            this._super.apply(this, arguments);
            this.context = state.context;
            this.resModel = this.context && this.context.default_res_model;
            //if (this.resModel == 'project.budget.hrs.report') {
               // this.title = 'Time Line';
           // }
        },

    _formatValue: function (value) {
        //this._super.apply(this, arguments);
        var measureField = this.fields[this.state.measure];
        var formatter = fieldUtils.format.float;
        var formatedValue = formatter(value, measureField, FORMAT_OPTIONS);
        return formatedValue;
    },
    /**
     * Used any time we need a new color in our charts.
     *
     * @private
     * @param {number} index
     * @returns {string} a color in HEX format
     */
    _getColor: function (index) {
        return COLORS[index % COLOR_NB];
    },
    /**
     * Determines the initial section of the labels array
     * over a dataset has to be completed. The section only depends
     * on the datasets origins.
     *
     * @private
     * @param {number} originIndex
     * @param {number} defaultLength
     * @returns {number}
     */
    _getDatasetDataLength: function (originIndex, defaultLength) {
        if (_.contains(['bar', 'horizontalBar', 'line'], this.state.mode) && this.state.comparisonFieldIndex === 0) {
            return this.dateClasses.dateSets[originIndex].length;
        }
        return defaultLength;
    },

     /**
     * Determines over which label is the data point
     *
     * @private
     * @param {Object} dataPt
     * @returns {Array}
     */
   _getLabel: function (dataPt) {
        var i = this.state.comparisonFieldIndex;
        if (_.contains(['bar', 'horizontalBar', 'line'], this.state.mode)) {
            if (i === 0) {
                return [this.dateClasses.dateClass(dataPt.originIndex, dataPt.labels[i])];
            } else {
                return dataPt.labels.slice(0, 1);
            }
        } else if (i === 0) {
            return Array.prototype.concat.apply([], [
                        this.dateClasses.dateClass(dataPt.originIndex, dataPt.labels[i]),
                        dataPt.labels.slice(i+1)
                    ]);
        } else {
            return dataPt.labels;
        }
    },

    /**
     * Returns an object used to style chart elements independently from the datasets.
     *
     * @private
     * @returns {Object}
     */
    _getElementOptions: function () {
        var elementOptions = {};
        if (this.state.mode === 'bar' || this.state.mode === 'horizontalBar') {
            elementOptions.rectangle = {borderWidth: 1};
        } else if (this.state.mode === 'line') {
            elementOptions.line = {
                tension: 0,
                fill: false,
            };
        }
        return elementOptions;
    },

     /**
     * Determines to which dataset belong the data point
     *
     * @private
     * @param {Object} dataPt
     * @returns {string}
     */
    _getDatasetLabel: function (dataPt) {
        if (_.contains(['bar', 'horizontalBar', 'line'], this.state.mode)) {
            // ([origin] + second to last groupBys) or measure
            //console.log("dataPt.labels", dataPt.labels, dataPt.labels.length, typeof dataPt.labels, self.resModel, this.resModel);
            if ((dataPt.labels.length > 2) && (this.resModel == 'project.timeline.report' || this.resModel == 'project.budget.hrs.report')) {
                var datasetLabel = dataPt.labels.slice(0).join("/");
            }
            else {
                var datasetLabel = dataPt.labels.slice(1).join("/");
            }
            //var datasetLabel = dataPt.labels.slice(0).join("/");
            if (this.state.origins.length > 1) {
                datasetLabel = this.state.origins[dataPt.originIndex] +
                    (datasetLabel ? ('/' + datasetLabel) : '');
            }
            datasetLabel = datasetLabel || this.fields[this.state.measure].string;
            return datasetLabel;
        }
        return this.state.origins[dataPt.originIndex];
    },


    _filterDataPoints: function () {
        var dataPoints = [];
        if (_.contains(['bar', 'horizontalBar', 'pie'], this.state.mode)) {
            dataPoints = this.state.dataPoints.filter(function (dataPt) {
                return dataPt.count > 0;
            });
        } else if (this.state.mode === 'line') {
            var counts = 0;
            this.state.dataPoints.forEach(function (dataPt) {
                if (dataPt.labels[0] !== _t("Undefined")) {
                    dataPoints.push(dataPt);
                }
                counts += dataPt.count;
            });
            // data points with zero count might have been created on purpose
            // we only remove them if there are no data point with positive count
            if (counts === 0) {
                dataPoints = [];
            }
        }
        return dataPoints;
    },


    /**
     * Returns the options used to generate the chart legend.
     *
     * @private
     * @param {Number} datasetsCount
     * @returns {Object}
     */
    _getLegendOptions: function (datasetsCount) {
        var legendOptions = {
            display: datasetsCount <= MAX_LEGEND_LENGTH,
            // position: this.state.mode === 'pie' ? 'right' : 'top',
            position: 'top',
            onHover: this._onlegendTooltipHover.bind(this),
            onLeave: this._onLegendTootipLeave.bind(this),
        };
        var self = this;
        if (_.contains(['bar', 'horizontalBar', 'line'], this.state.mode)) {
            var referenceColor;
            if (this.state.mode === 'bar' || this.state.mode === 'horizontalBar') {
                referenceColor = 'backgroundColor';
            }
            else {
                referenceColor = 'borderColor';
            }
            legendOptions.labels = {
                generateLabels: function (chart) {
                    var data = chart.data;
                    return data.datasets.map(function (dataset, i) {
                       var r =  dataset[referenceColor];
                       if ((dataset[referenceColor] instanceof Array) && (dataset[referenceColor].length>=1)) {
                            //var res = dataset[referenceColor].filter(item => item != 'red');
                            var res = r.filter(item => item != 'red');
                            if (res.length>=1) {
                               r = res[0]
                            }
                          /*  else{
                               dataset[referenceColor] = dataset[referenceColor][0]
                            } */
                        }
                        var label_res = dataset.label;
                        //if ((self.resModel == 'project.budget.hrs.report') || (self.resModel == 'project.timeline.report')) {
                        if (self.resModel == 'project.timeline.report') {
                        var measure_value =  self.fields[self.state.measure].string.split(" ").splice(-1);
                        label_res = label_res.replace("Actual", "Actual " + measure_value).replace("Budgeted", "Budgeted " + measure_value);
                        }
                        return {
                            text: self._shortenLabel(label_res),
                            fullText: label_res,
                            fillStyle: r,
                            hidden: !chart.isDatasetVisible(i),
                            lineCap: dataset.borderCapStyle,
                            lineDash: dataset.borderDash,
                            lineDashOffset: dataset.borderDashOffset,
                            lineJoin: dataset.borderJoinStyle,
                            lineWidth: dataset.borderWidth,
                            strokeStyle: r,
                            pointStyle: dataset.pointStyle,
                            datasetIndex: i,
                        };
                    });
                },
            };
        } else {
            legendOptions.labels = {
                generateLabels: function (chart) {
                    var data = chart.data;
                    var metaData = data.datasets.map(function (dataset, index) {
                        return chart.getDatasetMeta(index).data;
                    });
                    return data.labels.map(function (label, i) {
                        var hidden = metaData.reduce(
                            function (hidden, data) {
                                if (data[i]) {
                                    hidden = hidden || data[i].hidden;
                                }
                                return hidden;
                            },
                            false
                        );
                        var fullText = self._relabelling(label);
                        var text = self._shortenLabel(fullText);
                        return {
                            text: text,
                            fullText: fullText,
                            fillStyle: label.isNoData ? '#d3d3d3' : self._getColor(i),
                            hidden: hidden,
                            index: i,
                        };
                    });
                },
            };
        }
        return legendOptions;
    },

    /**
     * Extracts the important information from a tooltipItem generated by Charts.js
     * (a tooltip item corresponds to a line (different from measure name) of a tooltip)
     *
     * @private
     * @param {Object} item
     * @param {Object} data
     * @returns {Object}
     */
    _getTooltipItemContent: function (item, data) {
        var dataset = data.datasets[item.datasetIndex];
        var label = data.labels[item.index];
        var value;
        var boxColor;
        if (this.state.mode === 'bar') {
            label = this._relabelling(label, dataset.originIndex);
            if (this.state.processedGroupBy.length > 1 || this.state.origins.length > 1) {
                if (this.resModel == 'project.timeline.report' || this.resModel == 'project.budget.hrs.report')
                  {
                  label = dataset.label;
                  }
                else{
                   label = label + "/" + dataset.label;
                }
            }
            value = this._formatValue(item.yLabel);
            boxColor = dataset.backgroundColor;
            var r =  dataset.backgroundColor;
            if ((dataset.backgroundColor instanceof Array) && (dataset.backgroundColor.length>=1)) {
                boxColor = dataset.backgroundColor[item.index]
            }
        } else if (this.state.mode === 'horizontalBar') {
         label = this._relabelling(label, dataset.originIndex);
            if (this.state.processedGroupBy.length > 1 || this.state.origins.length > 1) {
                if (this.resModel == 'project.timeline.report' || this.resModel == 'project.budget.hrs.report')
                  {
                  label = dataset.label;
                  }
                else{
                   label = label + "/" + dataset.label;
                }
            }
            value = this._formatValue(item.xLabel);
            boxColor = dataset.backgroundColor;
            if ((dataset.backgroundColor instanceof Array) && (dataset.backgroundColor.length>=1)) {
                boxColor = dataset.backgroundColor[item.index]
            }
        }
        else if (this.state.mode === 'line') {
            label = this._relabelling(label, dataset.originIndex);
            if (this.state.processedGroupBy.length > 1 || this.state.origins.length > 1) {
                label = label + "/" + dataset.label;
            }
            value = this._formatValue(item.yLabel);
            boxColor = dataset.borderColor;
        } else {
            if (label.isNoData) {
                value = this._formatValue(0);
            } else {
                value = this._formatValue(dataset.data[item.index]);
            }
            label = this._relabelling(label, dataset.originIndex);
            if (this.state.origins.length > 1) {
                label = dataset.label + "/" + label;
            }
            boxColor = dataset.backgroundColor[item.index];
        }
        return {
            label: label,
            value: value,
            boxColor: boxColor,
        };
    },
      /**
     * This function extracts the information from the data points in tooltipModel.dataPoints
     * (corresponding to datapoints over a given label determined by the mouse position)
     * that will be displayed in a custom tooltip.
     *
     * @private
     * @param {Object} tooltipModel see chartjs documentation
     * @return {Object[]}
     */
    _getTooltipItems: function (tooltipModel) {
        var self = this;
        var data = this.chart.config.data;
        var orderedItems = tooltipModel.dataPoints.sort(function (dPt1, dPt2) {
            return dPt2.yLabel - dPt1.yLabel;
        });
        return orderedItems.reduce(
            function (acc, item) {
                if (item.value > 0) {
                    acc.push(self._getTooltipItemContent(item, data));
                }
                return acc;
            },
            []
        );
    },

    _isRedirectionEnabled: function () {
        return !this.disableLinking &&
               (this.state.mode === 'bar' || this.state.mode === 'horizontalBar' || this.state.mode === 'pie');
    },

     /**
     * Determine how to relabel a label according to a given origin.
     * The idea is that the getLabel function is in general not invertible but
     * it is when restricted to the set of dataPoints coming from a same origin.

     * @private
     * @param {Array} label
     * @param {Array} originIndex
     * @returns {string}
     */
    _relabelling: function (label, originIndex) {
        if (label.isNoData) {
            return label[0];
        }
        var i = this.state.comparisonFieldIndex;
        if (_.contains(['bar', 'horizontalBar', 'line'], this.state.mode) && i === 0) {
            // here label is an array of length 1 and contains a number
            return this.dateClasses.representative(label, originIndex) || '';
        } else if (this.state.mode === 'pie' && i === 0) {
            // here label is an array of length at least one containing string or numbers
            var labelCopy = label.slice(0);
            if (originIndex !== undefined) {
                labelCopy.splice(i, 1, this.dateClasses.representative(label[i], originIndex));
            } else {
                labelCopy.splice(i, 1, this.dateClasses.dateClassMembers(label[i]));
            }
            return labelCopy.join('/');
        }
        // here label is an array containing strings or numbers.
        return label.join('/') || _t('Total');
    },

    async _renderView() {
        if (this.chart) {
            this.chart.destroy();
        }
        this.$el.empty();
        if (!_.contains(CHART_TYPES, this.state.mode)) {
            this.trigger_up('warning', {
                title: _t('Invalid mode for chart'),
                message: _t('Cannot render chart with mode : ') + this.state.mode
            });
        }
        var dataPoints = this._filterDataPoints();
        dataPoints = this._sortDataPoints(dataPoints);
        if (this.isInDOM) {
            this._renderTitle();

            // detect if some pathologies are still present after the filtering
            if (this.state.mode === 'pie') {
                const someNegative = dataPoints.some(dataPt => dataPt.value < 0);
                const somePositive = dataPoints.some(dataPt => dataPt.value > 0);
                if (someNegative && somePositive) {
                    const context = {
                        title: _t("Invalid data"),
                        description: [
                            _t("Pie chart cannot mix positive and negative numbers. "),
                            _t("Try to change your domain to only display positive results")
                        ].join("")
                    };
                    this._renderNoContentHelper(context);
                    return;
                }
            }

            if (this.state.isSample && !this.isEmbedded) {
                this._renderNoContentHelper();
            }

            // only render the graph if the widget is already in the DOM (this
            // happens typically after an update), otherwise, it will be
            // rendered when the widget will be attached to the DOM (see
            // 'on_attach_callback')
            var $canvasContainer = $('<div/>', {class: 'o_graph_canvas_container'});
            var $canvas = $('<canvas/>').attr('id', this.chartId);
            $canvasContainer.append($canvas);
            this.$el.append($canvasContainer);

            var i = this.state.comparisonFieldIndex;
            if (i === 0) {
                this.dateClasses = this._getDateClasses(dataPoints);
            }
            if (this.state.mode === 'bar') {
                this._renderBarChart(dataPoints);
            }  else if (this.state.mode === 'horizontalBar') {
                this._renderhorizontalBarChart(dataPoints);
            }
            else if (this.state.mode === 'line') {
                this._renderLineChart(dataPoints);
            } else if (this.state.mode === 'pie') {
                this._renderPieChart(dataPoints);
            }
        }
    },

    _getScaleHBarOptions: function () {
        var self = this;
        if (_.contains(['horizontalBar'], this.state.mode)) {
            return {
                xAxes: [{
                    type: 'linear',
                    scaleLabel: {
                        display: !this.isEmbedded,
                        labelString: this.fields[this.state.measure].string,
                    },
                    ticks: {
                        display: false,
                        callback: this._formatValue.bind(this),
                        suggestedMax: 0,
                        suggestedMin: 0,
                    }
                }],
                yAxes: [{
                    type: 'category',
                    scaleLabel: {
                        display: this.state.processedGroupBy.length && !this.isEmbedded,
                        labelString: this.state.processedGroupBy.length ?
                            this.fields[this.state.processedGroupBy[0].split(':')[0]].string : '',
                    },
                    ticks: {
                        // don't use bind:  callback is called with 'index' as second parameter
                        // with value labels.indexOf(label)!
                        callback: function (label) {
                            return self._relabelling(label);
                        },
                    },
                }],
            };
        }
        return {};
    },

     _animationOptions: function () {
        var animationOptions = {};
        var GraphVal = this;
        if (this.state.mode === 'bar') { // && this.resModel == 'project.budget.hrs.report'
             var animationOptions = {
                duration: "1",
                "onComplete": function() {
                var chartInstance = this.chart,
                ctx = chartInstance.ctx;
                ctx.font = Chart.helpers.fontString(12, 'bold', "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif");
                ctx.textAlign = 'center';
                ctx.textBaseline = 'bottom';
                this.data.datasets.forEach(function(dataset, i) {
                  var meta = chartInstance.controller.getDatasetMeta(i);
                  meta.data.forEach(function(bar, index) {
                    var data = dataset.data[index];
                    var value;
                    if(!!data && chartInstance.isDatasetVisible(i)){
                        value = GraphVal._formatValue(data);
                        ctx.fillText(value, bar._model.x, bar._model.y - 5);
                    }
                  });
                });
              }
               };
              }
        return animationOptions;
    },

    _animation_HBar_Options: function () {
        var animationHBarOptions = {};
        var GraphVal = this;
        if (this.state.mode === 'horizontalBar') { // && this.resModel == 'project.budget.hrs.report'
             var animationHBarOptions = {
                duration: "1",
                "onComplete": function() {
                var chartInstance = this.chart,
                 ctx = chartInstance.ctx;
                ctx.font = Chart.helpers.fontString(12, 'bold', "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif");
                ctx.textAlign = 'left';
                ctx.textBaseline = 'bottom';
                this.data.datasets.forEach(function(dataset, i) {
                  var meta = chartInstance.controller.getDatasetMeta(i);
                  meta.data.forEach(function(bar, index) {
                    var data = dataset.data[index];
                     //var barWidth = bar._model.x - bar._model.base;
                     //var centerX = bar._model.base + barWidth / 2;
                    //console.log("data", JSON.stringify(data), chartInstance.isDatasetVisible(i), !chartInstance.isDatasetVisible(i))
                    var value;
                    if(!!data && chartInstance.isDatasetVisible(i)){
                        value = GraphVal._formatValue(data);
                        //ctx.fillStyle = '#FFF';
                        ctx.fillText(value, bar._model.x, bar._model.y + 5);
                        //ctx.fillText(value, centerX, bar._model.y + 4);
                    }
                  });
                });
              }
               };
              }
        return animationHBarOptions;
    },

    _prepareOptions: function (datasetsCount) {
        const options = {
            maintainAspectRatio: false,
            scales: this._getScaleOptions(),
            legend: this._getLegendOptions(datasetsCount),
            tooltips: this._getTooltipOptions(),
            elements: this._getElementOptions(),
            animation: this._animationOptions(),
        };
        if (this._isRedirectionEnabled()) {
            options.onClick = this._onGraphClicked.bind(this);
        }
        return options;
    },

    _renderBarChart: function (dataPoints) {
        var self = this;

        // prepare data
        //console.log("datappppppppppp", dataPoints);
        var data = this._prepareData(dataPoints);

        // this.title = 'Time Line';
       if (self.resModel == 'project.budget.hrs.report') {
          var groupedData = _.groupBy(data.datasets, x => x.label.replace('Actual Hours', '').replace('Budgeted Hours', '').split("/")[0]);
        _.map(groupedData, (y) => {
          if (y.length > 1) {
        var zipped_1 = _.zip.apply(null, [y[0].data, y[1].data]);
        var maxA = zipped_1.map((a) => {
           if ((!!a[0] && !!a[1]) && a[0] > a[1]) {
             return 'red';
           } else if ((!!a[0] && !!a[1]) && a[0] < a[1]) {
                return self._getColor(0);
           }
           else {
            return self._getColor(0);
           }
          });
          y[0].backgroundColor = maxA;
          y[1].backgroundColor = self._getColor(1);
          }
        });
       }
       if (self.resModel == 'project.timeline.report') {
          var groupedData = _.groupBy(data.datasets, x => x.label.replace('Actual', '').replace('Budgeted', '').split("/")[0]);
          //var groupedData = _.groupBy(data.datasets, x => x.label.replace('Actual Hours', '').replace('Budgeted Hours', ''));
        _.map(groupedData, (y) => {
          if (y.length > 1) {
        var zipped_1 = _.zip.apply(null, [y[0].data, y[1].data]);
        var maxA = zipped_1.map((a) => {
           if ((!!a[0] && !!a[1]) && a[0] > a[1]) {
             return 'red';
           } else if ((!!a[0] && !!a[1]) && a[0] < a[1]) {
                return self._getColor(0);
           }
           else {
            return self._getColor(0);
           }
          });
          y[0].backgroundColor = maxA;
          y[1].backgroundColor = self._getColor(1);
        //var zipped_2 = _.zip.apply(null, [y[1].data, y[0].data]);
        /*var maxB = zipped_2.map((a) => {
           if ((!!a[0] && !!a[1]) && a[0] > a[1]) {
               return self._getColor(1);
           } else if ((!!a[0] && !!a[1]) && a[0] < a[1]) {
               return 'red';
           }
           else {
            return self._getColor(1);
           }
          });
          y[1].backgroundColor = maxB;*/
          }
        });
       }
       if (self.resModel == 'project.budget.amt.report') {
          var groupedData2 = _.groupBy(data.datasets, x => x.label.replace('Actual Cost', '').replace('Budgeted Revenue', ''));
        _.map(groupedData2, (y) => {
          if (y.length > 1) {
        var zipped_1 = _.zip.apply(null, [y[0].data, y[1].data]);
        var maxA = zipped_1.map((a) => {
           if ((!!a[0] && !!a[1]) && a[0] > a[1]) {
             return 'red';
           } else if ((!!a[0] && !!a[1]) && a[0] < a[1]) {
                return self._getColor(0);
           }
           else {
            return self._getColor(0);
           }
          });
          y[0].backgroundColor = maxA;
          y[1].backgroundColor = self._getColor(1);
          }
        });
       }
       if (self.resModel == 'project.consultant.hrs.report') {
          var groupedData3 = _.groupBy(data.datasets, x => x.label.replace('Actual Hours for period', '').replace('Budgeted Hours for period', ''));
        _.map(groupedData3, (y) => {
          if (y.length > 1) {
        var zipped_1 = _.zip.apply(null, [y[0].data, y[1].data]);
        var maxA = zipped_1.map((a) => {
           if ((!!a[0] && !!a[1]) && a[0] > a[1]) {
             return 'red';
           } else if ((!!a[0] && !!a[1]) && a[0] < a[1]) {
                return self._getColor(0);
           }
           else {
            return self._getColor(0);
           }
          });
          y[0].backgroundColor = maxA;
          y[1].backgroundColor = self._getColor(1);
          }
        });
       }
        data.datasets.forEach(function (dataset, index) {
            // used when stacked
            dataset.stack = self.state.stacked ? self.state.origins[dataset.originIndex] : undefined;
            // set dataset color
        /* if (self.state.stacked && dataset.label.includes("Actual")) {
             dataset.stack = 1;
         }*/
         if (self.resModel == 'project.budget.hrs.report') {
            if (dataset.label.indexOf("Actual Hours") === -1 && dataset.label.toLowerCase().indexOf("Budgeted Hours") === -1) {
            //if (dataset.label.indexOf("Actual") === -1 && dataset.label.toLowerCase().indexOf("Budgeted") === -1) {
             var color = self._getColor(index);
             dataset.backgroundColor = color;
            }
         }
         else if (self.resModel == 'project.timeline.report') {
            //if (dataset.label.indexOf("Actual Hours") === -1 && dataset.label.toLowerCase().indexOf("Budgeted Hours") === -1) {
            if (dataset.label.indexOf("Actual") === -1 && dataset.label.toLowerCase().indexOf("Budgeted") === -1) {
             var color = self._getColor(index);
             dataset.backgroundColor = color;
            }
         }
         else if (self.resModel == 'project.budget.amt.report') {
            if (dataset.label.indexOf("Actual Cost") === -1 && dataset.label.toLowerCase().indexOf("Budgeted Revenue") === -1) {
             var color = self._getColor(index);
             dataset.backgroundColor = color;
            }
         }
         else if (self.resModel == 'project.consultant.hrs.report') {
            if (dataset.label.indexOf("Actual Hours for period") === -1 && dataset.label.toLowerCase().indexOf("Budgeted Hours for period") === -1) {
             var color = self._getColor(index);
             dataset.backgroundColor = color;
            }
         }
         else {
           var color = self._getColor(index);
           dataset.backgroundColor = color;
         }
        });
        // prepare options
        var options = this._prepareOptions(data.datasets.length);
        // create chart
        var ctx = document.getElementById(this.chartId);
        this.chart = new Chart(ctx, {
            type: 'bar',
            data: data,
            options: options,
        });
    },

    _prepare_HBar_Options: function (datasetsCount) {
        const options = {
            maintainAspectRatio: false,
            scales: this._getScaleHBarOptions(),
            legend: this._getLegendOptions(datasetsCount),
            tooltips: this._getTooltipOptions(),
            elements: this._getElementOptions(),
            animation: this._animation_HBar_Options(),
        };
        if (this._isRedirectionEnabled()) {
            options.onClick = this._onGraphClicked.bind(this);
        }
        return options;
    },


    _renderhorizontalBarChart: function (dataPoints) {
        var self = this;

        // prepare data
        var data = this._prepareData(dataPoints);

        //console.log("datappppppppppp", dataPoints);

         if (self.resModel == 'project.budget.hrs.report') {
          var groupedData = _.groupBy(data.datasets, x => x.label.replace('Actual Hours', '').replace('Budgeted Hours', '').split("/")[0]);
          //var groupedData = _.groupBy(data.datasets, x => x.label.replace('Actual', '').replace('Budgeted', '').split("/")[0]);
        _.map(groupedData, (y) => {
          if (y.length > 1) {
        var zipped_1 = _.zip.apply(null, [y[0].data, y[1].data]);
        var maxA = zipped_1.map((a) => {
           if ((!!a[0] && !!a[1]) && a[0] > a[1]) {
             return 'red';
           } else if ((!!a[0] && !!a[1]) && a[0] < a[1]) {
                return self._getColor(0);
           }
           else {
            return self._getColor(0);
           }
          });
          y[0].backgroundColor = maxA;
          y[1].backgroundColor = self._getColor(1);
        //var zipped_2 = _.zip.apply(null, [y[1].data, y[0].data]);
          }
        });
       }

        if (self.resModel == 'project.timeline.report') {
          //var groupedData = _.groupBy(data.datasets, x => x.label.replace('Actual Hours', '').replace('Budgeted Hours', '').split("/")[0]);
          var groupedData = _.groupBy(data.datasets, x => x.label.replace('Actual', '').replace('Budgeted', '').split("/")[0]);
        _.map(groupedData, (y) => {
          if (y.length > 1) {
        var zipped_1 = _.zip.apply(null, [y[0].data, y[1].data]);
        var maxA = zipped_1.map((a) => {
           if ((!!a[0] && !!a[1]) && a[0] > a[1]) {
             return 'red';
           } else if ((!!a[0] && !!a[1]) && a[0] < a[1]) {
                return self._getColor(0);
           }
           else {
            return self._getColor(0);
           }
          });
          y[0].backgroundColor = maxA;
          y[1].backgroundColor = self._getColor(1);
        //var zipped_2 = _.zip.apply(null, [y[1].data, y[0].data]);
          }
        });
       }

       if (self.resModel == 'project.budget.amt.report') {
          var groupedData2 = _.groupBy(data.datasets, x => x.label.replace('Actual Cost', '').replace('Budgeted Revenue', ''));
        _.map(groupedData2, (y) => {
          if (y.length > 1) {
        var zipped_1 = _.zip.apply(null, [y[0].data, y[1].data]);
        var maxA = zipped_1.map((a) => {
           if ((!!a[0] && !!a[1]) && a[0] > a[1]) {
             return 'red';
           } else if ((!!a[0] && !!a[1]) && a[0] < a[1]) {
                return self._getColor(0);
           }
           else {
            return self._getColor(0);
           }
          });
          y[0].backgroundColor = maxA;
          y[1].backgroundColor = self._getColor(1);
          //var zipped_2 = _.zip.apply(null, [y[1].data, y[0].data]);
          }
        });
       }

       if (self.resModel == 'project.consultant.hrs.report') {
          var groupedData3 = _.groupBy(data.datasets, x => x.label.replace('Actual Hours for period', '').replace('Budgeted Hours for period', ''));
        _.map(groupedData3, (y) => {
          if (y.length > 1) {
        var zipped_1 = _.zip.apply(null, [y[0].data, y[1].data]);
        var maxA = zipped_1.map((a) => {
           if ((!!a[0] && !!a[1]) && a[0] > a[1]) {
             return 'red';
           } else if ((!!a[0] && !!a[1]) && a[0] < a[1]) {
                return self._getColor(0);
           }
           else {
            return self._getColor(0);
           }
          });
          y[0].backgroundColor = maxA;
          y[1].backgroundColor = self._getColor(1);
          }
        });
       }

        data.datasets.forEach(function (dataset, index) {
            // used when stacked
            dataset.stack = self.state.stacked ? self.state.origins[dataset.originIndex] : undefined;
            // set dataset color
        /*if (self.state.stacked && dataset.label.includes("Actual")) {
             dataset.stack = 1;
         }*/
         if (self.resModel == 'project.budget.hrs.report') {
            if (dataset.label.indexOf("Actual Hours") === -1 && dataset.label.toLowerCase().indexOf("Budgeted Hours") === -1) {
             var color = self._getColor(index);
             dataset.backgroundColor = color;
            }
         }
         else if (self.resModel == 'project.timeline.report') {
            if (dataset.label.indexOf("Actual") === -1 && dataset.label.toLowerCase().indexOf("Budgeted") === -1) {
             var color = self._getColor(index);
             dataset.backgroundColor = color;
            }
         }
        else if (self.resModel == 'project.budget.amt.report') {
            if (dataset.label.indexOf("Actual Cost") === -1 && dataset.label.toLowerCase().indexOf("Budgeted Revenue") === -1) {
             var color = self._getColor(index);
             dataset.backgroundColor = color;
            }
         }
        else if (self.resModel == 'project.consultant.hrs.report') {
            if (dataset.label.indexOf("Actual Hours for period") === -1 && dataset.label.toLowerCase().indexOf("Budgeted Hours for period") === -1) {
             var color = self._getColor(index);
             dataset.backgroundColor = color;
            }
         }
        else  {
            var color = self._getColor(index);
            dataset.backgroundColor = color;
         }
        });

        // prepare options
        var options = this._prepare_HBar_Options(data.datasets.length);
        // create chart
        var ctx = document.getElementById(this.chartId);
        this.chart = new Chart(ctx, {
            type: 'horizontalBar',
            data: data,
            options: options,
        });
    },
    /**
     * Sort datapoints according to the current order (ASC or DESC).
     *
     * Note: this should be moved to the model at some point.
     *
     * @private
     * @param {Object[]} dataPoints
     * @returns {Object[]} sorted dataPoints if orderby set on state
     */
    _sortDataPoints(dataPoints) {
        if (!Object.keys(this.state.timeRanges).length && this.state.orderBy &&
            ['bar', 'horizontalBar', 'line'].includes(this.state.mode) && this.state.groupBy.length) {
            // group data by their x-axis value, and then sort datapoints
            // based on the sum of values by group in ascending/descending order
            const groupByFieldName = this.state.groupBy[0].split(':')[0];
            const groupedByMany2One = this.fields[groupByFieldName].type === 'many2one';
            const groupedDataPoints = {};
            dataPoints.forEach(function (dataPoint) {
                const key = groupedByMany2One ? dataPoint.resId : dataPoint.labels[0];
                groupedDataPoints[key] = groupedDataPoints[key] || [];
                groupedDataPoints[key].push(dataPoint);
            });
            dataPoints = _.sortBy(groupedDataPoints, function (group) {
                return group.reduce((sum, dataPoint) => sum + dataPoint.value, 0);
            });
            dataPoints = dataPoints.flat();
            if (this.state.orderBy === 'desc') {
                dataPoints = dataPoints.reverse('value');
            }
        }
        return dataPoints;
    },


    });
});
