(function($) {

/*******************************************************************************
 *
 * CloudFlare Chart Template Prototypes
 *
 ******************************************************************************/
    
    $.chartTemplates = {
        
        baseChart: function(){}
                
    };

/***
 * Basic Chart
 ***/

    $.chartTemplates.baseChart.prototype = {
        
        chart: {
            renderTo: null,
            defaultSeriesType: 'column',
            margin: [50, 50, 60, 80],
            events: {}
        },
        
        credits: {
            enabled: false
        },
        
        // TODO: Pick a better series of CloudFlare-friendly colors...
        colors: [
            '#fcd318',
            '#90d218',
            '#ff7e00',
            '#F6358A',
            '#5CB3FF',
            '#5E767E',
            '#F87431',
            '#F9966B',
            '#FAF8CC',
            '#34282C',
            '#4C7D7E',
            '#151B8D',
            '#8D38C9',
            '#7D053F',
            '#893BFF',
            '#00FFFF',
            '#348017',
            '#64E986',
            '#FFFF00',
            '#C9BE62',
            '#7E2217',
            '#7F462C'
        ],
        
        plotOptions: {
            
        },
        
        subtitle: {
            text: "Subtitle Undefined"
            //style: null
        },
        
        title: {
            text: "Untitled Chart"
            //style: null
        }
        
    };

/*******************************************************************************
 *
 * CloudFlare Chart Plot Prototypes
 *
 ******************************************************************************/

    $.chartPlots = {
        
        basicPlot: function() {},
        barPlot: function() {},
        linePlot: function() {},
        piePlot: function() {}
        
    };

/***
 * Basic Plot
 ***/

    $.chartPlots.basicPlot.prototype = {
        
        // TODO
        
    };

/***
 * Bar Plot
 ***/
 
    $.chartPlots.barPlot.prototype = $.extend(
        new $.chartPlots.basicPlot(),
        {
            // TODO
        }
    );

/***
 * Line Plot
 ***/
 
    $.chartPlots.linePlot.prototype = $.extend(
        new $.chartPlots.basicPlot(),
        {
            // TODO
        }
    );

/***
 * Pie Plot
 ***/

    $.chartPlots.piePlot.prototype = $.extend(
        new $.chartPlots.basicPlot(),
        {
            // TODO
        }
    );

/*******************************************************************************
 *
 * CloudFlare Chart Axes Prototypes
 *
 ******************************************************************************/
    
    $.chartAxes = {
        
        baseAxis: function() {},
        dateAxis: function() {},
        pieAxis: function() {}
        
    };

/***
 * Base Axis
 ***/

    $.chartAxes.baseAxis.prototype = {
        type: "linear",
        //min: null,
        //max: null,
        title: {
            //align: "middle",
            //enabled: false,
            //margin: 35,
            //rotation: 0,
            //style: null,
            //text: "Untitled Axis"
        },
        //lineWidth: 1,
        minPadding: 0,
        maxPadding: 0,
        //maxZoom: 1,
        offset: 0,
        //opposite: false,
        reversed: false,
        //startOfWeek: 1,
        startOnTick: false,
        //gridLineColor: "#C0C0C0",
        //gridLineWidth: 0,
        endOnTick: true
        //minorGridLineColor: "#E0E0E0",
        //minorGridLineWidth: 1,
        //tickColor: "#C0D0E0",
        //tickInterval: "auto",
        //tickLength: 5,
        //tickmarkPlacement: "between",
        //tickPixelInterval: null,
        //tickPosition: "outside",
        //tickWidth: 1,
        //minorTickColor: "#A0A0A0",
        //minorTickInterval: null,
        //minorTickLength: 2,
        //minorTickPosition: "outside",
        //minorTickWidth: 1,
    };
    
/***
* Date Axis
***/
    $.chartAxes.dateAxis.prototype = $.extend(
        new $.chartAxes.baseAxis(),
        {
            startOnTick: true,
            dateTimeLabelFormats: {
                //second: '%H:%M:%S',
                //minute: '%H:%M',
                //hour: '%H:%M',
                //day: '%e. %b',
                //week: '%e. %b',
                //month: '%b %y',
                //year: '%Y'
            }
        }
    );

/***
* Pie Axis
***/

    $.chartAxes.pieAxis.prototype = $.extend(
        new $.chartAxes.baseAxis(),
        {
            
        }
    );

    
/*******************************************************************************
 *
 * CloudFlare Chart Data Formatting Functions
 *
 * Data format expected:
 *
 *  {
 *      // Super properties...
 *      timeZero: $NUMBER,
 *      format: $STRING,
 *      data: [
 *          // Data series..
 *          {
 *              name: $STRING,
 *              interval: $NUMBER,
 *              data: [ $NUMBER ]
 *          }
 *      ]
 *  }
 * 
 * Aggregate spits out:
 *
 *  [
 *      {
 *          type: $STRING,
 *          data: [
 *              {
 *                  name: $STRING,
 *                  y: $NUMBER
 *              }
 *          ]
 *      }
 *  ]
 *
 * Note: Aggregate will always return an array of length 1! Series data is
 * condensed into the result[n].data[] array.
 *
 * Series spits out:
 * 
 *  [
 *      {
 *          type: $STRING,
 *          name: $STRING,
 *          data: [
 *              [
 *                  $X, $Y
 *              ]
 *          ]
 *      }
 *  ]
 * 
 ******************************************************************************/
 
    $.chartFormat = {
        
        aggregate: function(unformatted) {
            
            var formatted = [
                {
                    type: unformatted.format,
                    data: []
                }
            ];
            
            for(var i = 0; i < unformatted.objs.length; i++) {
                
                formatted[0].data.push(
                    {
                        name: unformatted.objs[i].name,
                        y: (function(data) {
                            
                            var sum = 0;
                            
                            for(var j = 0; j < data.length; j++) {
                                
                                sum += data[j];
                                
                            }
                            
                            return sum;
                            
                        })(unformatted.objs[i].data)
                    }
                );
                
            }
            
            //console.log('Dumping aggregate formatted: ');
            //console.dir(formatted);
            
            return formatted;
            
        },
        
        series: function(unformatted) {
            
            var formatted = [];
            
            for(var i = 0; i < unformatted.objs.length; i++) {
                
                formatted.push(
                    {
                        
                        type: unformatted.format,
                        name: unformatted.objs[i].name,
                        data: (function(data) {
                            
                            var series = [];
                            
                            for(var j = 0; j < data.length; j++) {
                                series.push(
                                    [
                                        (unformatted.timeZero + unformatted.objs[i].interval * j) * 1000,
                                        data[j]
                                    ]
                                );
                                
                            }
                            
                            return series;
                            
                        })(unformatted.objs[i].data)
                        
                    }
                );
                
                
            }
            
            return formatted;
            
        }
        
    };
    
    
/*******************************************************************************
 *
 * CloudFlare UI Chart Widget
 *
 ******************************************************************************/

    $.widget('ui.chart', {
        
        options: {
            
            title: "CloudFlare Data",
            subTitle: "",
            template: $.chartTemplates.baseChart,
            width: 400,
            height: 200,
            xAxisType: "datetime",
            xAxisTitle: "Date",
            yAxisType: "linear",
            yAxisTitle: "Value",
            remote: true,
            data: [
                {
                    url: "http://sandbox.local/webservice/dummy.php",
                    format: "column"
                }
            ]
            
        },
        
        _internalSettings: {
            
            selfClasses: 'cf-ui chart',
            innerStub: '<div></div>'
            
        },
        
        _create: function() {
            
            var self = this;
            
            if((self.element.is('div') || self.element.is('li'))) {
                
                //console.log("Instantiating the chart!");
                
                self.chartContainer = $(self._internalSettings.innerStub);
                self.chartContainer.attr('id', self.element.attr('id') + "-chart");
                
                self.remoteRequests = 0;
                
                self.element.append(self.chartContainer);
                self.element.addClass(self._internalSettings.cssClasses);
                
                self.refresh();
                
            } else {
                
                // Incompatible element type...
                
            }
            
        },
        
        _setOption: function(key, value) {
            
            // TODO: This method needs some work...
            var self = this;
            
            $.Widget.prototype._setOption.apply(self, arguments);
            
            self.refresh();
            
        },
                
        _formatTemplate: function() {
            
            var self = this;
            
            self.template = new self.options.template();
            
            // Set width & height...
            self.template.chart.width = self.options.width;
            self.template.chart.height = self.options.height;
            
            // Set render container & titles...
            self.template.chart.renderTo = self.chartContainer.attr('id');
            self.template.title.text = self.options.title;
            self.template.subtitle.text = self.options.subTitle;
            
            // Assign the data...
            if(self.options.remote) {
                
                self.template.chart.events.load = function() {
                    
                    for(var i = 0; i < self.options.data.length; i++) {
                        
                        self.addRemoteSeries(self.options.data[i]);
                        
                    }
                    
                };
                
            } else {
                
                self.template.series = self.options.data;
                
            }
            
            // Select the appropriate plot options...
            //self.template.plotOptions.pie = new $.chartPlots.piePlot();
            
            // Build the appropriate axes...
            
            self.template.xAxis = new $.chartAxes.baseAxis();
            self.template.xAxis.type = self.options.xAxisType;
            self.template.xAxis.title.text = self.options.xAxisTitle;
            self.template.yAxis = new $.chartAxes.baseAxis();
            self.template.yAxis.type = self.options.yAxisType;
            self.template.yAxis.title.text = self.options.yAxisTitle;
            
        },
        
        _buildChart: function() {
            
            var self = this;
            
            self._destroyChart();
            
            self._formatTemplate();
                
            self.chart = new Highcharts.Chart(self.template);
            
            $(self.chart.container).hide().fadeIn(400);
            
        },
        
        _destroyChart: function() {
            
            var self = this;
            
            if(self.chart) {
                
                self.chart.destroy();
                
            }
            
            if(self.chartContainer) {
                
                self.chartContainer.empty();
                
            }
            
        },
        
        removeSeries: function(name, refresh) {
            
            var self = this;
            
            refresh = refresh != null ? refresh : true;
            
            for(var i = 0; i < self.chart.series.length; i++) {
                
                if(self.chart.series[i].name == name) {
                    
                    self.chart.series[i].remove(refresh);
                    
                }
                
            }
            
        },
        
        // Note: addSeries expects 'unformatted' to be structured as described
        // above in "CloudFlare Chart Data Formatting Functions"
        addSeries: function(unformatted, format, refresh) {
            
            //console.log("Add " + format + " series called, with unformatted: " + unformatted);
            
            var self = this;
            var formatted;
            
            refresh = refresh != null ? refresh : true;
            
            unformatted.result.format = format;
            formatted = format == "pie" ? $.chartFormat.aggregate(unformatted.result) : $.chartFormat.series(unformatted.result);
            formatted.name = self.options.title;
            
            for(var i = 0; i < formatted.length; i++) {
                
                self.chart.addSeries(formatted[i], false);
                
            }
            
            if(refresh) {
                
                self.refresh();
                
            }
        },
        
        addRemoteSeries: function(seriesRequest) {
            
            var self = this;
            
            self.remoteRequests++;
            
            // TODO: Show loader while loading remote data...
            $.ajax(
                {
                    url: seriesRequest.url,
                    dataType: "application/json",
                    complete: function() {
                        
                        self.remoteRequests--;
                        // TODO: Hide loader when remoteRequests == 0...
                        
                    },
                    error: function() {
                        
                        //console.log("CloudFlare UI Chart - AJAX Error!");
                        
                    },
                    success: function(unformatted, status, xhr) {
                        
                        self.addSeries($.secureEvalJSON(unformatted), seriesRequest.format);
                        
                    }
                }
            );
            
        },
        
        refresh: function() {
            
            var self = this;
            
            //console.log("Refresh called!");
            
            if(self.chart == null) {
                
                //console.log("No chart exists! Building...");
                
                self._buildChart();
                
            } else {
                
                //console.log("Chart exists! Redrawing...");
                
                self.chart.redraw();
                
            }
            
        },
        
        destroy: function() {
            
            self._destroyChart();
            
            self.chartContainer.remove();
            
            self.element.removeClass(self._internalSettings.selfClasses);
            
        }
        
    });

})(jQuery);