Index: samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/QuestionPoolMessages.properties
===================================================================
--- samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/QuestionPoolMessages.properties	(revision 308089)
+++ samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/QuestionPoolMessages.properties	(working copy)
@@ -112,7 +112,7 @@
 # add/update
 add_title=Add Pool
 add_summary=add  main form
-creator=Creator
+creator=Owner
 dept=Department/Group
 desc=Description
 obj=Objectives
@@ -214,3 +214,22 @@
 alt_sortRole = Order by role
 alt_sortRoleAscending = Order by role in Ascending
 alt_sortRoleDescending = Order by role in Descending
+
+# SAM-2049
+t_transferPool=Transfer Pool
+transfer_pool=transfer pool
+tranfer_pool_continue=Continue
+transfer_pool_back=Back
+transfer_pool_cancel=Cancel
+transfer_pool_ownership=Transfer Ownership
+a_transfer=t
+a_transfer_back=b
+a_cancel=c
+transfer_pool_user=transfer pool add user
+transfer_pool_confirmation=transfer pool confirmation
+transfer_pool_input_user=Enter the user ID for the new owner of the selected pools and click 'Continue'.
+transfer_pool_confirm_owner=Ownership of the following pools will be transferred to {0}:
+transfer_pool_ids_null_error=You must select at least one question pool to proceed with the transfer.
+transfer_pool_userId_null_error=Please input user ID.
+transfer_pool_user_invalid=Please enter a valid username.
+transfer_pool_select_all=Select All Pools
Index: samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/questionpool/QuestionPoolBean.java
===================================================================
--- samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/questionpool/QuestionPoolBean.java	(revision 308089)
+++ samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/questionpool/QuestionPoolBean.java	(working copy)
@@ -47,6 +47,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.struts.upload.FormFile;
+import org.osid.shared.SharedException;
 import org.sakaiproject.tool.assessment.business.questionpool.QuestionPoolTreeImpl;
 import org.sakaiproject.tool.assessment.data.dao.assessment.ItemMetaData;
 import org.sakaiproject.tool.assessment.data.dao.questionpool.QuestionPoolData;
@@ -58,12 +59,16 @@
 import org.sakaiproject.tool.assessment.facade.QuestionPoolFacade;
 import org.sakaiproject.tool.assessment.facade.QuestionPoolIteratorFacade;
 import org.sakaiproject.tool.assessment.facade.SectionFacade;
+import org.sakaiproject.tool.assessment.osid.shared.impl.IdImpl;
 import org.sakaiproject.tool.assessment.services.ItemService;
 import org.sakaiproject.tool.assessment.services.QuestionPoolService;
 import org.sakaiproject.tool.assessment.services.SectionService;
 import org.sakaiproject.tool.assessment.ui.bean.author.ItemAuthorBean;
 import org.sakaiproject.tool.assessment.ui.listener.util.ContextUtil;
 import org.sakaiproject.tool.assessment.util.BeanSort;
+import org.sakaiproject.user.api.User;
+import org.sakaiproject.user.api.UserNotDefinedException;
+import org.sakaiproject.user.cover.UserDirectoryService;
 import org.sakaiproject.util.ResourceLoader;
 import org.sakaiproject.event.cover.EventTrackingService;
 
@@ -149,6 +154,16 @@
   private QuestionPoolDataModel qpDataModel;
   private QuestionPoolDataModel qpDataModelCopy;
   private QuestionPoolDataModel subQpDataModel;
+  
+  // SAM-2049
+  private String sortTransferPoolProperty = "title";
+  private boolean sortTransferPoolAscending = true;
+  private QuestionPoolDataModel qpDataModelTransfer;
+  private QuestionPoolDataModel qpDataModelTransferSelected;
+  private List<Long> transferPools;
+  private String ownerId;
+  private String confirmMessage;
+  private boolean checkAll = false;
 
  private String addOrEdit;
   private String outcome;
@@ -2215,4 +2230,273 @@
   		String owner = AgentFacade.getDisplayName(getAgentId());
   		return owner;
   	}
