/*jslint node: true */
/*jslint browser: true*/
/*jslint nomen: true*/
/*global angular, BaseController, CFE_mapping, defaultSQL, alert, $, common*/

'use strict';

var changesController = BaseController.extend({
    /**
     * Initialize  Controller
     * @param $scope, current controller scope
     * @param $location
     * @param reportService
     * @param paginationService
     * @param commonHelper
     * @param notificationService
     */

    init: function($scope, $q, $location, $routeParams, $http, $filter, reportService, paginationService, commonHelper, notificationService, modalWindowService, wizardSharedService) {
        var self = this;
        this._super($scope);
        this._reportService = reportService;
        this._paginationService = paginationService;
        this._notificationService = notificationService;
        this._commonHelper = commonHelper;
        this._modalWindowService = modalWindowService;
        this._wizardSharedService = wizardSharedService;


        self.goToTopIcon = $('.go-to-top');
        self.goToTopIcon.click(function() {
            $("html, body").animate({
                scrollTop: 0
            }, 600);
            return false;
        });
        self.goToBottomIcon = $('.go-to-bottom');
        self.goToBottomIcon.click(function() {
            $("html, body").animate({
                scrollTop: $('#wrapper').height()
            }, 600);
            return false;
        });

        $(window).on('scroll', function()
        {
            if ($(this).scrollTop() <= 100) {
                 self.goToBottomIcon.hide();
                 self.goToTopIcon.hide();
             } else if ($(this).scrollTop() <= 180) {
                self.goToTopIcon.hide();
                self.goToBottomIcon.show();
            } else {
                self.goToTopIcon.show();
                self.goToBottomIcon.show();
            }

            if (($(this).scrollTop()+100) >= $('#wrapper').height()-$(window).height()) {
                self.goToBottomIcon.hide();
            }
        });


        self.$scope.filters = [];
        self.$scope.sorting = '-changetime'; // default ordering by latest to top of report

        this.$scope.paginator = paginationService;
        this.$location = $location;
        this.$http = $http;
        this.$routeParams = $routeParams;
        this.$filter = $filter;

        this.$scope.modalWindow = modalWindowService;

        self.$scope.notifications = {};
        self.$scope.showEnvironmentFilterButtons = true;

        self.$scope.selectedCols = [];
        // see changes_data_addons
        self.$scope.changesColumns = changesColumns;

        self.$scope.reportRoles = {};

        self.$scope.roles = this._commonHelper.getRolesArray();
        self.$scope.is_admin = self._commonHelper.checkifAdmin(self.$scope.roles);

        self.$scope.savedSearchName = {};
        self.$scope.savedSearchCategory = {};
        self.$scope.savedSearchCategory.input = 'changes';
        self.$scope.reportCategory = self.$scope.savedSearchCategory.input;

        self.$scope.is_public = {};

        self.$scope.isChanges = true;

        self.$scope.reportId = '';
        self.$scope.reportLabel = '';

        self.$scope.is_own = 1;
        self.$scope.can_edit = 1;
        self.$scope.can_delete = 1;
        self.$scope.readonly = 0;
        self.$scope.is_public.input = 0;
        self.$scope.show_buttons = 1;

        self.$scope.alertData   = {};
        self.$scope.hostcontexts = {};
        self.$scope.excludedHosts = '';
        self.$scope.hostselectionstate = {};

        self.$scope.initializing = true;

        self._initVIEWParams();

        self.$scope.todayDate = new Date();
        self.$scope.todaysDateStart = self._returnDate(0, true);
        self.$scope.minDate = self._returnDate(29);
        self.$scope.weekDate = self._returnDate(6);
        self.$scope.yesterDate = self._returnDate(1);

        self.$scope.myDateRange = {
            startDate: self.$scope.todaysDateStart,
            endDate: self.$scope.todayDate,
            dateLimit: {days:1},
            maxDate: self.$scope.todayDate
        };

        self.$scope.SQL = {};
        // only for means of saving: will stay empty
        self.$scope.SQL.hostcontexts = '';
        self.$scope.SQL.hostcontextsprofileid = '';
        self.$scope.SQL.hostcontextspath = '';

        self.$scope.dateOpts = {
            ranges: {
                'Today': [self.$scope.todayDate,self.$scope.todayDate],
                'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
                'Last 7 Days': [moment().subtract(6, 'days'), moment()]
            },
            applyClass: 'btn-primary',
            separator: ' to ',
            buttonClasses: ['pull-right', 'btn']
        };

        //Watch for date changes & communicate with directive to show on screen
        self.$scope.$watch('myDateRange', function(oldDate, newDate) {
            if (!self.$scope.initializing) { self._runQuery();}
            if (oldDate !== newDate) {
                self.$scope.$broadcast('changeTmpEvent', self.$scope.myDateRange);
            }
        }, true);

        self.$scope.$watch('selectedCols', function(newCols) {
            if (!angular.equals([], newCols)) {
                const sessionStorageChanges = JSON.parse(sessionStorage.getItem('changes_report'));
                sessionStorage.setItem('changes_report',JSON.stringify({...sessionStorageChanges, columns: newCols}));
            }
        }, true);

        self._resetChart();
    },

    defineScope: function (){
        this.$scope.instance            = "changesController";
        this.$scope.getTime             = this.getTime.bind(this);
        //this.$scope.scheduleReport      = this.scheduleReport.bind(this);
        this.$scope.saveReport          = this.saveReport.bind(this);
        this.$scope.copyReport          = this.copyReport.bind(this);
        this.$scope.sortReorder         = this.sortReorder.bind(this);
        this.$scope.setChartData        = this.setChartData.bind(this);
        this.$scope.exportChart         = this.exportChart.bind(this);
        this.$scope.colSelected         = this.colSelected.bind(this);
        this.$scope.setDownloadData     = this.setDownloadData.bind(this);
    },

    defineListeners: function () {
        var self = this;

        self.$scope.$on("hostContextApply_Event", function(event, hostContextObj) {
            // because for the changes context filter combined with field filter we do the following:
            // 1. get hostcontext
            // 2. broadcast event to recalculate filter

            self.$scope.SQL.hostcontexts = angular.copy(hostContextObj.hostcontexts);
            self.$scope.SQL.hostcontextsprofileid = angular.copy(hostContextObj.hostcontextsprofileid);
            self.$scope.SQL.hostcontextspath = angular.copy(hostContextObj.hostcontextspath);
            self.$scope.hostcontexts = self.$scope.SQL.hostcontexts;
            self.$scope.alertData.hostContexts = self.$scope.SQL.hostcontexts;

            self._wizardSharedService.reportPropertiesChanged(self._commonHelper.getReportData(self.$scope));
            self.$scope.$broadcast('environmentFilter_EVENT');
        });

        self.$scope.$on('environmentExcludeChanged_Event', function(event, excludedHosts) {
            if (Object.keys(excludedHosts).length)
            {
                self.$scope.alertData.excludedHosts = {name: Object.values(excludedHosts).join(', '), excludes: Object.keys(excludedHosts)};
                self.$scope.SQL.excludedHosts = {name: Object.values(excludedHosts).join(', '), excludes: Object.keys(excludedHosts)};
                self.$scope.excludedHosts = {name: Object.values(excludedHosts).join(', '), excludes: Object.keys(excludedHosts)};
            }
            else {
                self.$scope.alertData.excludedHosts = '';
                self.$scope.excludedHosts = '';
                self.$scope.SQL.excludedHosts = '';
            }
        });

         self.$scope.$on('changesDirectiveReady_EVENT', function(event) {
            self._loadReport_or_RunDefault();
        });

        self.$scope.$on("runQuery_EVENT", function(event) {
            self._runQuery();
        });

        self.$scope.$on('clearFilters_EVENT', function () {
            self.$scope.$broadcast('clearAll_EVENT');
        });

        self.$scope.$on('paginatorChange', function() {
            self._runQuery();
        });
    },

    saveReport: function (isOverwrite){
        var self = this;
        self.$scope.SQL.columns = self.$scope.selectedCols;
        self._commonHelper.saveReport(isOverwrite, self.$scope, 'changes-result');
    },

    copyReport: function(isOverwrite) {
        var self = this;
        var $scope = self.$scope;
        self._commonHelper.copyReport(self.$scope.reportId, self.$scope.savedSearchName.input, $scope, isOverwrite, 'changes-result');
    },

    /*scheduleReport: function () {
        var self = this;
        self._wizardSharedService.scopeStateChanged(self.$scope.SQL);
        self._wizardSharedService.reportPropertiesChanged(self._commonHelper.getReportData(self.$scope));
        var url = '/report/schedule';
        if (self.$scope.reportId !== undefined && self.$scope.reportId !== '')
        {
            url = url + '/' + self.$scope.reportId;
        }
        self.$location.path(url);
    },*/

    sortReorder: function (columnName, e) {
        var self = this;

         angular.forEach(self.$scope.selectedCols, function(el) {
            if (el.name === columnName) {
                el.sort = el.sort > 0 ? -1 : 1;
                if (el.sort>0) {
                    self.$scope.sorting = columnName;
                } else {
                    self.$scope.sorting = "-"+columnName;
                }
            } else {
                el.sort = null;
            }
        });
        self._runQuery();
    },

    _initVIEWParams: function() {
        var self = this;

    },

    _returnDate: function(days, startOfDay) {
        var self = this,
            date = new Date(new Date().setDate(self.$scope.todayDate.getDate()-days));

        if(startOfDay === true){
            date.setHours(0,0,0,0);
        }

        return date;
    },


    _loadReport_or_RunDefault: function () {
        var self = this;
        const sessionStorageChanges = JSON.parse(sessionStorage.getItem('changes_report'));
        // if date range set in params:
        if (self.$routeParams.from && self.$routeParams.to) {
            self.$scope.myDateRange = {
                startDate: new Date(Number(self.$routeParams.from)),
                endDate: (self.$scope.myDateRange.endDate < new Date(Number(self.$routeParams.to))) ?
                    self.$scope.myDateRange.endDate :
                    new Date(Number(self.$routeParams.to))
            }
        }

        // load a saved report or run default

        if (self.$routeParams.reportid) {

            // load report from ID
            self._loadReport(self.$routeParams.reportid);
        }
        else if (sessionStorageChanges && sessionStorageChanges.reportData) {
            // load report from saved session data (i.e if reload/refresh)

            var sessionData = sessionStorageChanges.reportData;

            self.$scope.filters = sessionData.filters;
            self.$scope.hostselectionstate = sessionStorageChanges.hasOwnProperty('hostcontexts') ? { hostContexts: sessionStorageChanges.hostcontexts } : {};
            if (sessionStorageChanges.columns && sessionStorageChanges.columns.length) {
                self.$scope.selectedCols = sessionStorageChanges.columns;
            } else {
                self.$scope.selectedCols = self._getColumns(selectDefaultChangesColumns);
            }
            self._runQuery();
        }
        else {
            // load default report
            self.$scope.is_own = 1;
            self.$scope.can_edit = 1;
            self.$scope.selectedCols = self._getColumns(selectDefaultChangesColumns);

            // set default date range
            //self.$scope.myDateRange.startDate = moment(self._returnDate(7));
            self._runQuery();

            //self.$scope.$broadcast('runDefaultReport_EVENT', self.$scope.selectDefaultColumns);
        }

        self._wizardSharedService.reportPropertiesChanged(self._commonHelper.getReportData(self.$scope));
    },

    _loadReport: function (reportid) {
        var self = this;
        var $scope = self.$scope;
        self._reportService.loadReport(reportid).then(
            function (result) {
                var data = result.data;
                var formData = angular.fromJson(data['AdvancedReportsData']);

                if (formData.SQL !== undefined)
                {
                    $scope.SQL = angular.fromJson(formData.SQL);
                    $scope.selectedCols = $scope.SQL.columns;
                    $scope.filters = $scope.SQL.filters;
                    self._wizardSharedService.scopeStateChanged(self.$scope.SQL);
                }
                if (formData.noResultsSuccess === true){
                    $scope.customNoRowsMessage = ' There are no failures / results.'
                    $scope.notificationType = 'good';
                }

                $scope.reportLabel = data.label;
                $scope.reportId = reportid;
                $scope.savedSearchName.input = data.label;

                $scope.can_edit = data.can_edit;
                $scope.can_delete = data.can_delete;
                $scope.is_own = data.is_own;
                $scope.readonly = data.readonly;
                $scope.is_public = {};
                $scope.is_public.input = Boolean(data.is_public);
                $scope.loadedSearch = true;
                $scope.reportRolesTMP = (data.sharedPermission !== undefined ? angular.fromJson(data.sharedPermission) : {});

                angular.forEach($scope.reportRolesTMP, function(key, value) {
                    $scope.reportRoles[key] = true;
                });

                self._wizardSharedService.reportPropertiesChanged(self._commonHelper.getReportData(self.$scope));
                self.$scope.$broadcast('changesReportLoaded_EVENT', self.$scope.SQL);
            },
            function (error) {
                var reportError = self._notificationService.createObjectForNotification('error', 500, 'Unable to load report');
                self._notificationService.setNotification(reportError.type, reportError.data);
            }
        );
    },

    _runQuery: function (type) {
        var self = this;
        var data = {};
        self._notificationService.resetNotification();
        data.filters = self.$scope.filters;
        // save host contexts in case we want to get them from saved reports in the future
        //data.hostcontexts = self.$scope.hostcontexts || {};

        data.from = Math.floor(moment.utc(self.$scope.myDateRange.startDate).valueOf()/1000);
        data.to = Math.floor(moment.utc(self.$scope.myDateRange.endDate).valueOf()/1000);

        angular.copy(data, self.$scope.SQL);

        data.sort = self.$scope.sorting;

        // only use last entry in host contexts dropdown, as it is most narrow: eg linux->ubuntu, use 'ubuntu'
        data.includes = self.$scope.hostcontexts.includes != undefined && self.$scope.hostcontexts.includes.length > 0 ? self.$scope.hostcontexts.includes : '';;
        data.excludes = self.$scope.excludedHosts.excludes != undefined ? self.$scope.excludedHosts.excludes : '';
        data.cleanFilters = self._cleanFilters(self.$scope.filters);

        if (type==='chart' || type==='download') {
           data.count = self.$scope.totalCount;
           data.page = 1;
        } else {
            data.count = self.$scope.paginator.rowsPerPage;
            data.page = self.$scope.paginator.page;
        }
        const changesStorage =  {reportData: data, dateRange: self.$scope.myDateRange, hostcontexts: self.$scope.hostcontexts}
        if (!angular.equals([],self.$scope.selectedCols)) {
            changesStorage.columns = self.$scope.selectedCols
        }
        sessionStorage.setItem('changes_report', JSON.stringify(changesStorage))

        return self._reportService.runChangesQuery(data).then(
            function (result) {
                if (type==='chart') {
                    self.$scope.chartresult = result.data.data;
                    return result.data.data;
                } else if (type==='download') {
                    return result.data.data;
                } else {
                    self.$scope.totalCount = result.data.total;
                    self.$scope.result = result.data.data;
                    self.$scope.paginator.refreshPaginator(result.data.total);
                    self.$scope.display = true;
                    self.$scope.initializing = false;
                    self.$scope.originalFilters = angular.copy(self.$scope.filters);
                }

                if (!self.$scope.result.length) {
                    var error = self._notificationService.createObjectForNotification('warning', 505, 'Query returned 0 rows');
                    self._notificationService.setNotification(error.type, error.data);
                }
            },
            function (error) {
                console.log(error);
            }
        );
    },

    _convertToCSVArray: function (data) {
        var self = this;
        self.$scope.csvArray = [];
        var headers = [];
        angular.forEach(self.$scope.selectedCols, function (col, key) {
            headers.push(col.label);
        });
        self.$scope.csvArray.push(headers);

        angular.forEach(data, function (row, key) {
            var entry = [];
            angular.forEach(self.$scope.selectedCols, function (header, key1) {
                entry.push(htmlSpecialCharsDecode(row[header.name]));
            });
            self.$scope.csvArray.push(entry);
        });
    },

    _cleanFilters: function (filters) {
        var self = this;
        var filterString = "";
        angular.forEach(filters, function (filter, key) {
            // check if has value
            if (filter.value !== undefined) {
                var val = encodeURIComponent(filter.value);
                if (filter.condition === 'ILIKE') {
                    val += '%';
                }
                if (key>0) {filterString += "&"};
                filterString += filter.attribute_name +"="+val;
            } else {
                // if no value, remove from array
                filters.splice(key,1);
            }
        });
        return filterString;
    },

    _getColumns: function (cols) {
        var self = this;
        var selectedCols = [];
        angular.forEach(cols, function(column, key) {
            var col1 = self.$filter('filter')(changesColumns, function (c) {return c.name == column})[0];
            selectedCols.push(col1);
        });

        return selectedCols;
    },

    getTime: function (timestamp) {
        var self = this;
        return common.time.format(timestamp*1000);
    },

    setDownloadData: function () {
        var self = this;
        self._runQuery('download').then(
            function (result) {
                // convert to CSV suitable
                self._convertToCSVArray(result);
            },
            function (error) {

            }
        );
    },

    setChartData: function (title, idx) {
        var self = this;
        //run query without pagination limit
        self._runQuery('chart').then(
            function(result) {
                self.$scope.modalWindow.open('showChartPopup', self.$scope);

                if (!title && !idx && self.$scope.currentChart) {
                    title = self.$scope.currentChart.title;
                    idx = self.$scope.currentChart.index;
                } else {
                    // save current chart details for updating on filter change
                    self.$scope.currentChart = {title: title, index: idx};
                }

                if (title && idx!=='0') {
                    self.$scope.showChart = true;
                    var array = [];

                    angular.forEach(self.$scope.chartresult, function(res) {
                        var datapoint;
                        if (title==='changetime') {
                            self.$scope.chartConfig.changetime = true;
                            datapoint = moment.unix(res[title]);
                            datapoint = moment(datapoint).format('dddd MMMM DD YYYY');
                            self.$scope.chartConfig.options.chart.type = 'column';
                            array.unshift(datapoint);
                        } else {
                            self.$scope.chartConfig.changetime = false;
                            datapoint = res[title];
                            array.push(datapoint);
                        }
                    });

                    self.$scope.chartConfig.title.text = self.$scope.selectedCols[idx].label;
                    self.$scope.chartConfig.xAxis.title.text = self.$scope.selectedCols[idx].label;
                    self.$scope.chartConfig.series[0] = {
                        name: title,
                        data: self._convertArray(array)
                    };

                } else {
                    self.$scope.showChart = false;
                }
            },
            function(error) {
                // todo error handle for no data
            });
    },

    exportChart: function (type){
        var self = this;
        var charts1 = $('#chart1').highcharts(); // not ideal way to get highcharts object
        switch (type) {
            case 'print':
                charts1.print();
                break;
            case 'img':
                charts1.exportChart({type: "image/png"});
                break;
        }
    },

    _resetChart: function () {
        var self = this;
        self.$scope.chartConfig = {
            options: {
                chart: {
                    type: 'pie',
                    backgroundColor: 'transparent',
                    height: '360'
                },
                exporting: {
                    enabled: false
                },
                plotOptions: {
                     column: {
                        allowPointSelect: true,
                        cursor: 'pointer'
                    },
                    pie: {
                        allowPointSelect: true,
                        cursor: 'pointer',
                        dataLabels: {
                            enabled: true,
                            format: '<b>{point.name}</b>: {y}'
                        }
                    }
                },
                tooltip: {
                    formatter: function() {
                        if (this.percentage) {
                            return '<b>' + this.point.name + '</b><br/>Changes: ' + this.y + '<br/>' + this.percentage.toFixed(1) +'%';
                        } else {
                            return '<b>' + this.point.name + '</b><br/>Changes: ' + this.y;
                        }
                    }
                },
                legend: {
                    enabled: false
                }
            },
            series: [{
                    data: []
                }],
            title: {
                text: ''
            },
            subtitle: {
                text: 'by # changes'
            },
            xAxis: {
                categories: [],
                title: {
                    text: null
                },
                allowDecimals:false
            },
            yAxis: {
                allowDecimals:false,
                min: 0,
                title: {
                    text: '# changes'
                }
            },
            credits: {
                enabled:false
            },
            loading: false,
            changetime: false
        };
    },

    _convertArray: function(arr) {
        var self = this;
        var obj = {};
        for (var i = 0, j = arr.length; i < j; i++) {
            if (obj[arr[i]]) {
                obj[arr[i]]++;
            }
            else {
                obj[arr[i]] = 1;
            }
        }
        var array = [];
        var axis = [];
        angular.forEach(obj, function(key, value) {
            array.push([value, key]);
            axis.push(value);
        });

        self.$scope.chartConfig.xAxis.categories = axis;
        return array;
    },


    /*
     * Check if column name is in selectedCols list
     */
    colSelected: function(col) {
        var self = this;
        var found = true;
        angular.forEach(self.$scope.selectedCols, function (column, key) {
            if (column.name === col.name) {
                found = false;
            }
        });
        return found;
    },

});



    changesController.$inject = [ '$scope',
                                    '$q',
                                    '$location',
                                    '$routeParams',
                                    '$http',
                                    '$filter',
                                    'reportService',
                                    'paginationService',
                                    'commonHelper',
                                    'notificationService',
                                    'modalWindowService',
                                    'wizardSharedService'
                                   ];