(function()
{
    var TasksPermissionChecker = require('./tasks.permission_checker.class.js');

    var template = require('../../html/project/tasks_board.directive.html');
	var moduleName = 'claromentis.project';

	angular.module(moduleName)
        .directive('clangProjectTasksBoard', projectTasksBoard);

    projectTasksBoard.$inject = ['tasksService'];
    function projectTasksBoard(service) {
        return {
            restrict: 'E',
            templateUrl: template,
            scope: {
                tasks: '<',
                statuses: '<',
                lists: '<',
                groupByList: '<',
                perms: '<',
                isMobile: '<'
            },
            controllerAs: 'ctrl',
            bindToController: true,
            controller: controller,
            link: link
        };

        function controller()
        {
            var ctrl = this;

            ctrl.tasksService = service;
            ctrl.todoStatus = null;
            ctrl.orderableStatuses = [];
            ctrl.doneStatus = null;

            this.$onInit = function() {
                ctrl.buildStatuses();
                ctrl.permsChecker = new TasksPermissionChecker(ctrl.perms);
            };

            ctrl.HasTaskDragPerms = function(task, listId) {
                if (ctrl.isMobile)
                    return false;

                return ctrl.permsChecker.HasTaskDragPerms(task, listId);
            };

            ctrl.HasListDragPerms = function() {
                if (ctrl.isMobile)
                    return false;

                return ctrl.permsChecker.HasListDragPerms();
            };

            ctrl.HasStatusDragPerms = function() {
                if (ctrl.isMobile)
                    return false;

                return ctrl.permsChecker.HasStatusDragPerms();
            };

            ctrl.IsMyTask = function(task) {
                return ctrl.permsChecker.IsMyTask(task);
            }

            ctrl.CanEditMyOwnTask = function(task) {
                return ctrl.permsChecker.CanEditMyOwnTask(task);
            }

            ctrl.CanUpdateMyTaskStatus = function(task, listId) {
                return ctrl.permsChecker.CanUpdateMyTaskStatus(task, listId);
            }

            ctrl.buildStatuses = function()
            {
                var taskCounts = {};
                for (var listIndex = 0; listIndex < ctrl.tasks.lists.length; listIndex++)
                {
                    if (ctrl.tasks.lists[listIndex].statuses !== undefined)
                    {
                        var list = ctrl.tasks.lists[listIndex];
                        for (var statusIndex = 0; statusIndex < list.statuses.length; statusIndex++)
                        {
                            var status = list.statuses[statusIndex];

                            if (taskCounts[status.status.id] === undefined)
                                taskCounts[status.status.id] = 0;

                            taskCounts[status.status.id] += status.tasks.length;
                        }
                    }
                }

                ctrl.todoStatus = ctrl.statuses[0];
                ctrl.todoStatus.isNew = false;
                ctrl.orderableStatuses.length = 0;
                for (var i = 1; i < ctrl.statuses.length - 1; i++)
                {
                    ctrl.statuses[i].taskCount = taskCounts[ctrl.statuses[i].id];
                    ctrl.orderableStatuses.push(ctrl.statuses[i]);
                }

                ctrl.doneStatus = ctrl.statuses[ctrl.statuses.length - 1];
                ctrl.doneStatus.isNew = false;
            }

            /**
             * Called while dragging to determine where items can be dropped. Because we have both task and section containers we find
             * the types involved and limit items to only be dropped in a container of their own kind. If this is not done we can drop
             * tasks as a section and vice versa.
             */
            ctrl.dragAccept = function (sourceItemHandleScope, destSortableScope)
            {
                var sourceType = '';
                if ('task' in sourceItemHandleScope.itemScope.$parent)
                    sourceType = 'Task';
                else if ('list' in sourceItemHandleScope.itemScope.$parent)
                    sourceType = 'Section';
                else if ('status' in sourceItemHandleScope.itemScope.$parent)
                    sourceType = 'Status';

                var destType = destSortableScope.options.dropType;

                if (sourceType === destType)
                {
                    if ((sourceType === 'Section') &&
                        (!ctrl.perms.can_edit_any_task))
                    {
                        return false;
                    }

                    if (sourceType === 'Task')
                    {
                        if (ctrl.perms.can_edit_any_task)
                            return true;

                        var task = sourceItemHandleScope.itemScope.$parent.task;

                        if (ctrl.CanEditMyOwnTask(task))
                            return true;

                        if (ctrl.CanUpdateMyTaskStatus(task, destSortableScope.element.data('list-id')))
                            return true;

                        // Can only drag in the circumstances above
                        return false;
                    }

                    // Other combos are fine
                    return true;
                }

                // Can't drag between types at all
                return false;
            };

            ctrl.statusOrderChanged = function(data)
            {
                service.updateStatusOrder(data.source.itemScope.$parent.status.id, ctrl.statuses[data.dest.index + 1].sort_order);
            };

            ctrl.sectionOrderChanged = function(data)
            {
                service.updateListOrder(data.source.itemScope.$parent.list.list.id, data.dest.index);
            };


            ctrl.taskOrderChanged = function(data)
            {
                var destStatus = data.dest.sortableScope.$parent.$parent.ctrl.status;
                var destList = data.dest.sortableScope.$parent.$parent.ctrl.list;

                var taskId = parseInt(destStatus.tasks[data.dest.index].id);

                var newOrder = [];
                for (var taskIndex = 0; taskIndex < destStatus.tasks.length; taskIndex++)
                {
                    newOrder.push(parseInt(destStatus.tasks[taskIndex].id));
                }

                var newData = {
                    statusId: parseInt(destStatus.status.id),
                    order: newOrder
                };

                if (destList !== undefined)
                    newData.listId = parseInt(destList.list.id);

                service.updateTaskOrder(taskId, newData);
            };

            ctrl.dragStatusListeners =
            {
                dropType: 'Status',
                accept: ctrl.dragAccept,
                orderChanged: ctrl.statusOrderChanged,
                containment: ".js-drag-container",
                containerPositioning: 'relative'
            };

            ctrl.dragSectionListeners =
            {
                dropType: 'Section',
                accept: ctrl.dragAccept,
                orderChanged: ctrl.sectionOrderChanged,
                containment: ".js-drag-container",
                containerPositioning: 'relative'
            };

            ctrl.dragTaskListeners =
            {
                dropType: 'Task',
                accept: ctrl.dragAccept,
                itemMoved: ctrl.taskOrderChanged,
                orderChanged: ctrl.taskOrderChanged,
                containment: '.js-drag-container',
                containerPositioning: 'relative'
            };
        }

        function link($scope, $element, $attrs, $ctrl)
        {
            // Rebuild the statuses headers due to change of data
            $scope.$watch('ctrl.statuses', function(newVal, oldVal){
                $ctrl.buildStatuses();
            }, true);

            $scope.$watch('ctrl.tasks', function(newVal, oldVal){
                $ctrl.buildStatuses();
            }, true);
        }
    }
}());