+  	
+  	// **********************************************
+  	// ****************** SAM-2049 ******************
+  	// **********************************************
+  	
+  	public boolean getSortTransferPoolAscending() {
+  		return sortTransferPoolAscending;
+  	}
+  	
+	public void setSortTransferPoolAscending(boolean sspa) {
+		sortTransferPoolAscending = sspa;
+	}
+	  
+	public String getSortTransferPoolProperty() {
+	    return sortTransferPoolProperty;
+	}
+	  
+	public void setSortTransferPoolProperty(String newProperty) {
+	    sortTransferPoolProperty= newProperty;
+	}
+	
+	public String transferPoolConfirmBack() {		
+		return "transferPoolInputUser";
+	}
+
+	public List<Long> getTransferPools() {
+		return transferPools;
+	}
+
+	public void setTransferPools(List<Long> transferPools) {
+		this.transferPools = transferPools;
+	}
+
+	public String getOwnerId() {
+		return ownerId;
+	}
+
+	public void setOwnerId(String ownerId) {
+		this.ownerId = ownerId;
+	}
+
+	public boolean isCheckAll() {
+		return checkAll;
+	}
+
+	public void setCheckAll(boolean checkAll) {
+		this.checkAll = checkAll;
+	}
+  	
+  	public QuestionPoolDataModel getTransferQpools() {	
+		buildTreeCopy();
+		setQpDataModelByLevelTransferPool();
+		log.debug("getSelectedQpools");
+		return qpDataModelTransfer;
+	}
+   
+  	public QuestionPoolDataModel getTransferSelectedQpools() {
+  		buildTreeTransferPool();
+  		setQpDataModelByLevelTransferSelectedPools();
+  		log.debug("qpDataModelTransferSelected");
+  		return qpDataModelTransferSelected;
+  	}
+  
+  	public void buildTreeTransferPool() {
+  		try {
+  			QuestionPoolService delegate = new QuestionPoolService();
+  			List<QuestionPoolFacade> qpList = new ArrayList<QuestionPoolFacade>();
+  
+  		  	if (transferPools != null ) {
+  		  		for (Long poolId : transferPools) {
+  		  			QuestionPoolFacade qpFacade =  delegate.getPool(poolId, AgentFacade.getAgentString() );
+  
+  		  			IdImpl parentId = (IdImpl) qpFacade.getParentId();
+  		  			Long parentIdLong = new Long("0");
+  
+  		  			try {
+  					  parentIdLong = Long.valueOf(parentId.getIdString());
+  		  			} catch (SharedException e) {
+  					  log.warn("error setting pool id to Long." + e.getMessage());
+  		  			}
+  		  			
+  		  			// If just the child pool will transfer but not the parent pool, set this child pool has no parent.
+  		  			if (!transferPools.contains(parentIdLong)) {
+  		  				IdImpl updateParentId = new IdImpl("0");
+  		  				qpFacade.setParentId(updateParentId);
+  		  			}
+  				  				
+  		  			qpList.add(qpFacade);
+  		  		}
+  		  		QuestionPoolIteratorFacade qpif = new QuestionPoolIteratorFacade(qpList);
+  		  		tree = new QuestionPoolTreeImpl(qpif);
+  		  	} else {
+  			  tree = new QuestionPoolTreeImpl(new QuestionPoolIteratorFacade(new ArrayList<QuestionPoolFacade>()));
+  		  	}
+  		} catch (Exception e) {
+  		  log.warn("error building transfer pool tree." + e.getMessage());
+  		  throw new RuntimeException(e);
+  	  	}	  
+  	}
+	
+	public String sortTransferPoolByColumnHeader() {
+		String sortString = ContextUtil.lookupParam("transferPoolOrderBy");
+		String ascending = ContextUtil.lookupParam("transferPoolAscending");
+		this.setSortTransferPoolProperty(sortString);
+		this.setSortTransferPoolAscending((Boolean.valueOf(ascending)).booleanValue());
+		setQpDataModelByLevelTransferPool();
+		return "transferPool";
+	}
+	
+	public void setQpDataModelByLevelTransferPool() {
+  		Collection<QuestionPoolDataIfc> objects = tree.getSortedObjects();
+
+  		// Construct the sortedList, pools need to be sorted one level at a time
+  		// so the hierachical structure can be maintained. Here, we start from root = 0,
+  		if (objects != null) {
+  			ArrayList<QuestionPoolDataIfc> sortedList = sortPoolByLevel(new Long("0"), objects,
+  					getSortTransferPoolProperty(), getSortTransferPoolAscending());
+  			ListDataModel model = new ListDataModel((List<QuestionPoolDataIfc>) sortedList);
+  			QuestionPoolDataModel qpDataModel = new QuestionPoolDataModel(tree,
+  					model);
+  			this.qpDataModelTransfer = qpDataModel;
+  		}
+  	}
+
+ 	public void setQpDataModelByLevelTransferSelectedPools() {
+		Collection<QuestionPoolDataIfc> objects = tree.getSortedObjects();
+
+		// Construct the sortedList, pools need to be sorted one level at a time
+		// so the hierachical structure can be maintained. Here, we start from root = 0,
+		if (objects != null) {
+			ArrayList<QuestionPoolDataIfc> sortedList = sortPoolByLevel(new Long("0"), objects,
+					"title", true);
+			ListDataModel model = new ListDataModel((List<QuestionPoolDataIfc>) sortedList);
+			QuestionPoolDataModel qpDataModel = new QuestionPoolDataModel(tree,
+					model);
+			this.qpDataModelTransferSelected = qpDataModel;
+		}
+	}
+ 	
+ 	// Click transfer ownership link in main page
+	public String transferPool() {
+		// Reset transferPools, checkAll checkbox, ownerId
+		this.transferPools = null;
+		this.checkAll = false;
+		this.ownerId = null;
+		
+		buildTree();
+		setQpDataModelByLevelTransferPool();
+		return "transferPool";
+	}
+	
+	// Transfer pool tree page click continue button
+	public String transferPoolContinue() {
+		// Setup selected pools for transfer; if no pools selected, post error message
+		String transferPoolIds = ContextUtil.paramValueLike("transferPoolIds");
+               if (transferPoolIds == null || transferPoolIds.isEmpty()) {
+                    FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(rb.getString("transfer_pool_ids_null_error")));
+                    return "transferPool";
+               }
+
+		String[] poolIds = transferPoolIds.split(",");		
+		List<Long> transferPoolIdLong = new ArrayList<Long>();
+		for (int i = 0; i < poolIds.length; i++) {
+                        if (poolIds[i] != null && !poolIds[i].isEmpty()) {
+                                transferPoolIdLong.add(new Long(poolIds[i]));
+                        }
+		}
+		this.transferPools = transferPoolIdLong;	
+		
+		String checkAllChecked = ContextUtil.paramValueLike("checkAllCheckbox");
+		if (checkAllChecked == null || "false".equals(checkAllChecked)) {
+			this.checkAll = false;
+		} else {
+			this.checkAll = true;
+		}
+		
+		return "transferPoolInputUser";
+	}
+	
+	// Transfer pool tree page click cancel button
+	public String cancelTransferPool() {
+		buildTree();
+		setQpDataModelByLevel();
+		return "poolList";
+	}
+	
+	// Transfer pool input user id page, click continue button
+	public String transferPoolInputUserContinue() {
+		String ownerUserId = ContextUtil.paramValueLike("owneruserId");
+		
+		// Check if the userId is null or ""
+		FacesContext context=FacesContext.getCurrentInstance();
+		String err;
+		if (ownerUserId == null || "".equals(ownerUserId)) {
+			err = rb.getString("transfer_pool_userId_null_error");
+			context.addMessage(null, new FacesMessage(err));
+			return "transferPoolInputUser";
+		}
+		
+		// Check if userId is valid
+		try { 
+			User user = UserDirectoryService.getUserByEid(ownerUserId);
+		} catch (UserNotDefinedException e) {
+			log.debug("Unable to get user by eid: " + ownerUserId);
+			err = rb.getString("transfer_pool_user_invalid");
+			context.addMessage(null, new FacesMessage(err));
+			return "transferPoolInputUser";
+		}
+		
+		this.ownerId = ownerUserId;
+		return "transferPoolConfirm";
+	}
+	
+	// Transfer pool input user id page, click back button
+	public String transferPoolInputUserBack() {
+		buildTree();
+		setQpDataModelByLevelTransferPool();
+		return "transferPool";
+	}
+	
+	public String getConfirmMessage() {
+		try {
+			User user = UserDirectoryService.getUserByEid(ownerId);
+			String userInfo = user.getDisplayName() +  " (" + this.ownerId +  ")";
+			confirmMessage = rb.getFormattedMessage("transfer_pool_confirm_owner", new String[] {userInfo});
+			return confirmMessage;
+		} catch(UserNotDefinedException e) {
+			log.warn("Unable to get user by eid: " + ownerId);
+			e.printStackTrace();
+			return "";
+		}
+	}
+	
+	public String transferPoolOwnership() {		
+		QuestionPoolService delegate = new QuestionPoolService();
+		try {
+			// Need to pass userId not eid to transfer pool.
+			String userId = UserDirectoryService.getUserId(ownerId);
+			delegate.transferPoolsOwnership(userId, transferPools);
+			
+			// Aggregate pool IDs
+			String poolIdString = "";
+			String prefix = "";
+			for (Long poolId : transferPools) {
+				poolIdString += prefix + poolId.toString();
+				prefix = ",";
+			}
+			
+			// Post event
+			Date now = new Date();	
+			User currentUser = UserDirectoryService.getCurrentUser();
+			String userEID = "";
+			if (currentUser != null) {
+				userEID = currentUser.getEid();
+			} else {
+				userEID = "[current user is null]";
+			}
+			EventTrackingService.post(EventTrackingService.newEvent("sam.questionpool.transfer", "pool(s) [" + poolIdString + "] transferred " +
+					"from " + userEID + " to " + this.ownerId + " on " + now , true));
+
+			buildTree();
+			setQpDataModelByLevel();
+			return "poolList";
+		} catch (UserNotDefinedException e) {
+			log.warn("Unable to get user by eid: " + ownerId);
+			e.printStackTrace();
+			return "";
+		}
+	}
 }
