;(function( $, _ , moment, window, document, undefined ){

    var DashboardStats = function(options){
        this.options = options;
    };

    DashboardStats.prototype = {

        defaults: {
            // Moment.js locale
            locale: 'fr',
            // Datepicker initialization variables
            startDate: moment().subtract(29, 'days'),
            endDate: moment(),
            momentExchangeFormat: 'YYYY/MM/DD',
            datePickerValueFormat: 'D MMMM YYYY',
            datePickerOptions: {
                startDate: moment().subtract(29, 'days'),
                endDate: moment(),
                format: 'MM/DD/YYYY',
                showDropdowns: true,
                showWeekNumbers: true,
                timePicker: false,
                timePickerIncrement: 1,
                timePicker12Hour: true,
                opens: 'left',
                ranges: {
                    'Aujourd\'hui': [moment(), moment()],
                    'Hier': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
                    '7 derniers jours': [moment().subtract(6, 'days'), moment()],
                    '30 derniers jours': [moment().subtract(29, 'days'), moment()],
                    'Ce mois-ci': [moment().startOf('month'), moment().endOf('month')],
                    'Le mois dernier': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
                },
                opens: 'left',
                buttonClasses: ['btn', 'btn-sm'],
                applyClass: 'btn-primary',
                cancelClass: 'btn-default',
                separator: ' to ',
                locale: {
                    applyLabel: 'Appliquer',
                    cancelLabel: 'Annuler',
                    fromLabel: 'De',
                    toLabel: 'à',
                    customRangeLabel: 'Personnalisé',
                    daysOfWeek: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve','Sa'],
                    monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
                    firstDay: 1
                }
            },
            // Charts.js initialization variables
            datasetOptions: {
                fillColor : "rgba(19,129,176,0.4)",
                strokeColor : "#1381B0",
                pointColor : "#fff",
                pointStrokeColor : "#1381B0)"
            },
            chartOptions: {
                responsive: true,
                showXLabels: 10,
                pointHitDetectionRadius : 0,
                tooltipFillColor: "#1381B0",
                tooltipCornerRadius: 0
            },
            // Datatable.js initialization variables
            tableOptions: {
                searching: false,
                aLengthMenu: [[5, 10, 25, -1], [5, 10, 25, "All"]],
                iDisplayLength: 5,
                destroy: true
            }
        },

        init: function() {
            // Underscore template "Mustache style"
            _.templateSettings = {
                interpolate: /\{\{(.+?)\}\}/g
            };

            this.config = $.extend( {}, this.defaults, this.options );

            // moment locale
            moment.locale(this.config.locale);

            // DatePicker element
            this.$datePicker = $('#reportrange').daterangepicker(this.config.datePickerOptions);
            // Chart underscore template
            this._chartTemplate = _.template($('#graph-template').html(), { variable: 'chart' });
            // Date filter displayed value underscore template
            this._dateTemplate = _.template($('#date-template').html());
            // Trainer select element
            this.$trainingSelect = $('#training-select');
            // Displayed date filter element
            this.$dateRangeReport = $('#reportrange span');
            // Ajax spinner element
            this.$spinner = $('.spinner');
            // Charts container object
            this.charts = {};

            var self = this;

            // Listen on datepicker / trainingSelect events
            this.$datePicker.on('hide.daterangepicker', function(ev, picker){
                self.render();
            });
            this.$trainingSelect.on('change', function(){
                self.render();
            });

            // Listen on tab change
            $('a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
                self.render();
            });

            return this;
        },

        fetch: function() {

            // Filters values
            var startDate = this.$datePicker.data('daterangepicker').startDate,
                endDate = this.$datePicker.data('daterangepicker').endDate,
                deferred = $.Deferred()
            ;

            // Url parameters
            var params = {
                dateStart: startDate.format(this.config.momentExchangeFormat),
                dateEnd: endDate.format(this.config.momentExchangeFormat),
            };

            if (!_.isEmpty(this.$trainingSelect.val())) {
                params.trainingId = this.$trainingSelect.val();
            }

            // Fetching the data
            $.get(this.config.dataUrl, params, function(data){
                deferred.resolve(data);
            });

            return deferred;
        },

        render: function(chartId) {

            var self = this,
                startDate = this.$datePicker.data('daterangepicker').startDate,
                endDate = this.$datePicker.data('daterangepicker').endDate
            ;

            // Update the datepicker displayed value
            var dateReportHtml = this._dateTemplate({
                startDate: startDate.format(self.config.datePickerValueFormat),
                endDate: endDate.format(self.config.datePickerValueFormat)
            });
            this.$dateRangeReport.html(dateReportHtml);

            // Get the data
            this.$spinner.show();
            this.fetch().then(function(data) {

                self.data = data.stats;

                // Render all the tables and graphs, according to the provided options
                _.each(self.config.charts['graphType'], self.renderGraph, self);
                _.each(self.config.charts['tableType'], self.renderTable, self);

                self.$spinner.hide();
            }).fail(function() {

                // Something went wrong while fetching
                // Display an error somewhere ?
                console.log('Error during the fetch');
                self.$spinner.hide();
            });
        },

        renderGraph: function(statOptions, statName) {

            // If we got no data to show, don't show the graph
            // TODO: Maybe display an error somewhere ?
            if (_.isUndefined(this.data[statName])) {
                return;
            }

            // Re-organize data for charts.js
            var statData = this.data[statName],
                graphTitle = statData['title'],
                graphData = statData['graph'],
                chartLabels = _.pluck(graphData, 'date'),
                chartData = _.pluck(graphData, 'nb_event')
            ;

            // If we already got a graph rendered, just update the data
            // TODO: Make it work :(
            // Currently, the update() method on a charts.js instance with changed data dont work...
            // Maybe in a future version ?
            // if (!_.isUndefined(this.charts[statName])) {
            //     var chart = this.charts[statName];
            //     chart.labels = chartLabels;
            //     chart.datasets[0].data = chartData;
            //     chart.update();
            //     return;
            // }

            // Render the charts template
            var chartHtml = this._chartTemplate({
                title: graphTitle + ' ' + statOptions.title,
                // subtitle: statOptions.subtitle,
                icon: statOptions.icon
            });
            $chartContainer = $('#chart-'+statName).html(chartHtml);

            // Finally, charts.js rendering
            $chartElem = $chartContainer.find('canvas');

            if ($chartElem.size() > 0) {
                var ctx = $chartElem.get(0).getContext("2d");
                this.charts[statName] = new Chart(ctx).Line(
                    {
                        labels: chartLabels,
                        datasets: [
                            $.extend({ data: chartData }, this.config.datasetOptions)
                        ]
                    },
                    this.config.chartOptions
                );
            } else {
                console.log('Oops, no element to receive the chart "' + statName + '" ')
            }
        },

        renderTable: function(statOptions, statName){

            // If we got no data to show, dont show the graph
            // TODO: Maybe display an error somewhere ?
            if (_.isUndefined(this.data[statName])) {
                return;
            }

            var $tableContainer = $('#table-'+statName),
                // Format the data with the formatters if they exist in the config
                statData = _.map(this.data[statName], function(value){
                    formattedData = {};
                    _.each(value, function(value, key){
                        if (!_.isUndefined(statOptions.format) && !_.isUndefined(statOptions.format[key])) {
                            formattedData[key] = statOptions.format[key](value).toString();
                        } else {
                            formattedData[key] = value;
                        }
                    });
                    return formattedData;
                })
            ;

            this.charts[statName] = $tableContainer.dataTable(
                $.extend({
                        data: statData,
                        columns: _.map(statOptions.columns, function(value){ return { data: value }})
                    },
                    this.config.tableOptions 
                )
            );
        }
    };

    DashboardStats.defaults = DashboardStats.prototype.defaults;
    window.DashboardStats = DashboardStats;

})( jQuery, _, moment, window, document );
