/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/sam/trunk/samigo-app/src/java/org/sakaiproject/tool/assessment/business/questionpool/QuestionPoolTreeImpl.java $
* $Id: QuestionPoolTreeImpl.java 106463 2012-04-02 12:20:09Z david.horwitz@uct.ac.za $
***********************************************************************************
*
* Copyright (c) 2004, 2005, 2006, 2008, 2009 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.tool.assessment.business.questionpool;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osid.shared.SharedException;
import org.sakaiproject.tool.assessment.data.dao.questionpool.QuestionPoolData;
import org.sakaiproject.tool.assessment.data.model.Tree;
import org.sakaiproject.tool.assessment.facade.QuestionPoolFacade;
import org.sakaiproject.tool.assessment.facade.QuestionPoolIteratorFacade;
import org.sakaiproject.tool.assessment.util.BeanSort;
//import org.sakaiproject.tool.assessment.osid.shared.impl.IdImpl;
//import osid.shared.*;
// import org.osid.shared.Id; // should only use Long for id.
/**
* DOCUMENTATION PENDING
*
* @author $author$
* @version $Id: QuestionPoolTreeImpl.java 106463 2012-04-02 12:20:09Z david.horwitz@uct.ac.za $
*/
public class QuestionPoolTreeImpl
implements Tree
{
/**
*
*/
private static final long serialVersionUID = 2173986944623441011L;
private static Log log = LogFactory.getLog(QuestionPoolTreeImpl.class);
private HashMap poolMap;
private HashMap poolFamilies;
private Long currentPoolId;
private String currentObjectHTMLId;
private String currentLevel;
private String sortString = "lastModified";
public QuestionPoolTreeImpl()
{
poolMap = new HashMap();
poolFamilies = new HashMap();
}
/**
* Constucts the representation of the tree of pools.
* @param iter QuestionPoolIteratorFacade for the pools in question
*/
public QuestionPoolTreeImpl(QuestionPoolIteratorFacade iter)
{
// this is a table of pools by Id
poolMap = new HashMap();
// this is a cross reference of pool ids by parent id
// the pool ids in an Arraylist where the key is parent id
poolFamilies = new HashMap();
try
{
while(iter.hasNext())
{
QuestionPoolFacade pool = (QuestionPoolFacade) iter.next();
Long parentId = pool.getParentPoolId();
Long poolId = pool.getQuestionPoolId();
poolMap.put(poolId.toString(), pool);
ArrayList childList = new ArrayList();
if(poolFamilies.containsKey(parentId.toString()))
{
childList = (ArrayList) poolFamilies.get(parentId.toString());
}
childList.add(poolId);
poolFamilies.put(parentId.toString(), childList);
}
// Now sort the sibling lists.
Iterator iter2 = poolFamilies.keySet().iterator();
while(iter2.hasNext())
{
String key = (String) iter2.next();
Iterator children = ((ArrayList) poolFamilies.get(key)).iterator();
Collection sortedList = new ArrayList();
while(children.hasNext())
{
QuestionPoolFacade pool =
(QuestionPoolFacade) poolMap.get(children.next().toString());
sortedList.add(pool.getData());
}
BeanSort sort = new BeanSort(sortedList, sortString);
sortedList = sort.sort();
ArrayList ids = new ArrayList();
Iterator siblings = sortedList.iterator();
while(siblings.hasNext())
{
QuestionPoolData next = null;
try {
next = (QuestionPoolData) siblings.next();
if (poolMap != null) {
// Add at 0 because we want a reverse list.
if ("lastModified".equals(sortString)){
ids.add(0, ((QuestionPoolFacade) poolMap.get(next.getQuestionPoolId().toString())).getQuestionPoolId());
}
// Add to the end of list if not sorted by lastModified.
else {
ids.add(((QuestionPoolFacade) poolMap.get(next.getQuestionPoolId().toString())).getQuestionPoolId());
}
}
else {
log.error("poolMap is null");
}
} catch (RuntimeException e) {
log.error("Couldn't get ID " + next.getQuestionPoolId());
}
}
poolFamilies.put(key, ids);
}
}
catch (SharedException se)
{
se.printStackTrace();
}
catch(RuntimeException e)
{
e.printStackTrace();
}
}
/**
* Get a List of pools having parentId as parent
* @param parentId the Id of the parent pool
* @return a List with the Ids of all momma's children
*/
public List getChildList(Long parentId)
{
if(! poolFamilies.containsKey(parentId.toString()))
{
return new ArrayList();
}
return (ArrayList) poolFamilies.get(parentId.toString());
}
/**
* Get a List of top level pools.
* @return List of top level pool id strings
*/
public List getRootNodeList()
{
try
{
return getChildList(new Long("0"));
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
/**
* Get the object we're currently looking at.
*
* @return Current QuestionPool.
*/
public Object getCurrentObject()
{
return poolMap.get(currentPoolId.toString());
}
/**
* Get the parent of the object we're currently looking at.
*
* @return The parent pool of the current object, or null if
* it's a root node.
*/
public Object getParent()
{
if(currentPoolId == null)
{
return null;
}
QuestionPoolFacade current = (QuestionPoolFacade) getCurrentObject();
try
{
return (poolMap.get(current.getParentPoolId().toString()));
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
public void setCurrentObjectHTMLId(String param)
{
currentObjectHTMLId = param;
}
/**
* Get the HTML id of the current object.
*
* @return An HTML representation of the pool Id.
*/
public String getCurrentObjectHTMLId()
{
QuestionPoolFacade current = (QuestionPoolFacade) getCurrentObject();
try
{
QuestionPoolFacade parent = (QuestionPoolFacade) getParent();
if(parent == null)
{
Collection childList = getChildList(new Long("0"));
return Integer.toString(
((ArrayList) childList).indexOf(
((QuestionPoolFacade) getCurrentObject()).getQuestionPoolId()) + 1);
}
else
{
setCurrentId(current.getParentPoolId());
String result = getCurrentObjectHTMLId();
Collection childList = getChildList(parent.getQuestionPoolId());
setCurrentId(current.getQuestionPoolId());
return result + "-" +
(
((ArrayList) childList).indexOf(
((QuestionPoolFacade) getCurrentObject()).getQuestionPoolId()) + 1
);
}
}
catch(RuntimeException e)
{
e.printStackTrace();
return "0";
}
}
/**
* Get the current level.
*
* @return A String that represents the level we're on (1 is root node,
* 2 is first level child, etc..
*/
public String getCurrentLevel()
{
int index1 = 1;
QuestionPoolFacade current = (QuestionPoolFacade) getCurrentObject();
try
{
while(! current.getParentPoolId().toString().equals("0"))
{
current = (QuestionPoolFacade) poolMap.get(current.getParentPoolId().toString())
;
index1++;
}
//QuestionPoolFacade parent = (QuestionPoolFacade) getParent();
}
catch(Exception e)
{
e.printStackTrace();
return "0";
}
return Integer.toString(index1);
}
/**
* Return in order the current:<ul>
* <li> Pool Name
* <li> Author
* <li> Last Modified
* <li> Total # of Questions
* <li> Total # of Subpools
*/
public Collection getCurrentObjectProperties()
{
Collection properties = new ArrayList();
/*
// not used anymore,
if(currentPoolId == null)
{
properties.add("Pool Name");
properties.add("Author");
properties.add("Last Modified");
properties.add("Total # of Questions");
properties.add("Total # of Subpools");
}
else
{
try
{
QuestionPoolFacade pool = (QuestionPoolFacade) getCurrentObject();
QuestionPoolData props = (QuestionPoolData) pool.getData();
if(props == null)
{
props = new QuestionPoolData();
}
//properties.add(pool.getDisplayName());
// commenting the following temporarily because getOwner is null - daisyf (9/19/04)
properties.add(props.getOwner().getDisplayName());
if(props.getLastModified() != null)
{
// SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
// properties.add(sdf.format(props.getLastModified()));
properties.add(props.getLastModified());
}
else
{
properties.add("N/A");
}
if(props.getQuestions() != null)
{
properties.add(new Integer(props.getQuestions().size()).toString());
}
else
{
properties.add("0");
}
if(getChildren(currentPoolId) != null)
{
properties.add(
new Integer(getChildren(currentPoolId).size()).toString());
}
else
{
properties.add("0");
}
}
catch(Exception e)
{
e.printStackTrace();
throw new RuntimeException(e);
}
}
*/
return properties;
}
/**
* Set the properties to request. Not needed here.
*/
public void setPropertyMethods(String[] methods)
{
}
/**
* Get Map of QuestionPoolImpls.
* @return Map of all QuestionPoolImpls
*/
public Map getAllObjects()
{
return poolMap;
}
/**
* Dump the tree into a long collection of objects of the form:<ul>
* <li> Pool 1
* <ul> <li> Pool 2
* <ul> <li> Pool 3
* <li> Pool 4
* </ul><li> Pool 5
*
*/
public Collection getSortedObjects()
{
Collection total = new ArrayList();
try
{
addChildren(total, new Long("0"));
}
catch(Exception e)
{
e.printStackTrace();
throw new RuntimeException(e);
}
return total;
}
/**
* get sorted objects for a subpool tree
*/
public Collection getSortedObjects(Long poolId)
{
Collection total = new ArrayList();
try
{
addChildren(total, poolId);
}
catch(Exception e)
{
e.printStackTrace();
throw new RuntimeException(e);
}
return total;
}
/**
* Auxiliary method for recursion.
*/
private void addChildren(Collection total, Long parentId)
{
List childList = getChildList(parentId);
if(childList.isEmpty())
{
return;
}
Iterator iter = childList.iterator();
while(iter.hasNext())
{
Long nextId = (Long) iter.next();
total.add(poolMap.get(nextId.toString()));
addChildren(total, nextId);
}
}
/**
* Get Map of QuestionPoolImpls retricted to a given
* Parent Id string
* @param parentId parent of all returned children
* @return a Map of QuestionPoolImpls that are childen
*/
public Map getChildren(Long parentId)
{
HashMap childPool = new HashMap();
List childList = getChildList(parentId);
Iterator children = childList.iterator();
while(children.hasNext())
{
Long poolId = (Long) children.next();
childPool.put(poolId.toString(), poolMap.get(poolId.toString()));
}
return childPool;
}
/**
* Get Map of QuestionPoolImpls retricted to childeren of the currently
* selected pool Id string
* @return a Map of QuestionPoolImpls that are children
*/
public Map getChildren()
{
return getChildren(getCurrentId());
}
/**
* Obtain the poolId set as the current working poolId-designated node
* @return the current working poolId String
*/
public Long getCurrentId()
{
return currentPoolId;
}
/**
* Set the current working poolId String, from which context relative
* child lists are calculated from the poolId-designated node
* @param poolId
*/
public void setCurrentId(Long poolId)
{
currentPoolId = poolId;
}
/**
* Determine if the pool has childeren
* @return true if it has children
*/
public boolean currentObjectIsParent()
{
return poolFamilies.containsKey(getCurrentId().toString());
}
/**
* List the child pool id strings
* @return a list of children's pool id strings
*/
public List getChildList()
{
return getChildList(getCurrentId());
}
/**
* @return true if childlist is not empty, false otherwise
*/
public boolean getHasChildList(){
if (this.getChildList().isEmpty()) {
return false;
}
else {
return true;
}
}
public boolean getHasNoChildList(){
if (this.getChildList().isEmpty()) {
return true;
}
else {
return false;
}
}
/**
* This gets the property by which siblings will be sorted.
*
* @return A String representation of the sort property.
*/
public String getSortProperty()
{
return sortString;
}
/**
* This sets the property by which siblings will be sorted.
*/
public void setSortProperty(String newProperty)
{
sortString = newProperty;
}
public void sortByProperty(String sortProperty, boolean sortAscending)
{
// Now sort the sibling lists.
Iterator iter2 = poolFamilies.keySet().iterator();
while(iter2.hasNext())
{
String key = (String) iter2.next();
Iterator children = ((ArrayList) poolFamilies.get(key)).iterator();
ArrayList sortedList = new ArrayList();
while(children.hasNext())
{
QuestionPoolFacade pool =
(QuestionPoolFacade) poolMap.get(children.next().toString());
sortedList.add(pool.getData());
}
BeanSort sort = new BeanSort(sortedList, sortProperty);
if ("lastModified".equals(sortProperty))
{
sort.toDateSort();
}
else
{
sort.toStringSort();
}
sort.sort();
if (!sortAscending)
{
Collections.reverse(sortedList);
}
ArrayList ids = new ArrayList();
Iterator siblings = sortedList.iterator();
while(siblings.hasNext())
{
QuestionPoolData next = null;
try {
next = (QuestionPoolData) siblings.next();
if (next != null) {
// Add at 0 because we want a reverse list.
if ("lastModified".equals(sortProperty)){
ids.add(0, ((QuestionPoolFacade) poolMap.get(next.getQuestionPoolId().toString())).getQuestionPoolId());
}
else {
// Add at the end , if not sorted by lastModified.
ids.add(((QuestionPoolFacade) poolMap.get(next.getQuestionPoolId().toString())).getQuestionPoolId());
}
}
else {
log.error("next is null");
}
} catch (RuntimeException e) {
log.error("Couldn't get ID " + next.getQuestionPoolId());
}
}
poolFamilies.put(key, ids);
}
}
/**
* THis checks to see if given two pools have a common ancestor
*/
public boolean haveCommonRoot(Long poolIdA,Long poolIdB)
{
try{
Long rootA=poolIdA;
Long rootB=poolIdB;
QuestionPoolFacade tempPool=(QuestionPoolFacade)poolMap.get(rootA.toString());
while(tempPool!=null){
if((tempPool.getParentPoolId()==null)||(((tempPool.getParentPoolId()).toString()).equals("0"))){
tempPool=null;
}else{
rootA = tempPool.getParentPoolId();
tempPool = (QuestionPoolFacade)poolMap.get(rootA.toString());
}
}
tempPool=(QuestionPoolFacade)poolMap.get(rootB.toString());
while(tempPool!=null){
if((tempPool.getParentPoolId()==null)||(((tempPool.getParentPoolId()).toString()).equals("0"))){
tempPool=null;
}else{
rootB = tempPool.getParentPoolId();
tempPool = (QuestionPoolFacade)poolMap.get(rootB.toString());
}
}
return rootA.equals(rootB);
}
catch(Exception e){
e.printStackTrace();
return false;
}
}
/**
* Is a pool (pool A) a descendant of the other (Pool B)?
*/
public boolean isDescendantOf(Long poolA,Long poolB)
{
try{
Long tempPoolId = poolA;
while((tempPoolId !=null)&&(tempPoolId.toString().compareTo("0")>0)){
QuestionPoolFacade tempPool = (QuestionPoolFacade)poolMap.get(tempPoolId.toString());
if(tempPool.getParentPoolId().toString().compareTo(poolB.toString())==0) return true;
tempPoolId = tempPool.getParentPoolId();
}
return false;
}catch(Exception e){
e.printStackTrace();
return false;
}
}
/**
* This returns the level of the pool inside a pool tree, Root being 0.
*/
public int poolLevel(Long poolId){
try{
Long rootId=poolId;
int level=0;
QuestionPoolFacade tempPool=(QuestionPoolFacade)poolMap.get(rootId.toString());
while(tempPool!=null){
if((tempPool.getParentPoolId()==null)||(((tempPool.getParentPoolId()).toString()).equals("0"))){
tempPool=null;
}else{
level++;
rootId = tempPool.getParentPoolId();
tempPool = (QuestionPoolFacade)poolMap.get(rootId.toString());
}
}
return level;
}catch(Exception e){
e.printStackTrace();
return 0;
}
}
}