Index: samigo-app/src/webapp/WEB-INF/faces-config.xml
===================================================================
--- samigo-app/src/webapp/WEB-INF/faces-config.xml	(revision 308089)
+++ samigo-app/src/webapp/WEB-INF/faces-config.xml	(working copy)
@@ -1039,6 +1039,21 @@
       <from-outcome>copyPool</from-outcome>
       <to-view-id>/jsf/questionpool/copyPool.jsp</to-view-id>
     </navigation-case>
+    
+    <!-- SAM-2049 -->
+     <navigation-case>
+      <from-outcome>transferPoolInputUser</from-outcome>
+      <to-view-id>/jsf/questionpool/transferPoolInputUser.jsp</to-view-id>
+    </navigation-case>
+     <navigation-case>
+      <from-outcome>transferPool</from-outcome>
+      <to-view-id>/jsf/questionpool/transferPool.jsp</to-view-id>
+    </navigation-case>
+      <navigation-case>
+      <from-outcome>transferPoolConfirm</from-outcome>
+      <to-view-id>/jsf/questionpool/transferPoolConfirm.jsp</to-view-id>
+    </navigation-case>
+    
     <navigation-case>
       <from-outcome>movePool</from-outcome>
       <to-view-id>/jsf/questionpool/movePool.jsp</to-view-id>
Index: samigo-app/src/webapp/js/samigotree.js
===================================================================
--- samigo-app/src/webapp/js/samigotree.js	(revision 308089)
+++ samigo-app/src/webapp/js/samigotree.js	(working copy)
@@ -541,3 +541,148 @@
   }
 }
 
