({
    plugins: ['Dashlet', 'Tooltip'],

    events: {
    },

    // Current dashboardId
    dashboardId: null,

    // Endpoint URL's
    getDashboardsEndpoint: 'AnalyticReporting/GetDashboards',
    getDashboardEndpoint: 'AnalyticReporting/GetDashboard?dashboardId=',
    getDashboardWidgetsEndpoint: 'AnalyticReporting/GetDashboardWidgets?dashboardId=',
    getDashboardWidgetEndpoint: 'AnalyticReporting/GetDashboardWidget?reportId=',
    getReportResultEndpoint: 'AnalyticReporting/GetReportResult?record=', // TODO: Change record to reportId
    saveDashboardEndpoint: 'AnalyticReporting/SaveDashboard',
    savePermissionsEndpoint: 'AnalyticReporting/SavePermissions',
    saveScheduleEndpoint: 'AnalyticReporting/SaveSchedule',

    store: null,

    /**
     * Initialize the View
     *
     * @constructor
     * @param {Object} options
     */
    initialize: function(options) {
        // Callbacks should access this, so bind this to all methods
        _.bindAll(this, "renderDasbhoard");
        // _.bindAll.apply(_, [this].concat(_.functions(this)));
        this.isManager = app.user.get('is_manager');
        this._super('initialize', [options]);
    },

    /**
     * Init dashlet settings
     */
    initDashlet: function() {
        // Validation handling for individual fields on the config
        this.layout.before('dashletconfig:save', function() {
            // Fields on the metadata
            var fields = _.flatten(this.dashletConfig.config.fields);

            // Grab all non-valid fields from the model
            var notValid = _.filter(fields, function(field) {
                return field.required && !this.dashModel.get(field.name);
            }, this);

            // If there no invalid fields we are good to go
            if (notValid.length === 0) {
                return true;
            }

            // Otherwise handle notification of invalidation
            _.each(notValid, function(field) {
                var fieldOnView = _.find(this.fields, function(comp, cid) {
                    return comp.name === field.name;
                });

                fieldOnView.model.trigger('error:validation:' + field.name, {required: true});
            }, this);

            // False return tells the drawer that it shouldn't close
            return false;
        }, this);
    },
    /**
     * Special case for dashboardId field rendering
     * TODO: In future this should be moved in config
     */
    _renderField: function(field, $fieldEl) {
        var self = this;

        // TODO: Must find better "Sugar" way for this solution
        // Special case for choosing dashboards
        if(field.name === "dashboardId") {
            App.progress.start();
            app.api.call('GET', app.api.buildURL(this.getDashboardsEndpoint), null, {
                success: function (data) {
                    if (this.disposed) {
                        App.progress.cancel();
                        return;
                    }

                    // Set report options as select options
                    App.progress.done();

                    var normalised = {};
                    data.map(function(item) {
                        normalised[item.id] = item.title;
                    });

                    field.items = normalised;
                    self._super("_renderField", [field, $fieldEl]);
                },
            });
        } else {
            // Render other fields
            self._super("_renderField", [field, $fieldEl]);
        }
    },

    /**
     * @inheritdoc
     */
    bindDataChange: function() {
        var self = this;
        if (!this.meta.config) {
            // Load app initial state and render dashboard when changing dashboardId by select bar
            this.settings.on('change:dashboardId', function(model) {
                self.loadAppInitialState(null, model.get('dashboardId'), self.renderDasbhoard);
            });
        }
    },

    /**
     * Load app initial state from API endpoint
     */
    loadData: function(options) {
        if (this.disposed || this.meta.config) {
            return;
        }

        // Load data and render chart when completed
        this.loadAppInitialState(
            options,
            this.settings.get('dashboardId'),
            this.renderDasbhoard
        );
    },


    /**
     * Load dashboard initial state from endpoint and run callback when completed
     */
    loadAppInitialState: function(options, dashboardId, callback) {
        var self = this;

        if(!dashboardId) {
            console.log("dashboardId is undefined", dashboardId, options)
        }

        App.progress.start();
        app.api.call('GET', app.api.buildURL(this.getDashboardEndpoint + dashboardId), null, {
            /**
             * On successfully retrieved data event
             */
            success: function (data) {
                if (this.disposed) {
                    App.progress.cancel();
                    return;
                }

                App.progress.done();

                // Replace module URLs with Sugar REST URLs and add OAuth token
                data.config.urls.loadReport = app.api.buildURL(self.getReportResultEndpoint);
                data.config.urls.fetchDashboardWidgetsUrl = app.api.buildURL(self.getDashboardWidgetsEndpoint);
                data.config.urls.fetchWidgetDataUrl = app.api.buildURL(self.getDashboardWidgetEndpoint);
                data.config.urls.saveDashboardUrl = app.api.buildURL(self.saveDashboardEndpoint);
                data.config.urls.savePermissionsUrl = app.api.buildURL(self.savePermissionsEndpoint);
                data.config.urls.saveScheduleUrl = app.api.buildURL(self.saveScheduleEndpoint);
                data.config.oauth = {
                    name: 'OAuth-Token',
                    value: app.api.getOAuthToken()
                }

                callback(data);
            },
            error: function (data) {
                if (this.disposed) {
                    App.progress.cancel();
                    return;
                }

                App.progress.done();
                self.renderErrorMessage(dashboardId, data.message);
            },
            complete: options ? options.complete : null,
        });
    },

    /**
     * Generic method to render dashboard with check for visibility and data.
     * Called by _renderHtml and loadData.
     */
    renderDasbhoard: function(appInitialState) {
        // Set dashboard title
        this.layout.setTitle(appInitialState.dashboard.title);

        // Set current dashboardId
        this.dashboardId = appInitialState.dashboard.id;

        if (!this.meta.config) {
            // Wrap title with link to dashboard
            var title = this.layout.$('h4.dashlet-title').text();
            var url = this.dashletConfig.config.openDashboardUrl + this.dashboardId;

            var chartTitle = '<a href="'+ url +'" target="_blank">' + title + '</a>';
            // this.layout.setTitle(chartTitle);
            this.layout.$el.find("h4").first().html(chartTitle);
        }

        $el = this.$el.find(".ar-dashboard:first");

        /**
         * If store is not defined, then dashboard is not rendered
         * and we should render it.
         *
         * If store is defined, then update dashboard
         */
        if(this.store) {
            // At now this does nothing
            console.log("Dashboard should be refreshed.");
        } else {
            // Render chart first time
            this._renderDashboard($el, appInitialState);
        }
    },

    /**
     * Render dashboard on element with appInitialState
     * @param $el
     * @param appInitialState
     * @private
     */
    _renderDashboard: function($el, appInitialState) {
        if(!window.ARDashboardApp) {
            console.log("window.ARDashboardApp is not defined.");
            return;
        }

        try {
            this.store = window.ARDashboardApp($el.prop("id"), appInitialState);
        } catch (e) {
            console.log("ARDashboardApp initialization error", e, appInitialState, $el.prop("id"))
        }
    },

    /**
     * Render error message in dashboard DIV container with link to dashboard.
     * Called by loadAppInitialState.
     */
    renderErrorMessage: function(dashboardId, errorMessage) {
        var url = this.dashletConfig.config.openDasbhoardUrl + dashboardId;
        try {
            $el = this.$el.find(".ar-dashboard:first");
            var a = $("<a />")
                .attr('href', url)
                .text(errorMessage);
            var div = $("<div />")
                .css({
                    height: "100%",
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center"
                });
            a.appendTo(div.appendTo($el));
        } catch(e) {
            console.log("Couldn't render error message for dashboardId: " + dashboardId);
        }
    },
})