package net.sf.egonet.model;
import java.util.ArrayList;
import java.util.TreeMap;
import java.util.List;
import net.sf.egonet.persistence.DB;
import net.sf.egonet.persistence.Presets;
import net.sf.egonet.persistence.AnswerLists;
/**
* TitleAndStudy is a convenience class for tracking
* lists of answers by title and study ID.
* Once this data is in the database much of the
* logic will likely be refactored to do filters
* using Hibernate SQL commands
* TODO : this could be replaced by the more general
* purpose NameAndValue class.
*/
class TitleAndStudy implements Comparable<TitleAndStudy> {
String title;
Long studyId;
TitleAndStudy ( String title, Long studyId ) {
this.title = title;
this.studyId = studyId;
}
public void setTitle ( String title ) {
this.title = title;
}
public String getTitle() { return(title);}
public void setStudyId( Long studyId ) {
this.studyId = studyId;
}
public Long getStudyId() { return(studyId);}
public boolean isForStudyId ( Long studyId) {
return (this.studyId.equals(studyId));
}
public String toString() {
return ( title + " " + studyId);
}
public int compareTo( TitleAndStudy that ) {
int iRetval;
iRetval = title.compareTo(that.title);
if ( iRetval==0)
iRetval = studyId.compareTo(that.studyId);
return(iRetval);
}
}
/* ******************************************************** */
/* main public class, AnswerListMgr */
/* ******************************************************** */
public class AnswerListMgr extends Entity {
// private class AnswerListIterator implements Iterator<AnswerList> {
// String[] strTitles;
// int index;
//
// /**
// * inner class Iterator so the outside world can step
// * through all the AnswerLists with ease
// * @param sID identifies the study to work with
// */
// AnswerListIterator( Long sID) {
// strTitles = getTitles ( sID);
// index = 0;
// }
//
// public boolean hasNext() {
// return(index<strTitles.length);
// }
//
// public AnswerList next() {
// AnswerList retList = answerListTree.get(strTitles[index]);
// ++index;
// return(retList);
// }
//
// public void remove() {} // not implemented
// }
//
/**
* this will maintain two very similar data structures.
* answerListTree will be used during the creation and
* editting of lists of preset answers,
* answerLists will be used when editting the questions
* themselves
*/
private static Long studyId;
private static TreeMap<TitleAndStudy,AnswerList> answerListTree;
private static TreeMap<String,NameAndValue[]> answerLists;
private static TreeMap<String,String[]> originalPresets;
private static boolean needsUpdate;
/**
* simple loads all the answer lists for a specified study
* @param sId identifyes the study
* @return
*/
public static boolean loadAnswerListsForStudy ( Long sId) {
boolean bListsLoaded = true;
List<AnswerList> listAnswerLists = null;
TitleAndStudy titleAndStudy;
studyId = sId;
try {
listAnswerLists = AnswerLists.getAnswerListsUsingStudy(studyId);
} catch ( Exception e) {
System.out.println ( "exception thrown from Answerists.getAnswerListsUsingStudy");
e.printStackTrace();
bListsLoaded = false;
}
if ( listAnswerLists==null || !bListsLoaded || listAnswerLists.isEmpty()) {
System.out.println ("Initializing using initFromPresets");
initFromPresets();
return(true);
}
answerListTree = new TreeMap<TitleAndStudy,AnswerList>();
answerLists = new TreeMap<String,NameAndValue[]>();
for ( AnswerList answerList : listAnswerLists ) {
titleAndStudy = new TitleAndStudy ( answerList.getListName() , studyId);
answerListTree.put(titleAndStudy, answerList);
}
update();
needsUpdate = false;
return(bListsLoaded);
}
/**
* when a study is first started it will have no lists of
* preset Answer Options, this will create an initial list
*/
private static void initFromPresets() {
String[] listPresetTitles;
TitleAndStudy titleAndStudy;
AnswerList answerList;
originalPresets = Presets.get();
listPresetTitles = new String[originalPresets.size()];
listPresetTitles = originalPresets.keySet().toArray(listPresetTitles);
// from the originalPresets, consisting of arrays of strings
// keyed by a string name, create answerLists which will have
// arrays of (strings+Integers) keyed by a string name, the
// integers getting default values
answerLists = new TreeMap<String,NameAndValue[]>();
for ( String strTitle : listPresetTitles ) {
answerLists.put(strTitle, NameAndValue.createArray(originalPresets.get(strTitle)));
}
answerListTree = new TreeMap<TitleAndStudy,AnswerList>();
for ( String strTitle : listPresetTitles ) {
answerList = new AnswerList ( strTitle, studyId, answerLists.get(strTitle));
titleAndStudy = new TitleAndStudy (strTitle, studyId );
answerListTree.put(titleAndStudy, answerList);
}
needsUpdate = false;
}
/**
* this first set of functions deal with allowing the outside world
* to edit this data.
* First, functions that deal with the names of the lists available
*/
/**
* returns a list of the titles ( names assigned to lists of preset
* answers for Selection and Multiple Selection questions )
* @param studyId id of the study we are dealing with
* @return Array of string for use in the GUI
*/
public static String[] getTitles ( Long studyId) {
ArrayList<String> workArray;
String[] retArray;
workArray = getTitlesAsList(studyId);
retArray = new String[workArray.size()];
retArray = workArray.toArray(retArray);
return(retArray);
}
/**
* returns the list of titles as an array list
* @param studyId identifies the study
* @return ArrayList of titles ( names of preset answer groups )
*/
public static ArrayList<String> getTitlesAsList ( Long studyId) {
ArrayList<String> workArray = new ArrayList<String>();
for ( TitleAndStudy tas : answerListTree.keySet()) {
if ( tas.isForStudyId(studyId))
workArray.add(tas.getTitle());
}
return(workArray);
}
/**
* simply returns the index of title/studyId within
* the answerTreeList
* @param strTitle title we are looking for
* @param studyId id of study we are dealing with
* @return
*/
private static int indexOf ( String strTitle, Long studyId ) {
int index = 0;
for ( TitleAndStudy tas : answerListTree.keySet()) {
if ( tas.isForStudyId(studyId)) {
if (tas.getTitle().equals(strTitle))
return(index);
++index;
}
}
return(index);
}
/**
* removes a title from the data structure
* @param strTitle title of the list to remove
* @param studyId id of the study we are dealing with
* @return true if the title is removed false if it is not in the list
*/
public static int removeTitle ( String strTitle, Long studyId ) {
TitleAndStudy titleAndStudy = new TitleAndStudy (strTitle, studyId );
AnswerList answerListToRemove;
int index = -1;
if ( answerListTree.containsKey(titleAndStudy)) {
index = indexOf ( strTitle, studyId);
answerListToRemove = answerListTree.get(titleAndStudy);
answerListToRemove.setActive(false);
DB.save(answerListToRemove); // needed to save the active=false flag
answerListTree.remove(titleAndStudy);
needsUpdate = true;
}
return(index);
}
/**
* adds a title ( and hence a new, empty AnswerList ) to
* the data structure
* @param strTitle title of the new list
* @param studyId id of the study we are dealing with
* @return true if the title is a new one and it is added,
* false otherwise
*/
public static boolean addTitle ( String strTitle, Long studyId ) {
TitleAndStudy titleAndStudy = new TitleAndStudy (strTitle, studyId );
AnswerList answerList;
if ( answerListTree.containsKey(titleAndStudy)) {
return(false);
}
answerList = new AnswerList ( strTitle, studyId);
answerListTree.put(titleAndStudy, answerList);
needsUpdate = true;
return(true);
}
/**
* now the functions that deal with adding/removing option names
* from specific lists
*/
/**
* returns all the option names (pre-created lists of answers for Selection
* and Multiple Selection questions) for a given title and studyId
*/
public static NameAndValue[] getOptionNames ( String strTitle, Long studyId ) {
TitleAndStudy titleAndStudy = new TitleAndStudy (strTitle, studyId );
AnswerList answerList;
answerList = answerListTree.get(titleAndStudy);
if ( answerList==null ) {
System.out.println ( titleAndStudy + " not found in AnswerListMgr.getOptionNames");
return(new NameAndValue[0]);
}
return(answerList.getListOptionNames());
}
/**
* returns the list of name/value pairs as an Arraylist
* @param strTitle the name of the group
* @param studyId identifies the study we are interested in
* @return arraylist of name/value answer pairs
*/
public static ArrayList<NameAndValue> getOptionNamesAsList (String strTitle, Long studyId ) {
NameAndValue[] optionNames = getOptionNames(strTitle,studyId);
ArrayList<NameAndValue> retList = new ArrayList<NameAndValue>(optionNames.length);
for ( NameAndValue str:optionNames) {
retList.add(str);
}
return(retList);
}
/**
* adds a new string to the list of option names
* @param strTitle title of the list of options we are dealing with
* @param studyId id of the study we are dealing with
* @param optionName the option name within the list we are dealing with
* @param optionValue the value we want the option to have
* @return true if any changes take place
*/
public static boolean addOptionName ( String strTitle, Long studyId,
String optionName, Integer optionValue ) {
TitleAndStudy titleAndStudy = new TitleAndStudy (strTitle, studyId );
AnswerList answerList;
ArrayList<NameAndValue> strList;
answerList = answerListTree.get(titleAndStudy);
if ( answerList==null ) {
System.out.println ( titleAndStudy + " not found in AnswerListMgr.addOptionName");
return(false);
}
strList = answerList.getListOptionNamesAsList();
if ( strList.contains(optionName))
return(false);
strList.add(new NameAndValue(optionName, optionValue));
answerList.setListOptionNamesFromList(strList);
needsUpdate = true;
return(true);
}
/**
* lets the user remove an option name from the list
* @param strTitle title of the list of options we are dealing with
* @param studyId id of the study we are dealing with
* @param optionName the option name within the list we are dealing with
* @param newName the new value of the option name
* @return true if any changes take place
*/
public static boolean removeOptionName ( String strTitle, Long studyId,
String optionName, Integer optionValue ) {
TitleAndStudy titleAndStudy = new TitleAndStudy (strTitle, studyId );
AnswerList answerList;
answerList = answerListTree.get(titleAndStudy);
if ( answerList==null ) {
System.out.println ( titleAndStudy + " not found in AnswerListMgr.removeOptionName");
return(false);
}
answerList.removeNameAndValue(optionName, optionValue);
needsUpdate = true;
return(true);
}
/**
* lets the user change an option name
* @param strTitle title of the list of options we are dealing with
* @param studyId id of the study we are dealing with
* @param optionName the option name within the list we are dealing with
* @param newName the new value of the option name
* @return true if any changes take place
*/
public static boolean replaceOptionName ( String strTitle, Long studyId,
String optionName, Integer optionValue, String newName, Integer newValue ) {
boolean retVal = false;
TitleAndStudy titleAndStudy = new TitleAndStudy (strTitle, studyId );
AnswerList answerList;
// special check, if the new name == the old name
// don't need to do anything
if ( optionName.equals(newName) && optionValue.equals(newValue))
return(retVal);
answerList = answerListTree.get(titleAndStudy);
if ( answerList==null ) {
System.out.println ( titleAndStudy + " not found in AnswerListMgr.replaceOptionName");
return(retVal);
}
retVal = answerList.replaceNameAndValue(optionName, optionValue, newName, newValue);
needsUpdate = true;
return(retVal);
}
/**
* used to allow the user to rearrange a list of option names. They can move
* a string up in the list
* @param strTitle title of the list of options we are dealing with
* @param studyId id of the study we are dealing with
* @param optionName the option name within the list we are dealing with
* @return true if any changes take place
*/
public static boolean moveOptionNameUp ( String strTitle, Long studyId,
String optionName, Integer optionValue ) {
TitleAndStudy titleAndStudy = new TitleAndStudy (strTitle, studyId );
AnswerList answerList;
answerList = answerListTree.get(titleAndStudy);
if ( answerList==null ) {
System.out.println ( titleAndStudy + " not found in AnswerListMgr.moveOptionNameUp");
return(false);
}
answerList.moveUp( optionName, optionValue);
needsUpdate = true;
return(true);
}
/**
* takes care of creating the usable TreeMap
*/
private static void update() {
AnswerList answerList;
answerLists.clear();
for ( TitleAndStudy tas : answerListTree.keySet()) {
answerList = answerListTree.get(tas);
answerLists.put(tas.getTitle(), answerList.getListOptionNames());
}
}
/**
* now the non-editting functions,
* for when this data is used to help construct questions
* this is used in the editquestion page as a drop-in
* replacement for the old presets.
*/
public static TreeMap<String,NameAndValue[]> get() {
if (needsUpdate)
update();
return(answerLists);
}
/**
* save all the preset answer lists data for this study
* @param studyId identifies the study
* @return true if all goes well, false if things go bad-wrong
*/
public static boolean saveAllAnswerListsForStudy(Long studyId) {
boolean bRetVal = true;
TitleAndStudy titleAndStudy;
String[] strTitles = getTitles ( studyId);
AnswerList answerList;
for ( String str:strTitles ) {
titleAndStudy = new TitleAndStudy (str, studyId );
answerList = answerListTree.get(titleAndStudy);;
try {
DB.save(answerList);
} catch ( org.hibernate.MappingException me ) {
me.printStackTrace();
bRetVal = false;
}
}
return(bRetVal);
}
/**
* returns the contents of the answerListTree as an Array
* so they can be processed sequentially quickly.
* Used in the Archiving to XML section
* @param sID identifies the study to save
* @return Array of all answerLists
*/
public static AnswerList[] getAnswerLists(Long sID) {
AnswerList[] returnArray;
loadAnswerListsForStudy (sID);
returnArray = new AnswerList[answerListTree.size()];
returnArray = answerListTree.values().toArray(returnArray);
return(returnArray);
}
/**
* outside world can use this to deal with answerLists without
* dealing with the internals of how things are stored.
*
* @param sID study ID we are dealing with
* @return an iterator
*/
// public static Iterator<AnswerList> getIterator(Long sID) {
//
// return ( new AnswerListMgr().new AnswerListIterator(sID));
// }
}