+// **********************************************
+// ****************** SAM-2049 ******************
+// **********************************************
+
+function checkChildrenCheckboxes(item) {
+	var localItem = jQuery(item);
+	var itemChecked = localItem.is(':checked');
+
+	// Go to the item's parent table that has the tier. I would have used a wildcard selector but the version
+	// of jquery we are using doesn't seem to have that working well
+	var itemParentTable = localItem.parent().parent().parent().parent().parent();
+  
+	// Make sure we found something.  A length of 0 would be not found
+	if (itemParentTable.length == 1) {
+		// What is the css style of this parent table? we assume this is "tierX"
+		var itemTierClassName = itemParentTable.attr("class");
+		var itemCheckboxTierDigit = getTierDigit(itemTierClassName);
+		var itemParentTr = itemParentTable.parent().parent().parent();
+     
+		// Let's get all the other mega table rows
+		var itemPeerTrs = itemParentTr.nextAll(); // Get all sibling tr's AFTER this tr.
+
+		// This will be used if we find a tier level that is at a level the same or higher than the one being checked
+		var isKeepLooping = true;
+
+		for (var index = 0; (isKeepLooping && index < itemPeerTrs.length); index++) {	    	 
+			var siblingTr = jQuery(itemPeerTrs.get(index));
+			var siblingTierTable = siblingTr.find("table");
+			var siblingTierTableClassName = siblingTierTable.attr("class");	    	 
+			var siblingCheckboxTierDigit = getTierDigit(siblingTierTableClassName);
+
+			// If this tier level is greater than the initial item checked then these are child
+			// checkboxes that need to be set or unset.
+			if (siblingCheckboxTierDigit > itemCheckboxTierDigit) {
+				var siblingInputCheckbox = siblingTierTable.find("input:checkbox");
+				if (itemChecked) {
+					siblingInputCheckbox.attr("checked", "checked");
+					siblingInputCheckbox.attr("disabled", "disabled");
+				} else {
+					siblingInputCheckbox.removeAttr("checked");
+					siblingInputCheckbox.removeAttr("disabled");	    			  
+				}
+			} else {
+				// This tier level is NOT a child tier. No need to look at any more checkboxes
+				isKeepLooping = false;
+			}
+		}	      
+  	}
+}
+
+function getTierDigit(tierString) {
+	var classNameDigit = tierString.substr(4, tierString.length - 4);
+    return classNameDigit;
+}
+
+function checkAllCheckboxes(item) {
+	var selectAllCheckboxItem = jQuery(item);
+	var checkBoxChecked = selectAllCheckboxItem.is(':checked');	
+	var allCheckboxes = jQuery(':checkbox');
+
+	for (var index = 1; index < allCheckboxes.length; index++) {
+		var checkboxItem = jQuery(allCheckboxes.get(index));
+		if (checkBoxChecked) {
+			checkboxItem.attr("checked", "checked");
+			checkboxItem.attr("disabled", "disabled");
+		} else {
+			checkboxItem.removeAttr("checked");
+			checkboxItem.removeAttr("disabled");
+		}
+	}
+}
+
+function passSelectedPoolIds() {
+	var allCheckboxes = jQuery(':checkbox:checked');
+	var poolIds = new Array();
+	var checkAllChecked = jQuery('input[name$=checkAllCheckbox]').is(':checked');
+	var checkboxValue;
+	
+	// If check all checked, ignore the first value;
+	if (checkAllChecked) {
+		for (var index = 0; index < (allCheckboxes.length - 1); index++) {
+			checkboxValue = jQuery(allCheckboxes.get(index + 1)).val();
+			poolIds[index] = checkboxValue;
+		}
+	} else {
+		for (var index = 0; index < allCheckboxes.length; index++) {
+			checkboxValue = jQuery(allCheckboxes.get(index)).val();
+			poolIds[index] = checkboxValue;
+		}
+	}
+	
+	var hideInput = jQuery('input[name$=transferPoolIds]');
+	hideInput.val(poolIds);
+}
+
+function checkChildrenCheckboxesDisable(item) {
+	var localItem = jQuery(item);
+	var itemChecked = localItem.is(':checked');
+	var itemParentTable = localItem.parent().parent().parent().parent().parent();
+
+	if (itemParentTable.length == 1) {
+		var itemTierClassName = itemParentTable.attr("class");
+		var itemCheckboxTierDigit = getTierDigit(itemTierClassName);
+		var itemParentTr = itemParentTable.parent().parent().parent();
+		var itemPeerTrs = itemParentTr.nextAll(); // Get all sibling tr's AFTER this tr.
+		var isKeepLooping = true;
+
+		for (var index = 0; (isKeepLooping && index < itemPeerTrs.length); index++) {
+			var siblingTr = jQuery(itemPeerTrs.get(index));
+			var siblingTierTable = siblingTr.find("table");
+			var siblingTierTableClassName = siblingTierTable.attr("class");
+			var siblingCheckboxTierDigit = getTierDigit(siblingTierTableClassName);
+
+			if (siblingCheckboxTierDigit > itemCheckboxTierDigit) {
+				var siblingInputCheckbox = siblingTierTable.find("input:checkbox");
+				if (itemChecked) {
+					siblingInputCheckbox.attr("disabled", "disabled");
+				} else {
+					siblingInputCheckbox.removeAttr("disabled");
+				}
+			} else {
+				isKeepLooping = false;
+			}
+		}	      
+	}
+}
+
+function disableCheckboxes() {
+	var allCheckboxes = jQuery(':checkbox');
+	var checkAllChecked = jQuery('input[name$=checkAllCheckbox]').is(':checked');
+
+	for (var index = 1; index < allCheckboxes.length; index++) {
+		var checkboxItem = jQuery(allCheckboxes.get(index) );
+		if (checkAllChecked) {
+			checkboxItem.attr("disabled", "disabled");
+		} else {
+			checkboxItem.removeAttr("disabled");
+		}
+	}
+	
+	var otherCheckboxes = jQuery('input[name$=radiobtn]');
+	for (var i = 0; i < otherCheckboxes.length; i++) {
+		checkChildrenCheckboxesDisable(allCheckboxes.get(i));
+	}
+}
Index: samigo-app/src/webapp/jsf/questionpool/poolList.jsp
===================================================================
--- samigo-app/src/webapp/jsf/questionpool/poolList.jsp	(revision 308089)
+++ samigo-app/src/webapp/jsf/questionpool/poolList.jsp	(working copy)
@@ -107,6 +107,14 @@
  <h:outputText value="#{questionPoolMessages.import}"/>
   <f:param name="qpid" value="0"/>
 </h:commandLink> 
+
+<!-- SAM-2049 -->
+<h:outputText value=" #{generalMessages.separator}" rendered="#{questionpool.importToAuthoring == 'false' && authorization.createQuestionPool}" />
+<h:commandLink title="#{questionPoolMessages.t_transferPool}" rendered="#{questionpool.importToAuthoring == 'false' && authorization.createQuestionPool}" 
+	id="transfer" immediate="true" action="#{questionpool.transferPool}">
+	<h:outputText value="#{questionPoolMessages.transfer_pool_ownership}" />
+	<f:param name="qpid" value="0" />
+</h:commandLink>
  
 <h:outputText rendered="#{questionpool.importToAuthoring == 'false' && authorization.createQuestionPool}" escape="false" value="</p>"/>
 </div>
