/*global define */
define(['jquery', 'underscore', 'backbone'],
    function($, _, Backbone) {
    'use strict';

    /**
     * @class Metrics
     * @classdesc A single result from the DataONE Metrics Service
     * @classcategory Models
     * @extends Backbone.Model
     * @constructor
     */
    var Metrics = Backbone.Model.extend(
      /** @lends Metrics.prototype */{

        /**
        * The name of this Model
        * @type {string}
        */
        type: "Metrics",

        defaults: {
            metricRequest: null,
            startDate: null,
            endDate: null,
            results: null,
            resultDetails: null,
            pid_list: null,
            url: null,
            filterType: null,

            // metrics and metric Facets returned as response from the user
            // datatype: array
            citations: null,
            views: null,
            downloads: null,
            months: null,
            country: null,
            years: null,
            repository: null,
            award: null,
            datasets: null,


            // Total counts for metrics
            totalCitations: null,
            totalViews: null,
            totalDownloads: null,

            // flag to send POST request to the metrics service
            useMetricsPost: false,

            // colelctionQuery for Portal Objects
            filterQueryObject: null,
            forwardCollectionQuery: false,

            metricsRequiredFields: {
                metricName: true,
                pid_list: true
            }

        },

        metricRequest: {
            "metricsPage": {
                "total": 0,
                "start": 0,
                "count": 0
            },
            "metrics": [
                "citations",
                "downloads",
                "views"
            ],
            "filterBy": [
                {
                    "filterType": "",
                    "values": [],
                    "interpretAs": "list"
                },
                {
                    "filterType": "month",
                    "values": [],
                    "interpretAs": "range"
                }
            ],
            "groupBy": [
                "month"
            ]
        },

        /**
        * Initializing the Model objects pid and the metricName variables.
        * @param {object} options
        */
        initialize: function(options) {
            if((options) && options.pid_list !== 'undefined') {
                this.set("pid_list", options.pid_list);
                this.set("filterType", options.type);
            }
            this.set("startDate", "01/01/2012");

            // overwrite forwardCollectionQuery flag
            this.set("forwardCollectionQuery", MetacatUI.appModel.get("metricsForwardCollectionQuery"));

            // url for the model that is used to for the fetch() call
            this.url = MetacatUI.appModel.get("metricsUrl");
        },

        /**
        * Overriding the Model's fetch function.
        */
        fetch: function(){
          var fetchOptions = {};
          this.metricRequest.filterBy[0].filterType = this.get("filterType");
          this.metricRequest.filterBy[0].values = this.get("pid_list");

          // TODO: Set the startDate and endDate based on the datePublished and current date
          // respctively.
          this.metricRequest.filterBy[1].values = [];
          this.metricRequest.filterBy[1].values.push(this.get("startDate"));
          this.metricRequest.filterBy[1].values.push(this.getCurrentDate());

          // set custom request settings if we're forwarding a CollectionQuery for a portal
          if ( this.get("forwardCollectionQuery") && this.get("filterType") === "portal"
                                        &&  this.get("filterQueryObject") != undefined
                                        && typeof this.get("filterQueryObject") === "object") {
            var filterQueryObject = this.get("filterQueryObject");
            if (filterQueryObject.filterType != undefined
                                        && filterQueryObject.filterType == "query") {
                if (Array.isArray(filterQueryObject.values)
                                        && filterQueryObject.values.length > 0 ) {

                    // check if query object exists
                    var queryInserted = this.metricRequest.filterBy.indexOf(filterQueryObject);

                    // Performing HTTP POST?
                    if(this.get("useMetricsPost")) {
                        // insert query object
                        if (queryInserted < 0) {
                            this.metricRequest.filterBy.push(filterQueryObject);
                        }

                        fetchOptions = _.extend({
                            data:JSON.stringify(this.metricRequest),
                            type:"POST",
                            timeout:300000
                        });
                    }
                    else {
                        // insert query object
                        var collectionQuery = filterQueryObject.values[0];
                        if (collectionQuery.length < 1000 && queryInserted < 0) {
                            this.metricRequest.filterBy.push(filterQueryObject);
                        }

                        // set the fetch options for
                        var model = this;
                        fetchOptions = _.extend({
                            data:"metricsRequest="+JSON.stringify(this.metricRequest),
                            timeout:300000,
                            // on error recursively call fetch, but this time use POST
                            error: function(response){
                                model.set("useMetricsPost", "true");
                                model.fetch();
                            }
                        });
                    }
                }
            }
          }

          // check if we need to set fetchOptions
          if (Object.keys(fetchOptions).length === 0) {
            if ( this.get("useMetricsPost") ) {
                fetchOptions = _.extend({
                    data:JSON.stringify(this.metricRequest),
                    type:"POST",
                    timeout:300000
                });
            }
            else {
                fetchOptions = _.extend({
                    data:"metricsRequest="+JSON.stringify(this.metricRequest),
                    timeout:300000,
                });
            }
          }

          //This calls the Backbone fetch() function but with our custom fetch options.
          return Backbone.Model.prototype.fetch.call(this, fetchOptions);
        },

        /**
        * Get's a string version of today's date
        * @return {string}
        */
        getCurrentDate: function() {
            var today = new Date();
            var dd = today.getDate();
            var mm = today.getMonth()+1; //January is 0!

            var yyyy = today.getFullYear();
            if(dd<10){
                dd='0'+dd;
            }
            if(mm<10){
                mm='0'+mm;
            }
            var today = mm+'/'+dd+'/'+yyyy;
            return today;
        },

        /**
        * Parsing the response for setting the Model's member variables.
        */
        parse: function(response){
            var metricsObject = {
                "metricRequest": response.metricsRequest,
                "citations": response.results.citations,
                "views": response.results.views,
                "downloads": response.results.downloads,
                "months": response.results.months,
                "country": response.results.country,
                "resultDetails": response.resultDetails,
                "datasets": response.results.datasets
            }

            if (response.results.citations != null) {
                metricsObject["totalCitations"] =  response.results.citations.reduce(function(acc, val) { return acc + val; }, 0)
            }
            else {
                metricsObject["totalCitations"] =  0
            }

            if (response.results.downloads != null) {
                metricsObject["totalDownloads"] =  response.results.downloads.reduce(function(acc, val) { return acc + val; }, 0)
            }
            else {
                metricsObject["totalDownloads"] =  0
            }

            if (response.results.views != null) {
                metricsObject["totalViews"] =  response.results.views.reduce(function(acc, val) { return acc + val; }, 0)
            }
            else {
                metricsObject["totalViews"] =  0
            }

            //trim off the leading zeros and their corresponding months
            if (response.results.months != null) {

                // iterate all the metrics objects and remove the entry if the counts are 0
                for (var i = 0 ; i < metricsObject["months"].length; i++) {

                    if ( metricsObject["citations"] != null &&
                        metricsObject["views"]     != null &&
                        metricsObject["downloads"] != null ) {

                        if (( metricsObject["citations"][i] == 0 ) &&
                            ( metricsObject["views"][i]     == 0 ) &&
                            ( metricsObject["downloads"][i] == 0 )) {

                            metricsObject["months"].splice(i,1);
                            metricsObject["citations"].splice(i,1);
                            metricsObject["views"].splice(i,1);
                            metricsObject["downloads"].splice(i,1);

                            // if country facet was part of the request; update object;
                            if ( metricsObject["country"] != null) {
                                metricsObject["country"].splice(i,1)
                            }

                            // modified array size; decrement the counter;
                            i--;
                        }
                        else {
                            break;
                        }
                    }
                }
            }

            return metricsObject;
        },

    });
    return Metrics;
});
