(function () {
    'use strict';
    angular.module('api.module.Components')

        /**
         * @class api.module.Components.directives.EloUserSelection
         * @transclusion
         * @ngDirective
         * @xtype elo-user-selection
         * 
         * This directive provides a user selection component. Depending on 
         * its configuration a set of chosen users can be selected from a set
         * of given choices.
         * 
         * For every selected user a data object will be created, that can be
         * altered in order to configure any data for a selected user.
         * 
         * # Example:
         * 
         *     <elo-user-selection config="store.config" chosen-users="store.users" chosen-data="store.data" selected-index="store.index">
         *     ...
         *     </elo-user-selection>
         *     
         * Here all selected users will appear in the chosen-users array of 
         * de.elo.ix.client.UserInfo objects (i.e. store.users will hold this array).
         * The array chosen-data will always have the same length as chosen-users (i.e. store.data).
         * The users are bound by index to their according data object.
         * The index of the selected user in the list will be selected-index
         * (i.e. store.index).
         * 
         * # Transclusion:
         * This directive uses transclusion. Inside it their can be a form that
         * will fill the data object of the selected user (in the example 
         * above store.data[store.index] as ngModel).
         * 
         * @cfg {Object} config 
         * The config object of the user selection. It can hold:
         * 
         * @cfg {String} config.label
         * A string message that is displayed above the user selection.
         * 
         * @cfg {String} config.placeholder
         * A string message that is displayed in the empty user selection.
         * 
         * @cfg {Array} config.sourceUsers
         * An array of de.elo.ix.client.UserName objects that are the users that can be selected.
         * 
         * @cfg {Number} config.type
         * The type of users that can be selected (see: api.ix.ListUtils.listUsers),
         * one of USERTYPE_USER, USERTYPE_GROUP, USERTYPE_BOTH.
         * Please chose carefull the use of *_INCL_INVISIBLE constants here.
         * 
         * @cfg {Boolean} config.isDynamic
         * True to use a dynamic search to retrieve the users in the list.
         * If this is set a optional FindUserInfo object can be given
         * in config.findUserInfo to modify the search. Only the name of
         * the FindUserInfo object will be overwritten by the input of the field.
         * This option produces more communication requests to the 
         * server and should be used if the number of possible users is very large (>1000).
         * With this option the config.type constant will still be evaluated to filter invisible users.
         * 
         * @cfg {Object} config.findUserInfo
         * A de.elo.ix.client.FindUserInfo object to use for the dynamic
         * search. It will be ignored, if config.isDynamic is not set to true.
         * If the onlyGroups and onlyUsers properties in this object
         * conflict with the config.type constant it is possible, that 
         * to many or to view users will be present.
         * 
         * @cfg {Boolean} config.singleSelect
         * True to only select one user.
         * 
         * @cfg {Object} config.defaultData
         * An object that should hold the initial data for a new selected user.
         * A clone of that object will be added to chosenData if a new user is added to chosenUsers.
         * 
         * @cfg {Boolean} config.ordered
         * True to add move capabilities. This is needed if the order of 
         * selected users is relevant.
         * 
         * @cfg {String} config.dataTemplate
         * A template string to visualize the data object of every user inside the selected user list.
         * The data object of the user can accessed by chosenData[$index] in the template string.
         * 
         * @cfg {Funtion} config.onAddUser
         * Event function that triggers if a user is selected in the dropdown.
         * The function gets the new UserInfo object and the scope as parameters.
         * If the function returns true the user will be added or replaced (in case
         * of singleSelect) if the function returns false the event is cancelled.
         * If this event is not given, a user is only added if it is not already in the list.
         * 
         * @cfg {Boolean} config.expandGroups
         * true to add functionality to expand a group into their members. This 
         * has not effect if singleSelect is true.
         * 
         *
         * @cfg {Array} chosenUsers
         * The list of current selected users as array of 
         * de.elo.ix.client.UserInfo objects.
         *
         * @cfg {Array} chosenData
         * The list of data objects for chosenUsers.
         * 
         * @cfg {Number} index
         * The index of the current selected user in the list.
         */
        .directive('eloUserSelection', [function () {
                return {
                    restrict: 'E',
                    transclude: true,
                    replace: true,
                    scope: {
                        config: '=',
                        selectedIndex: '=',
                        chosenUsers: '=',
                        chosenData: '='
                    },
                    controller: ['$scope', 'InputUtilsFactory', function ($scope, InputUtilsFactory) {
                            $scope.store = {
                                everyoneGroup: elo.CONST.USER_INFO.ID_EVERYONE_GROUP
                            };
                            $scope.loadingMask = false;
                            $scope.initAll = function () {
                                var i, factOptions;
                                $scope.filtered = {};
                                $scope.userInputConfig = {};

                                if (!$scope.chosenUsers) {
                                    $scope.chosenUsers = [];
                                }

                                if (!$scope.chosenData) {
                                    $scope.chosenData = [];
                                }

                                if ($scope.chosenUsers.length > 0 && $scope.chosenData.length < $scope.chosenUsers.length) {
                                    for (i = $scope.chosenData.length; i < $scope.chosenUsers.length; i += 1) {
                                        $scope.chosenData.push($scope.initDefaultData());
                                    }
                                }

                                if (!$scope.config) {
                                    elo.helpers.Console.error('api.module.Components.eloUserSelection: Config object missing');
                                    return;
                                }

                                $scope.userInputConfig.label = $scope.config.label;
                                $scope.userInputConfig.placeholder = $scope.config.placeholder;
                                $scope.userInputConfig.name = 'userInfo';
                                $scope.userInputConfig.focused = true;

                                factOptions = {};
                                factOptions.sourceUsers = $scope.config.sourceUsers;
                                factOptions.type = $scope.config.type;
                                factOptions.isDynamic = $scope.config.isDynamic;
                                factOptions.findUserInfo = $scope.config.findUserInfo;

                                $scope.userInputConfig = InputUtilsFactory.addUserListConfig($scope.userInputConfig, factOptions);
                                $scope.userInputConfig.kwl.onSelect = $scope.addUser;

                                // remove to many initial users if singleSelect
                                if ($scope.config.singleSelect && $scope.chosenUsers.length > 1) {
                                    $scope.chosenUsers = [$scope.chosenUsers[0]];
                                }
                            };

                            // DO NOT CHANGE BEHAVIOUR USED IN ONADDUSER
                            $scope.initDefaultData = function () {
                                if ($scope.config.defaultData && $scope.config.defaultData.constructor === Object) {
                                    return angular.copy($scope.config.defaultData);
                                }
                                return {};
                            };

                            $scope.angularIndexOf = function (arr, obj) {
                                var i;
                                for (i = 0; i < arr.length; i += 1) {
                                    if (angular.equals(arr[i], obj)) {
                                        return i;
                                    }
                                }
                                return -1;
                            };

                            $scope.addUser = function ($item, $model, $label) {
                                $scope.filtered = {};
                                if ($scope.config.singleSelect && (!$scope.config.onAddUser || $scope.config.onAddUser($item, $scope))) {
                                    $scope.chosenUsers = [$item];
                                    $scope.chosenData = [$scope.initDefaultData()];
                                    $scope.selectedIndex = 0;
                                } else if ((!$scope.config.onAddUser && $scope.angularIndexOf($scope.chosenUsers, $item) === -1) || ($scope.config.onAddUser && $scope.config.onAddUser($item, $scope))) {
                                    $scope.chosenUsers.push($item);
                                    $scope.chosenData.push($scope.initDefaultData());
                                    $scope.selectedIndex = $scope.chosenUsers.length - 1;
                                }
                            };

                            $scope.removeSelection = function (userId) {
                                var i;
                                for (i = 0; i < $scope.chosenUsers.length; i += 1) {
                                    if ($scope.chosenUsers[i].id === userId) {
                                        $scope.chosenUsers.splice(i, 1);
                                        $scope.chosenData.splice(i, 1);
                                        if ($scope.chosenUsers.length <= i && $scope.selectedIndex === i) {
                                            // last item was removed, unselect
                                            $scope.selectedIndex = -1;
                                        }
                                        break;
                                    }
                                }
                            };

                            $scope.expandSelection = function (userId) {
                                var i, group, groupData;
                                for (i = 0; i < $scope.chosenUsers.length; i += 1) {
                                    if ($scope.chosenUsers[i].id === userId) {
                                        if ($scope.config.expandGroups && $scope.chosenUsers[i].type === api.CONST.USER_INFO.TYPE_GROUP) {
                                            group = $scope.chosenUsers.splice(i, 1)[0];
                                            groupData = $scope.chosenData.splice(i, 1)[0];
                                            break;
                                        }
                                    }
                                }

                                if (group && groupData) {
                                    // expand group
                                    $scope.loadingMask = {
                                        loading: true,
                                        noLoadingMsg: true
                                    };
                                    api.IX.ix().checkoutUsers([group.id], api.CONST.CHECKOUT_USERS.MEMBERS_OF_GROUP, api.CONST.LOCK.NO, new de.elo.ix.client.AsyncCallback(
                                        function (users) {
                                            var h, j, found;
                                            for (h = 0; h < users.length; h += 1) {
                                                found = false;
                                                for (j = 0; j < $scope.chosenUsers.length; j += 1) {
                                                    if (users[h].id === $scope.chosenUsers[j].id) {
                                                        found = true;
                                                        break;
                                                    }
                                                }
                                                if (!found) {
                                                    $scope.chosenUsers.splice(i, 0, users[h]);
                                                    $scope.chosenData.splice(i, 0, groupData);
                                                }
                                            }
                                            $scope.loadingMask = false;
                                            $scope.$apply();
                                        }, function (e) {
                                        elo.helpers.Console.error(api.helpers.Text.getText("ELOCMP.ERROR"), e.toString());
                                        api.webapps.WebApp.showToast(api.helpers.Text.getText("ELOCMP.ERROR"), e.toString(), api.webapps.WebApp.TOAST_TYPE.ERROR);
                                        $scope.loadingMask = false;
                                        $scope.$apply();
                                    }));
                                }
                            };

                            $scope.selectUser = function (index) {
                                $scope.selectedIndex = index;
                            };

                            $scope.listItemClass = function (idx) {
                                if (idx === $scope.selectedIndex) {
                                    return 'list-group-item selected-user active';
                                }
                                return 'list-group-item selected-user';
                            };

                            $scope.move = function (oldIndex, newIndex) {
                                var tmp1, tmp2;
                                tmp1 = $scope.chosenUsers.splice(oldIndex, 1)[0];
                                tmp2 = $scope.chosenData.splice(oldIndex, 1)[0];
                                $scope.chosenUsers.splice(newIndex, 0, tmp1);
                                $scope.chosenData.splice(newIndex, 0, tmp2);
                            };

                            $scope.userSelectionTracking = function (index, user) {
                                return [user.id, index].join(' ');
                            };

                            $scope.initAll();
                        }
                    ],
                    templateUrl: api.module.Components.relativeUrl + 'directives/user-selection/user-selection.html'
                };
            }]);
}());