Index: samigo-app/src/webapp/jsf/questionpool/transferPool.jsp
===================================================================
--- samigo-app/src/webapp/jsf/questionpool/transferPool.jsp	(revision 0)
+++ samigo-app/src/webapp/jsf/questionpool/transferPool.jsp	(working copy)
@@ -0,0 +1,57 @@
+<!-- $Id: transferPool.jsp 2012-11-10 wang58@iupui.edu -->
+
+<%@ page contentType="text/html;charset=utf-8" pageEncoding="utf-8" language="java" %>
+<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<%@ taglib uri="http://www.sakaiproject.org/samigo" prefix="samigo" %>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<f:view>
+  	<html xmlns="http://www.w3.org/1999/xhtml">
+		<head><%= request.getAttribute("html.head") %>
+			<title>
+				<h:outputText value="#{questionPoolMessages.transfer_pool}" />
+			</title>
+			                
+			<!-- stylesheet and script widgets -->
+			<script language="javascript" type="text/JavaScript">
+				<%@ include file="/js/samigotree.js" %>
+			</script>
+		
+			<script type="text/javascript" src="/library/js/jquery/jquery-1.9.1.min.js"></script>
+		</head>
+		<body onload="checkSaveButton(); disableCheckboxes();<%= request.getAttribute("html.body.onload") %>">
+			
+			<!-- content... -->
+			<div class="portletBody">
+				<h:form id="transferPool">
+					<h:messages infoClass="validation" warnClass="validation" errorClass="validation" fatalClass="validation"/>
+	
+					<h3>
+						<h:outputText value="#{questionPoolMessages.transfer_pool_ownership}"/>
+					</h3>
+					<h:inputHidden id="checkAll" value="" />
+					<h:inputHidden id="disabledCheckboxes" value="" />
+	
+					<br/>
+					<div class="tier4">
+						<h:selectBooleanCheckbox id="checkAllCheckbox" onclick="checkAllCheckboxes(this); checkSaveButton();" value="#{questionpool.checkAll}" />
+						<h:outputText value="#{questionPoolMessages.transfer_pool_select_all}" />
+					</div>
+	
+					<div class="longtext tier2">
+						<%@ include file="/jsf/questionpool/transferPoolTree.jsp" %>
+					</div>
+	
+					<p class="act">
+						<h:commandButton accesskey="#{questionPoolMessages.a_transfer}" id="transferpoolSubmit" immediate="true" 
+							value="#{questionPoolMessages.tranfer_pool_continue}" action="#{questionpool.transferPoolContinue}" styleClass="active" 
+							onclick="passSelectedPoolIds(); getDisabledCheckbox();" />
+						<h:commandButton accesskey="#{questionPoolMessages.a_cancel}" id="transferpoolCancel" value="#{questionPoolMessages.transfer_pool_cancel}" 
+							action="#{questionpool.cancelTransferPool}" immediate="true" />
+					</p>
+				</h:form>
+			</div>
+		</body>
+	</html>
+</f:view>
Index: samigo-app/src/webapp/jsf/questionpool/transferPoolConfirm.jsp
===================================================================
--- samigo-app/src/webapp/jsf/questionpool/transferPoolConfirm.jsp	(revision 0)
+++ samigo-app/src/webapp/jsf/questionpool/transferPoolConfirm.jsp	(working copy)
@@ -0,0 +1,104 @@
+<!-- $Id: transferPoolConfirm.jsp 2012-11-10 wang58@iupui.edu -->
+
+<%@ page contentType="text/html;charset=utf-8" pageEncoding="utf-8" language="java" %>
+<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<%@ taglib uri="http://www.sakaiproject.org/samigo" prefix="samigo" %>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<f:view>
+	<html xmlns="http://www.w3.org/1999/xhtml">
+		<head>
+			<%= request.getAttribute("html.head") %>
+			<title><h:outputText value="#{questionPoolMessages.transfer_pool_confirmation}" /></title>
+			<samigo:stylesheet path="/css/tool_sam.css" />
+		</head>
+		<body onload="<%= request.getAttribute("html.body.onload") %>">
+			<div class="portletBody">
+				<h:form id="transferPoolConfirm">
+					<h:messages infoClass="validation" warnClass="validation" errorClass="validation" fatalClass="validation" />
+
+					<h3>
+						<h:outputText value="#{questionPoolMessages.transfer_pool_ownership}"/>
+					</h3>
+					<p></p>
+					<div>
+						<h:outputText value="#{questionpool.confirmMessage}" />
+					</div>
+					<p></p>
+
+					<h:dataTable id="TreeTable" value="#{questionpool.transferSelectedQpools}"
+						var="pool" cellpadding="0" cellspacing="0" styleClass="listHier" >
+
+						<h:column id="col1">
+							<f:facet name="header">
+								<h:panelGroup>      
+									<h:outputText  value="#{questionPoolMessages.p_name}" />
+								</h:panelGroup>
+							</f:facet>
+							<h:panelGroup styleClass="tier#{questionpool.tree.currentLevel}"  id="firstcolumn">
+								<h:inputHidden id="rowid" value="#{questionpool.tree.currentObjectHTMLId}" />
+								<h:outputText id="poolnametext" value="#{pool.displayName}" escape="false" />
+							</h:panelGroup>
+						</h:column>
+
+						<h:column id="col2">
+							<f:facet name="header">
+								<h:panelGroup>      
+									<h:outputText  value="#{questionPoolMessages.creator}" />
+								</h:panelGroup>
+							</f:facet>
+							<h:panelGroup id="secondcolumn">
+								<h:outputText value="#{pool.ownerDisplayName}" />
+							</h:panelGroup>
+						</h:column>
+
+						<h:column id="col3">
+							<f:facet name="header">
+								<h:panelGroup>
+									<h:outputText value="#{questionPoolMessages.last_mod}" />
+								</h:panelGroup>
+							</f:facet>
+							<h:panelGroup id="thirdcolumn">
+								<h:outputText value="#{pool.lastModified}">
+									<f:convertDateTime pattern="#{generalMessages.output_date_picker}" />
+								</h:outputText>
+							</h:panelGroup>
+						</h:column>
+
+						<h:column id="col4">
+							<f:facet name="header">
+								<h:panelGroup>
+									<h:outputText value="#{questionPoolMessages.qs}" />
+								</h:panelGroup>
+							</f:facet>
+							<h:panelGroup id="fourthcolumn" >
+								<h:outputText value="#{pool.data.questionPoolItemSize}" />
+							</h:panelGroup>
+						</h:column>
+
+						<h:column id="col5">
+							<f:facet name="header">
+								<h:panelGroup>
+									<h:outputText value="#{questionPoolMessages.subps}" />
+								</h:panelGroup>
+							</f:facet>
+							<h:panelGroup id="fifthcolumn">
+								<h:outputText value="#{pool.subPoolSize}" />
+							</h:panelGroup>
+						</h:column>
+					</h:dataTable>
+
+					<p class="act">
+						<h:commandButton accesskey="#{questionPoolMessages.a_transfer}" id="transferpoolSubmit" immediate="true" 
+							value="#{questionPoolMessages.transfer_pool_ownership}" action="#{questionpool.transferPoolOwnership}" styleClass="active" />
+						<h:commandButton accesskey="#{questionPoolMessages.a_transfer_back}" id="transferpoolSubmit2" immediate="true" 
+							value="#{questionPoolMessages.transfer_pool_back}" action="#{questionpool.transferPoolConfirmBack}" styleClass="active" />
+						<h:commandButton accesskey="#{questionPoolMessages.a_cancel}" id="transferpoolCancel" value="#{questionPoolMessages.transfer_pool_cancel}" 
+							action="#{questionpool.cancelTransferPool}" immediate="true" />
+					</p>
+				</h:form>
+			</div>
+		</body>
+	</html>
+</f:view>
Index: samigo-app/src/webapp/jsf/questionpool/transferPoolInputUser.jsp
===================================================================
--- samigo-app/src/webapp/jsf/questionpool/transferPoolInputUser.jsp	(revision 0)
+++ samigo-app/src/webapp/jsf/questionpool/transferPoolInputUser.jsp	(working copy)
@@ -0,0 +1,44 @@
+<!-- $Id: transferPoolInputUser.jsp 2012-11-10 wang58@iupui.edu -->
+
+<%@ page contentType="text/html;charset=utf-8" pageEncoding="utf-8" language="java" %>
+<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<%@ taglib uri="http://www.sakaiproject.org/samigo" prefix="samigo" %>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<f:view>
+	<html xmlns="http://www.w3.org/1999/xhtml">
+		<head>
+			<%= request.getAttribute("html.head") %>
+			<title><h:outputText value="#{questionPoolMessages.transfer_pool_user}"/></title>
+		</head>
+		<body onload="<%= request.getAttribute("html.body.onload") %>">
+			<div class="portletBody">
+				<h:form id="transferPoolInputUser">
+					<h:messages infoClass="validation" warnClass="validation" errorClass="validation" fatalClass="validation"/>
+	
+					<h3>
+						<h:outputText value="#{questionPoolMessages.transfer_pool_ownership}" />
+					</h3>
+					<p></p>
+					<div class="tier2">
+						<h:outputText value="#{questionPoolMessages.transfer_pool_input_user}" />
+					</div>
+					<p></p>
+					<div class="tier3">
+						<h:inputText id="owneruserId" value="#{questionpool.ownerId}" />
+					</div>
+	
+					<p class="act">
+						<h:commandButton accesskey="#{questionPoolMessages.a_transfer}" id="transferpoolSubmit" immediate="true" 
+							value="#{questionPoolMessages.tranfer_pool_continue}" action="#{questionpool.transferPoolInputUserContinue}" styleClass="active" />
+						<h:commandButton accesskey="#{questionPoolMessages.a_transfer_back}" id="transferpoolSubmit2" immediate="true" 
+							value="#{questionPoolMessages.transfer_pool_back}" action="#{questionpool.transferPoolInputUserBack}" styleClass="active" />
+						<h:commandButton accesskey="#{questionPoolMessages.a_cancel}" id="transferpoolCancel" value="#{questionPoolMessages.transfer_pool_cancel}" 
+							action="#{questionpool.cancelTransferPool}" immediate="true" />
+					</p>
+				</h:form>
+			</div>
+		</body>
+	</html>
+</f:view>
Index: samigo-app/src/webapp/jsf/questionpool/transferPoolTree.jsp
===================================================================
--- samigo-app/src/webapp/jsf/questionpool/transferPoolTree.jsp	(revision 0)
+++ samigo-app/src/webapp/jsf/questionpool/transferPoolTree.jsp	(working copy)
@@ -0,0 +1,83 @@
+<!-- $Id: transferPoolTree.jsp 2012-11-10 wang58@iupui.edu -->
+
+<h:inputHidden id="transferPoolIds" value=""/>
+<h:dataTable id="TreeTable" value="#{questionpool.transferQpools}" var="pool" cellpadding="0" cellspacing="0" styleClass="listHier" >
+	<h:column id="col1">
+		<f:facet name="header">
+			<h:panelGroup>
+				<h:commandLink title="#{questionPoolMessages.t_sortTitle}" immediate="true" 
+					rendered="#{questionpool.sortTransferPoolProperty == 'title' && questionpool.sortTransferPoolAscending}" 
+					action="#{questionpool.sortTransferPoolByColumnHeader}">
+					<h:outputText  value="#{questionPoolMessages.p_name}" styleClass="currentSort" rendered="#{questionpool.sortTransferPoolProperty == 'title'}" />
+					<f:param name="transferPoolOrderBy" value="title" />
+					<f:param name="transferPoolAscending" value="false" />
+					<h:graphicImage alt="#{questionPoolMessages.alt_sortTitleDescending}" rendered="#{questionpool.sortTransferPoolAscending}" 
+						url="/images/sortascending.gif" />
+				</h:commandLink>
+				<h:commandLink title="#{questionPoolMessages.t_sortTitle}" immediate="true" 
+					rendered="#{questionpool.sortTransferPoolProperty == 'title' && !questionpool.sortTransferPoolAscending}" 
+					action="#{questionpool.sortTransferPoolByColumnHeader}">
+					<h:outputText  value="#{questionPoolMessages.p_name}" styleClass="currentSort" rendered="#{questionpool.sortTransferPoolProperty == 'title'}" />
+					<f:param name="transferPoolOrderBy" value="title"/>
+					<f:param name="transferPoolAscending" value="true" />
+					<h:graphicImage alt="#{questionPoolMessages.alt_sortTitleAscending}" rendered="#{!questionpool.sortTransferPoolAscending}" 
+						url="/images/sortdescending.gif"/>
+				</h:commandLink>
+			</h:panelGroup>
+		</f:facet>
+		<h:panelGroup id="firstcolumn">
+			<h:inputHidden id="rowid" value="#{questionpool.tree.currentObjectHTMLId}"/>
+			<h:selectManyCheckbox onclick="checkChildrenCheckboxes(this); checkSaveButton();" id="radiobtn"
+				value="#{questionpool.transferPools}" styleClass="tier#{questionpool.tree.currentLevel}" disabled="false">
+				<f:selectItem itemValue="#{pool.questionPoolId}" itemLabel="#{pool.displayName}" />
+			</h:selectManyCheckbox>
+		</h:panelGroup>
+	</h:column>
+
+	<h:column id="col2">
+		<f:facet name="header">
+			<h:panelGroup>      
+				<h:outputText  value="#{questionPoolMessages.creator}" />
+			</h:panelGroup>
+		</f:facet>
+		<h:panelGroup id="secondcolumn">
+			<h:outputText value="#{pool.ownerDisplayName}" />
+		</h:panelGroup>
+	</h:column>
+
+	<h:column id="col3">
+		<f:facet name="header">
+			<h:panelGroup>
+				<h:outputText value="#{questionPoolMessages.last_mod}" />
+			</h:panelGroup>
+		</f:facet>
+		<h:panelGroup id="thirdcolumn">
+			<h:outputText value="#{pool.lastModified}">
+				<f:convertDateTime pattern="#{generalMessages.output_date_picker}" />
+			</h:outputText>
+		</h:panelGroup>
+	</h:column>
+
+	<h:column id="col4">
+		<f:facet name="header">
+			<h:panelGroup>
+				<h:outputText value="#{questionPoolMessages.qs}" />
+			</h:panelGroup>
+		</f:facet>
+		<h:panelGroup id="fourthcolumn" >
+			<h:outputText value="#{pool.data.questionPoolItemSize}" />
+		</h:panelGroup>
+	</h:column>
+
+
+	<h:column id="col5">
+		<f:facet name="header">
+			<h:panelGroup>
+				<h:outputText value="#{questionPoolMessages.subps}" />
+			</h:panelGroup>
+		</f:facet>
+		<h:panelGroup id="fifthcolumn">
+			<h:outputText value="#{pool.subPoolSize}" />
+		</h:panelGroup>
+	</h:column>
+</h:dataTable>
Index: samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueries.java
===================================================================
--- samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueries.java	(revision 308089)
+++ samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueries.java	(working copy)
@@ -23,6 +23,8 @@
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -63,6 +65,9 @@
 public class QuestionPoolFacadeQueries
     extends HibernateDaoSupport implements QuestionPoolFacadeQueriesAPI {
   private static Log log = LogFactory.getLog(QuestionPoolFacadeQueries.class);
+  
+  // SAM-2049
+  private static final String VERSION_START = " - ";
 
   public QuestionPoolFacadeQueries() {
   }
@@ -1456,4 +1461,200 @@
 
 	  return agents;
   }
