# Source: src/js/views/GroupListView.js

    /*global define */
    define(['jquery', 'underscore', 'backbone', 'collections/UserGroup', 'models/UserModel', 'views/PagerView'],
    	function($, _, Backbone, UserGroup, UserModel, PagerView) {
    	'use strict';

    	/**
    	 * @class GroupListView
    	 * @classdesc Displays a list of UserModels of a UserGroup collection and allows owners to add/remove members from the group
       * @classcategory Views
       * @screenshot views/GroupListView.png
    	 */
    	var GroupListView = Backbone.View.extend(
        /** @lends GroupListView.prototype */{

    		type: "GroupListView",

    		tagName: "ul",

    		className: "list-group member-list",

    		memberEls: [],

    		/*
    		 * New instances of this view should pass a UserGroup collection in the options object
    		 */
    		initialize: function(options){
    			if(typeof options == "undefined")
    				var options = {};

    			this.collection    = options.collection || new UserGroup();
    			this.groupId       = this.collection.groupId || null;
    			this.collapsable   = (typeof options.collapsable == "undefined")? true : options.collapsable;
    			this.showGroupName = (typeof options.showGroupName == "undefined")? true : options.showGroupName;
    			this.maxItems      = options.maxItems || 2;
    		},

    		events: {
    			"click .toggle"               : "toggleMemberList",
    			"click .add-member .submit"   : "addToCollection",
    			"click .remove-member"		  : "removeFromCollection",
    			"click .add-owner"            : "addOwnerToCollection",
    			"click .remove-owner"         : "removeOwnership",
    			"keypress input"              : "checkForReturn"
    		},

    		/*
    		 * The overall list layout is created, with a header and list of members.
    		 * This view listens to the UserGroup collection and updates the member list as
    		 * members are added and removed.
    		 */
    		render: function(){

    			var group = this.collection,
    				view  = this;

    			//Empty first
    			this.$el.empty();

    			//Create the header/first-level of the list
    			var listItem   = $(document.createElement("li")).addClass("list-group-header list-group-item group"),
    				//icon       = $(document.createElement("i")).addClass("icon icon-caret-down tooltip-this group"),
    				numMembers = $(document.createElement("span")).addClass("num-members").text(group.length),
    				numMembersLabel = $(document.createElement("span")).text(" members"),
    				numMembersContainer = $(document.createElement("span")).append(numMembers, numMembersLabel);

    			if(this.showGroupName){
    				if(!this.collection.pending){
    					var link       = $(document.createElement("a")).attr("href", MetacatUI.root + "/profile/" + group.groupId).attr("data-subject", group.groupId),
    						groupName  = $(document.createElement("span")).text(group.name);
    				}
    				else{
    					var link       = $(document.createElement("a")).attr("href", "#"),
    						groupName  = $(document.createElement("span")).text("");
    				}

    				//Put it all together
    				$(listItem).append($(link).prepend(/*icon, */groupName));
    				numMembersContainer.prepend(" (").append(")");
    			}

    			//Add the member count
    			this.$el.append(listItem.append(numMembersContainer));

    			//Save some elements for later use
    			this.$header = $(listItem);
    			this.$numMembers = $(numMembers);
    			this.$groupName  = $(groupName);

    			//Create a list of member names
    			var view = this;
    			group.forEach(function(member){
    				view.addMember(member);
    			});

    			//Create a pager for this list if there are many group members
    			if(group.length > 4){
    				this.pager = new PagerView({
    					pages: this.$(".member"),
    					itemsPerPage: 4,
    					classes: "list-group-item"
    				});
    				this.$el.append(this.pager.render().el);
    			}

    			//Add some group controls for the owners
    			if(group.isOwner(MetacatUI.appUserModel))
    				this.addControls();

    			this.listenTo(group, "add", this.addMember);
    			this.listenTo(group, "remove", this.removeMember);
    			this.listenTo(group, "change:isOwnerOf", this.addControls);

    			return this;
    		},

    		//-------- Adding members to the group --------//
    		/*
    		 * The specified UserModel is added to the UI, and if the current user is an owner of the group,
    		 * the owner controls are displayed
    		 */
    		addMember: function(member){
    			var username = member.get("username"),
    				name     = member.get("fullName") || member.get("usernameReadable") || member.get("username");

    			//If this is the currently-logged-in user, display "Me"
    			if(username == MetacatUI.appUserModel.get("username"))
    				name = name + " (Me)";

    			//Create a list item for this member
    			var memberListItem = $(document.createElement("li")).addClass("list-group-item member").attr("data-username", username),
    				memberNameContainer = $(document.createElement("div")).addClass("name-container"),
    				memberIcon     = $(document.createElement("i")).addClass("icon icon-user icon-on-right"),
    				memberLink     = $(document.createElement("a")).attr("href", MetacatUI.root + "/profile/" + username).attr("data-username", username).prepend(memberIcon, name),
    				memberName     = $(document.createElement("span")).addClass("details ellipsis").attr("data-username", username).text(member.get("usernameReadable"));

    			memberIcon.tooltip({
    				placement: "top",
    				trigger: "hover",
    				title: "Group member"
    			});

    			//Put all the elements together
    			var memberEl = $(memberListItem).append($(memberNameContainer).append(memberLink, memberName));

    			//Store this element in the view
    			this.memberEls[member.cid] = memberEl;

    			//Append after the last member listed
    			if(this.$(".member").length)
    				this.$(".member").last().after(memberEl);
    			//If no members are listed yet, append to the main el
    			else
    				this.$el.append(memberEl);

    			//Add an owner icon for owners of the group or to assign owners to the group
    			if(this.collection.isOwner(member) || this.collection.isOwner(MetacatUI.appUserModel)){
    				var ownerIcon = this.getOwnerEl(member);
    				memberLink.before(ownerIcon);
    			}

    			//If the current user is an owner of this group, then display a 'remove member' button - but not for themselves
    			if(this.collection.isOwner(MetacatUI.appUserModel) && (username.toLowerCase() != MetacatUI.appUserModel.get("username").toLowerCase())){
    				//Add a remove icon for each member
    				var removeIcon = $(document.createElement("i")).addClass("icon icon-remove icon-negative remove-member"),
    					clearfix   = $(document.createElement("div")).addClass('clear'),
    				    memberControls = $(document.createElement("div")).addClass("member-controls").append(removeIcon);
    				removeIcon.tooltip({
    					trigger   : "hover",
    					placement : "top",
    					title     : "Remove this person from the group"
    				});
    				memberNameContainer.addClass("has-member-controls").after(memberControls, clearfix);
    			}

    			//Update the header
    			this.updateHeader();

    			//Collapse members of this group is necessary
    			if(this.$el.is(".collapsed"))
    				this.collapseMember(memberEl);

    			if(this.pager)
    				this.pager.update(this.$(".member"));
    		},

    		/*
    		 * When the user inputs a username, a UserModel is created and added to the collection.
    		 * The collection is saved to the server. Failed and successful member additions are
    		 * handled and displayed to the user
    		 */
    		addToCollection: function(e){
    			if(e) e.preventDefault();

    			//Get form values
    			var username = this.$addMember.find("input[name='username']").val().trim();
    			var fullName = this.$addMember.find("input[name='fullName']").val().trim();

    			//Reset the form
    			this.$addMember.find("input[name='username']").val("");
    			this.$addMember.find("input[name='fullName']").val("");

    			if(!username){
    				this.addMemberNotification({
    					msg: "You must enter a person's username. Try searching by name or email address.",
    					status: "error"
    				});
    				return;
    			}

    			//Is this user already in the collection?
    			if(this.collection.findWhere({username: username})){
    				this.addMemberNotification({
    					msg: fullName + " is already in this group",
    					status: "error"
    				});
    				return;
    			}

    			//Don't auto-collapse the list since the user is interacting with the controls right now
    			this.preventToggle = true;

    			//Create User Model
    			var user = new UserModel({
    				username: username,
    				fullName: fullName
    			});

    			//Add this user to the collection
    			this.collection.add(user);

    			//If this is a pending group (in the middle of creation), then don't save it to the server
    			if(this.collection.pending) return;

    			//Save this user in the group
    			var view = this;
    			var success = function(response){
    				view.addMemberNotification({
    					msg: fullName + " added",
    					status: "success"
    				});
    			}
    			var error = function(response){
    				if(!fullName) fullName = "that person";
    				view.addMemberNotification({
    					msg: "Something went wrong and " + fullName + " could not be added. " +
    							"Hint: That user may not exist.",
    					status: "error"
    				});

    				//Remove this user from the collection and other storage
    				view.memberEls[user.cid] = null;
    				view.collection.remove(user);
    			}

    			//Save
    			this.collection.save(success, error);
    		},

    		//-------- Removing members from the group ------//
    		/*
    		 * When the user clicks on the remove icon, the member is removed from the collection
    		 * and the updated collection is saved to the server
    		 */
    		removeFromCollection: function(e){
    			e.preventDefault();

    			var username = $(e.target).parents(".member").attr("data-username");
    			if(!username) return;

    			if(username.toLowerCase() == MetacatUI.appUserModel.get("username").toLowerCase()){
    				this.addMemberNotification({
    					status: "error",
    					msg: "You can't remove yourself from a group."
    				});
    				return;
    			}
    			else if(this.collection.length == 1){
    				this.addMemberNotification({
    					status: "error",
    					msg: "You must have at least one member in a group."
    				});
    				return;
    			}

    			//Remove the member from the collection
    			var member = this.collection.findWhere({username: username});
    			this.collection.remove(member);

    			//Update the header
    			this.updateHeader();

    			//Only save the group to the server if its not a pending group
    			if(!this.collection.pending)
    				this.collection.save();
    		},

    		/*
    		 * Removes the specified member from the UI
    		 */
    		removeMember: function(member){
    			//Get DOM element for this user
    			var memberEl = this.memberEls[member.cid];
    			if((typeof memberEl === "undefined") || !memberEl)
    				memberEl = this.$("li[data-username='" + member.get("username") + "']");

    			//Remove from page
    			memberEl.remove();

    			//Remove this member el from the view storage
    			this.memberEls[member.cid] = null;

    			if(this.pager)
    				this.pager.update(this.$(".member"));
    		},

    		//-------------- Displaying UI elements for owners --------------//
    		/*
    		 * When a user clicks on the add-owner element, this view will add the user as an owner of the
    		 * group and will update the collection. The collection is saved to the server.
    		 */
    		addOwnerToCollection: function(e){
    			if(!e) return;
    			e.preventDefault();

    			var view = this;

    			//Get this member
    			var username = $(e.target).parents(".member").attr("data-username");
    			if(!username) return;
    			var member = this.collection.findWhere({username: username});

    			//Update ownership
    			member.get("isOwnerOf").push(this.collection.groupId);
    			member.trigger("change:isOwnerOf");

    			//Save
    			var success = function(){ view.refreshOwner(member); }
    			this.collection.save(success);
    		},

    		/*
    		 * When the user clicks on the remove ownership icon for an owner, the rightsHolder is removed
    		 * from the group and the updated group is saved to the server.
    		 */
    		removeOwnership: function(e){
    			if(!e) return;
    			e.preventDefault();

    			var view = this;

    			//Get this member
    			var username = $(e.target).parents(".member").attr("data-username");
    			if(!username) return;
    			var member = this.collection.findWhere({username: username});

    			//Make sure we have at least one owner in this group left
    			var	newOwners = _.without( this.collection.getOwners(), member);
    			if(newOwners.length < 1){
    				MetacatUI.appView.showAlert("Groups need to have at least one owner.", "aler-error", this.$el, true);
    				return;
    			}

    			//Update the model
    			var newOwnership = _.without(member.get("isOwnerOf"), view.collection.groupId);
    			member.set("isOwnerOf", newOwnership);
    			member.trigger("change:isOwnerOf");

    			//Save
    			var success = function(){ view.refreshOwner(member); }
    			this.collection.save(success);
    		},

    		refreshOwner: function(user){
    			//Get the member element on the page
    			var memberEl = this.memberEls[user.cid];
    			if((typeof memberEl === "undefined") || !memberEl)
    				memberEl = this.$(".member[data-username='" + user.get("username") + "'");

    			//Replace the owner element with the new one
    			$(memberEl).find(".owner").tooltip("destroy").replaceWith(this.getOwnerEl(user));
    		},

    		getOwnerEl: function(member){
    			var ownerIcon = $(document.createElement("i")).addClass("icon owner pointer");

    			if(this.collection.isOwner(member)){
    				ownerIcon.addClass("icon-star is-owner remove-owner").tooltip({
    					placement: "top",
    					trigger: "hover",
    					title: "Group owner",
              delay: {
                show: 500
              }
    				});
    			}
    			else{
    				ownerIcon.addClass("icon-star-empty add-owner").tooltip({
    					placement: "top",
    					trigger: "hover",
    					title: "Add this person as a co-owner of the group",
              delay: {
                show: 500
              }
    				});
    			}

    			return ownerIcon;
    		},

    		addControls: function(){
    			if(!MetacatUI.appUserModel.get("loggedIn") || (!this.collection.isOwner(MetacatUI.appUserModel)) || this.$addMember) return;

    			//Add a form for adding a new member
    			var addMemberInput    = $(document.createElement("input"))
    									.attr("type", "text")
    									.attr("name", "username")
    	   							    .attr("placeholder", "Username or Name (cn=me, o=my org...)")
    	   							    .attr("data-submit-callback", "addToCollection")
    									.addClass("input-xlarge account-autocomplete submit-enter"),
    				addMemberName     = $(document.createElement("input"))
    									.attr("type", "hidden")
    									.attr("name", "fullName")
    									.attr("disabled", "disabled"),
    				addMemberIcon     = $(document.createElement("i")).addClass("icon icon-plus"),
    				addMemberSubmit   = $(document.createElement("button")).addClass("btn submit").append(addMemberIcon),
    				addMemberLabel    = $(document.createElement("label")).text("Add Member - Search by username, email, or name OR enter a full username below."),
    				addMemberMsg      = $(document.createElement("div")).addClass("notification")
    									.append($(document.createElement("i")).addClass("icon"),
    											$(document.createElement("span")).addClass("msg")),
    				addMemberForm     = $(document.createElement("form")).append(addMemberLabel, addMemberInput, addMemberName, addMemberSubmit, addMemberMsg),
    				addMemberListItem = $(document.createElement("li")).addClass("list-group-item add-member input-append").append(addMemberForm);

    			this.$addMember = $(addMemberForm);
    			this.$addMemberMsg = $(addMemberMsg);

    			this.$el.append(addMemberListItem);

    			this.setUpAutocomplete();

    		},

    		/*
    		 * Display a notification in the "add member" form space
    		 * Pass an options object with a msg (message string) and status ('success' or 'error')
    		 */
    		addMemberNotification: function(options){
    			if(!options.status) options.status = "success";
    			if(!options.msg) return;

    			if(options.status == "success"){
    				this.$addMemberMsg.addClass("success").removeClass("error")
    								  .children(".icon").addClass("icon-ok").removeClass("icon-remove");
    				this.$addMemberMsg.children(".msg").text(options.msg);
    			}
    			else{
    				this.$addMemberMsg.removeClass("success").addClass("error")
    				  .children(".icon").removeClass("icon-ok").addClass("icon-remove");
    				this.$addMemberMsg.children(".msg").text(options.msg);
    			}

    			this.$addMemberMsg.show().delay(3000).fadeOut();
    		},

    		/*
    		 * Update the header of this group list, which includes the number of members and the group name
    		 */
    		updateHeader: function(){
    			if(this.$numMembers)
    				this.$numMembers.text(this.collection.length);
    			if(this.$groupName)
    				this.$groupName.text(this.collection.name);
    		},

    		//----------- Form utilities -------------//
    		setUpAutocomplete: function() {
    			var input = this.$(".account-autocomplete");
    			if(!input || !input.length) return;

    			var view = this;

    			// look up registered identities
    			$(input).hoverAutocomplete({
    				source: function (request, response) {
    		            var term = $.ui.autocomplete.escapeRegex(request.term);

    		            var list = [];

    		            //Ids/Usernames that we want to ignore in the autocompelte
    		            var ignoreIds = view.collection.pluck("username");
    		            _.each(ignoreIds, function(id){
    		            	ignoreIds.push(id.toLowerCase());
    		            });
    		            ignoreIds.push(MetacatUI.appUserModel.get("username").toLowerCase());

    		            var url = MetacatUI.appModel.get("accountsUrl") + "?query=" + encodeURIComponent(term);
    					var requestSettings = {
    							url: url,
    							type: "GET",
    							success: function(data, textStatus, xhr) {

    								_.each($(data).find("person"), function(person, i){
    									var item = {};
    									item.value = $(person).find("subject").text();

    									//Ignore certain values
    									if(_.contains(ignoreIds, item.value.toLowerCase())) return;

    									item.fullName = $(person).find("fullName").text() || ($(person).find("givenName").text() + " " + $(person).find("familyName").text());
    									item.label = item.fullName;
    									//item.label = "<h3>"+item.fullName+"</h3>Google!";

    									list.push(item);
    								});

    					            response(list);
    							}
    					}
    					$.ajax(_.extend(requestSettings, MetacatUI.appUserModel.createAjaxSettings()));

    					//Send an ORCID search when the search string gets long enough
    					if(request.term.length > 3)
    						MetacatUI.appLookupModel.orcidSearch(request, response, false, ignoreIds);
    		        },
    				select: function(e, ui) {
    					e.preventDefault();

    					// set the text field
    					$(e.target).val(ui.item.value);
    					$(e.target).parents("form").find("input[name='fullName']").val(ui.item.fullName);
    				},
    				position: {
    					my: "left top",
    					at: "left bottom",
    					collision: "none"
    				}
    			});

    		},

    		checkForReturn: function(e){
    			if(e.keyCode != 13) return;

    			if($.contains(e.target, this.$addMember.find("input[name='fullName']"))){
    				e.preventDefault();
    				return;
    			}
    			else if($(e.target).is(".submit-enter")){
    				e.preventDefault();
    				var callback = $(e.target).attr("data-submit-callback");
    				this[callback]();
    				return;
    			}
    		},

    		//---------- Collapsing/Expanding the member list --------//
    		collapseMember: function(memberEl){
    			if(this.preventToggle || !this.collapsable) return;

    			$(memberEl).slideUp();
    		},

    		collapseMemberList: function(e){
    			if((this.preventToggle && !e) || !this.collapsable) return;

    			this.$(".member, .add-member").slideUp().addClass("collapsed");
    			this.$(".icon.group").addClass("icon-caret-right").removeClass("icon-caret-down");
    		},

    		toggleMemberList: function(e){
    			if(e) e.preventDefault();
    			else if(this.preventToggle || !this.collapsable) return;

    			this.$(".member, .add-member").slideToggle().toggleClass("collapsed");
    			this.$(".icon.group").toggleClass("icon-caret-right icon-caret-down");
    		},

    		// ------- When this view is closed --------//
    		onClose: function(){
    			this.remove();
    		}

    	});

    	return GroupListView;
    });