(function()
{
    var Url = require('url-parse');

    var moduleName = 'cla.project_list';

    // Manual singleton as the .service() appears to return multiple instances across Angular apps
    var instance = new ProjectListService();

    angular.module(moduleName)
        .service('claProjectListService', ['$http', '$q', '$timeout', '$anchorScroll', function($http, $q, $timeout, $anchorScroll)
        {
            instance.setHttp($http);
            instance.setQ($q);
            instance.setTimeout($timeout);
            instance.setAnchorScroll($anchorScroll);
            return instance;
        }]);

    function ProjectListService()
    {
        var service = this;
        service.$http = null;
        service.$q = null;
        service.$timeout = null;
        service.$anchorScroll = null;
        service.apiUrl = '/api/projects/';

        service.callbacks = [];

        // global variables from the project list template - projects/html/index.html
        service.sortOrder = sort;
        service.currentPage = current_page;
        service.searchTerms = searchTerms;
        service.totalCount = project_count;
        service.projectsPerPage = projects_per_page;
        service.projects = projects;
        service.filters = project_filters;
        service.currentFilter = current_filter;

        /**
         * Promise that is used to cancel the previous page fetching request
         * When it is resolved, the request is cancelled.
         * @type {Deferred}
         */
        service.page_fetch_canceler = null;

        /**
         * Handle to timout used to debounce typing in the search bar
         * @type {Promise}
         */
        service.search_debouncer = null;

        service.setHttp = function($http)
        {
            service.$http = $http;
        }

        service.setQ = function($q)
        {
            service.$q = $q;
            service.page_fetch_canceler = service.$q.defer();
        }

        service.setTimeout = function($timeout)
        {
            service.$timeout = $timeout;
            service.search_debouncer = service.$timeout();
            service.showProgressBars();
        }

        service.setAnchorScroll = function($anchorScroll)
        {
            service.$anchorScroll = $anchorScroll;
            // when we scroll to elements, we want to take the height of the navbar into account
            $anchorScroll.yOffset = angular.element('.claro-navbar');
        }

        service.registerCallback = function(callback) {
            service.callbacks.push(callback);
        }

        service.getProjects = function() {
            return service.projects;
        }

        service.setFilter = function(type) {
            service.currentFilter = type;
            service.currentPage = 1;
            service.getResultsPage(1);
        };

        service.getFilters = function() {
            return service.filters;
        }

        service.changeSortOrder = function(orderby) {
            service.sortOrder = orderby;
            service.getResultsPage(service.currentPage);
        };

        service.toggleBookmark = function(project_id, bookmark)
        {
            var url = '/api/projects/' + project_id + '/bookmark';

            if (bookmark == 0)
            {
                service.$http.put(url).then(function(){
                    service.getResultsPage(service.currentPage, false);
                });
            } else
            {
                service.$http.delete(url).then(function(){
                    service.getResultsPage(service.currentPage, false);
                });
            }
        };

        service.pageChanged = function(newPage) {
            service.getResultsPage(newPage);
        };

        service.search = function(searchTerms)
        {
            service.searchTerms = searchTerms;
            service.getResultsPage(service.currentPage);
        };

        service.getResultsPage = function(pageNumber, no_history)
        {
            var withHistory = true;

            if ((typeof no_history === 'boolean') &&
                (no_history))
            {
                withHistory = false;
            }

            var url = new Url('/projects/', {}, true);
            var query_params = {
                filter: service.currentFilter,
                page: pageNumber,
                sort: service.sortOrder
            };

            if (service.searchTerms.length > 0)
                query_params.search = service.searchTerms;

            if (service.companyId > 0)
                query_params.company_id = service.companyId;

            url.set('query', query_params);
            var history_url = history ? url.href : null;
            // add json parameter for REST request only
            query_params.format = 'json';

            // cancel previous timeout
            service.$timeout.cancel(service.search_debouncer);
            // cancel the actual AJAX request
            service.page_fetch_canceler.resolve();

            service.search_debouncer = service.$timeout(function() {
                service.fetchPage(url.pathname, history_url, query_params)
            }, 500)
        }

        service.fetchPage = function (url, history_url, query_params) {
            // cancel previous request to fetch a page
            service.page_fetch_canceler.resolve();
            service.page_fetch_canceler = service.$q.defer();

            service.$http.get(url, {
                params: query_params,
                timeout: service.page_fetch_canceler.promise
            }).then(function(result) {
                service.projects.length = 0;
                angular.extend(service.projects, result.data.projects);

                // Update pagination var in case it needs to show/hide
                service.totalCount = result.data.project_count;

                service.filters.length = 0;
                angular.extend(service.filters, result.data.filter_count);

                service.showProgressBars();

                // Company detail page has no history so don't attempt to set it
                if (history_url)
                    window.history.pushState({}, '', history_url);

                service.$anchorScroll("js-just-before-projects-list")

                for (var i = 0; i < service.callbacks.length; i++)
                {
                    service.callbacks[i]();
                }
            }, function(response) {
                //do nothing when request is cancelled, but have a callback here to prevent angularjs complaining
                if (response.xhrStatus !== "abort") {
                    console.error({
                        message: "Project list page fetch failed",
                        response: response
                    });
                }
            });
        }

        service.showProgressBars = function()
        {
            // Make IE show the right sized progress bars
            for (var i = 0; i < service.projects.length; i++)
            {
                service.$timeout(function(id, progress)
                {
                    angular.element('#progress-bar-' + id).css('width', progress + '%');
                }, 0, true, service.projects[i].id, service.projects[i].progress);
            }
        };

        /**
         * Delete project
         *
         * @param {number} project_id
         */
        service.deleteProject = function (project_id)
        {
            var url = '/api/projects/' + project_id;

            service.$http.delete(url).then(function(result)
            {
                if (result.data.result)
                    window.location.href = '/projects?message=' + encodeURIComponent(lmsg('projects.js.project.project_deleted'));
                else
                    cla.showMessage(lmsg('common.general.error') + ': ' + result.data.message, '', true);
            });
        }
    }
}());