+  
+  // **********************************************
+  // ****************** SAM-2049 ******************
+  // **********************************************
+  
+  public List<QuestionPoolData> getAllPoolsForTransfer(final List<Long> selectedPoolIds) {  
+	  final HibernateCallback hcb = new HibernateCallback() {
+		  public Object doInHibernate(Session session) throws HibernateException, SQLException {
+			  Query q = session.createQuery("FROM QuestionPoolData a WHERE a.questionPoolId IN (:ids)");
+			  q. setParameterList("ids", selectedPoolIds);
+			  return q.list();
+		  };
+	  };
+	  List list = getHibernateTemplate().executeFind(hcb);
+	  return list;	  
+  }
+	
+  private String createQueryString(List<Long> poolIds) {
+	  String poolIdQueryString ="";
+	  String prefix = "";
+	  for (Long poolId: poolIds) {
+		  poolIdQueryString += prefix + poolId.toString();
+		  prefix = ",";
+	  }
+	  
+  	  return poolIdQueryString;
+  }
+	    
+  private void updatePool(QuestionPoolData pooldata) {
+	  try {
+		  getHibernateTemplate().update(pooldata);
+	  } catch (Exception e) {
+		  log.warn("problem update the pool name" + e.getMessage());
+	  }	  
+  }
+  
+  private String renameDuplicate(String title) {
+	  if (title == null) {
+		  title = "";
+	  }
+  
+	  String rename = "";
+	  int index = title.lastIndexOf(VERSION_START);
+
+	  // If it is versioned
+	  if (index > -1) {
+		  String mainPart = "";
+		  String versionPart = title.substring(index);
+		  if(index > 0) {
+			  mainPart = title.substring(0, index);
+		  }
+  
+		  int nIndex = index + VERSION_START.length();
+		  String version = title.substring(nIndex);
+  
+		  int versionNumber = 0;
+		  try {
+			  versionNumber = Integer.parseInt(version);
+			  if (versionNumber < 2) {
+				  versionNumber = 2;
+			  }
+			  versionPart = VERSION_START + (versionNumber + 1);
+  			  rename = mainPart + versionPart;
+  		  } catch (NumberFormatException ex) {
+  			  rename = title + VERSION_START + "2";
+  		  }
+	  } else {
+		  rename = title + VERSION_START + "2";
+	  }
+
+	  return rename;
+  }
+	  
+  public void transferPoolsOwnership(String ownerId, final List<Long> transferPoolIds) {
+  	  Session session = null;
+  	  Connection conn = null;
+  	  PreparedStatement statement = null;
+  
+  	  // Get all pools to be transferred
+  	  List<QuestionPoolData> transferPoolsData = getAllPoolsForTransfer(transferPoolIds);
+  
+  	  // Get poolId which need to remove child-parent relationship
+  	  List<Long> needUpdatedPoolParentIdList = new ArrayList<Long>();
+  	  List<Long> updatePoolOwnerIdList = new ArrayList<Long>();
+  
+  	  for (QuestionPoolData poolTransfer : transferPoolsData) {
+  		  Long poolId = poolTransfer.getQuestionPoolId();	
+  		  updatePoolOwnerIdList.add(poolId);
+  		  
+  		  // Get remove child-parent relationship list
+  		  Long poolIdRemoveParent = poolTransfer.getParentPoolId();
+  		  if (!poolIdRemoveParent.equals(new Long("0")) && !transferPoolIds.contains(poolIdRemoveParent)) {
+  			  needUpdatedPoolParentIdList.add(poolId);
+  		  }
+  	  }
+  
+  	  // updatePoolOwnerIdList will not be empty, so no need to check the size
+  	  String updateOwnerIdInPoolTableQueryString = createQueryString(updatePoolOwnerIdList);
+  
+  	  // If all parent-children structure transfer, needUpdatedPoolParentIdList will be empty.	  
+  	  String removeParentPoolString = "";
+  	  if (needUpdatedPoolParentIdList.size() > 0) {
+  		  removeParentPoolString = createQueryString(needUpdatedPoolParentIdList);
+  	  }
+  
+  	  // I used jdbc update here since I met difficulties using hibernate to update SAM_QUESTIONPOOLACCESS_T. (it used composite-id there)
+  	  // For updating SAM_QUESTIONPOOL_T, I can use hibernate but it will have many db calls. (I didn't find an efficient way to bulk update.) So used jdbc here again.
+  	  try {
+  		  session = getSessionFactory().openSession();
+  		  conn = session.connection();
+                  boolean autoCommit = conn.getAutoCommit();
+  		  String query = "";
+  		  if (!"".equals(updateOwnerIdInPoolTableQueryString)) {
+  			  query = "UPDATE sam_questionpoolaccess_t SET agentid = '" + ownerId +"' WHERE questionpoolid IN (" + updateOwnerIdInPoolTableQueryString + ")" + 
+  					  " AND accesstypeid = 34";					 
+  			  statement = conn.prepareStatement(query);
+  			  statement.executeUpdate();
+  			  
+  			  query = "UPDATE sam_questionpool_t SET ownerid = '" + ownerId + "' WHERE questionpoolid IN (" + updateOwnerIdInPoolTableQueryString + ")";
+			  statement = conn.prepareStatement(query);
+			  statement.executeUpdate();
+                          
+                          if (!autoCommit) {
+                              conn.commit();
+                          }
+  		  }
+  
+  		  // if the pool has parent but the parent doesn't transfer, need to remove the child-parent relationship.
+  		  if (!"".equals(removeParentPoolString)) {
+  			  query = "UPDATE sam_questionpool_t SET parentpoolid = " + 0 + " WHERE questionpoolid IN (" + removeParentPoolString + ")";
+  			  statement = conn.prepareStatement(query);
+  			  statement.executeUpdate();	
+                          
+                          if (!autoCommit) {
+                              conn.commit();
+                          }
+  		  }
+  	  } catch (Exception ex) {
+  		  log.warn(ex.getMessage());
+	  } finally {
+  		  if (statement != null) {
+			  try {
+				  statement.close();
+			  } catch (Exception ex) {
+				  ex.printStackTrace();
+			  }
+		  }
+  		  
+  		  if (conn != null) {
+			  try {
+				  conn.close();
+			  } catch (Exception ex) {
+				  ex.printStackTrace();
+			  }
+		  }
+  		  
+  		  if (session != null) {
+  			  try {
+  				  session.close();
+			  } catch (Exception ex) {
+				  ex.printStackTrace();
+			  }
+  		  }
+  	  }
+  
+  	  // Update pool name if there is a duplicate one.	  
+	  for (QuestionPoolData pooldata : transferPoolsData) {
+		  Long poolId = pooldata.getQuestionPoolId();
+		  String title = pooldata.getTitle();
+		  boolean isUnique = poolIsUnique(poolId, title, new Long("0"), ownerId);
+		  if (!isUnique) {
+			  synchronized (title) {
+				  log.debug("Questionpool " + title + " is not unique.");
+				  int count = 0; // Alternate exit condition
+	
+				  while (!isUnique) {
+					  title = renameDuplicate(title);
+					  log.debug("renameDuplicate (title): " + title);
+					  
+					  // Recheck to confirm that new title is not a dplicate too
+					  isUnique = poolIsUnique(poolId, title, new Long("0"), ownerId);	      	  
+					  if (count++ > 99) {
+						  break; // Exit condition in case bug is introduced
+					  }
+				  }
+			  }
+			  
+			  pooldata.setTitle(title);
+			  pooldata.setOwnerId(ownerId);
+			  if (!"".equals(removeParentPoolString) && needUpdatedPoolParentIdList.contains(poolId)) {
+				  pooldata.setParentPoolId(new Long("0"));
+			  }
+			  updatePool(pooldata);
+		  }		  
+	  } 	  
+  }
 }
