/********************************************************************************** * $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; } } }