Index: samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueriesAPI.java
===================================================================
--- samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueriesAPI.java	(revision 308089)
+++ samigo-services/src/java/org/sakaiproject/tool/assessment/facade/QuestionPoolFacadeQueriesAPI.java	(working copy)
@@ -221,5 +221,8 @@
   public void removeQuestionPoolAccess(Tree tree, String user, Long questionPoolId, Long accessTypeId);   
 
   public List<AgentFacade> getAgentsWithAccess(final Long questionPoolId);
+  
+  //SAM-2049
+  public void transferPoolsOwnership(String ownerId, List<Long> poolIds);
 
 }
Index: samigo-services/src/java/org/sakaiproject/tool/assessment/services/QuestionPoolService.java
===================================================================
--- samigo-services/src/java/org/sakaiproject/tool/assessment/services/QuestionPoolService.java	(revision 308089)
+++ samigo-services/src/java/org/sakaiproject/tool/assessment/services/QuestionPoolService.java	(working copy)
@@ -595,4 +595,14 @@
 
 	  return agents;
   }
+  
+  // SAM-2049
+  public void transferPoolsOwnership(String ownerId, List<Long> poolIds) {
+	  try {
+		  PersistenceService.getInstance().getQuestionPoolFacadeQueries().transferPoolsOwnership(ownerId, poolIds);
+	  } catch (Exception ex) {
+		  log.error(ex);
+		  throw new RuntimeException(ex);
+	  }
+  }
 }
