/**
* RELOAD TOOLS Copyright (c) 2003 Oleg Liber, Bill Olivier, Phillip Beauvoir,
* Paul Sharples Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions: The
* above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS
* IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Project
* Management Contact: Oleg Liber Bolton Institute of Higher Education Deane
* Road Bolton BL3 5AB UK e-mail: o.liber@bolton.ac.uk Technical Contact:
* Phillip Beauvoir e-mail: p.beauvoir@bolton.ac.uk Paul Sharples e-mail:
* p.sharples@bolton.ac.uk Web: http://www.reload.ac.uk
*/
package org.olat.modules.scorm.server.beans;
import java.util.Iterator;
import java.util.Map;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.modules.scorm.ISettingsHandler;
import org.olat.modules.scorm.manager.ScormManager;
import org.olat.modules.scorm.server.sequence.SequenceManager;
import org.olat.modules.scorm.server.servermodels.SequencerModel;
/**
* A handler class which takes an input beans data and decides how to act. It
* will update a given items state and model and will return the new items data
* if the user had clicked "next/prev" or an item on the tree.
*
* @author Paul Sharples
*/
public class LMSDataHandler {
private static final OLog log = Tracing.createLoggerFor(LMSDataHandler.class);
protected ScormManager theCourse;
protected LMSDataFormBean _inputBean;
protected String status;
protected boolean isSco = false;
protected boolean isUpdating = false;
protected boolean isItemCompleted = false;
protected boolean isCourseCompleted = false;
protected boolean hasPrerequisites = false;
protected String itemId;
protected String[][] cmiStrings;
/**
* Constructor takes an input bean as argument
*
* @param theCourse an instance to a scorm manager
* @param inputBean
*/
public LMSDataHandler(ScormManager theCourse, LMSDataFormBean inputBean, ISettingsHandler settings) {
_inputBean = inputBean;
this.theCourse = theCourse;
}
/**
* A method to decide what kind of action to take given the information
* contained within the bean
*
* @return LMSResultsBean
*/
public LMSResultsBean getResultsBean() {
String lmsAction = _inputBean.getLmsAction();
if (lmsAction != null) {
// the user wants a new item - nothing to persist just get the data
if (lmsAction.equals("get")) {
return getCMIData(_inputBean.getItemID());
}
// the user wants to commit a model and may or may not want the next item
else if (lmsAction.equals("update")) {
return updateCMIData(_inputBean.getItemID());
}
// the package has been launched for the first time, so find the first
// item to launch
else if (lmsAction.equals("boot")) { return getCMIData(Integer.toString(getSequenceFromId(findFirstItemToLaunch()))); }
}
return null;
}
/**
* A method to update any CMI info given in the input bean
*
* @param itemIndex
* @return LMSResultsBean
*/
public LMSResultsBean updateCMIData(String itemIndex) {
itemId = findItemFromIndex(Integer.parseInt(itemIndex));
// if this is a sco
if (isItemSco(itemId)) {
isSco = true;
if (_inputBean.getDataAsMap() != null) {
cmiStrings = convertTo2dArray(_inputBean.getDataAsMap());
updateClientModel(itemId, cmiStrings);
} else {
// get the cmi data string into correct format
cmiStrings = formatCmiDataResults(_inputBean.getData());
updateClientModel(itemId, cmiStrings);
}
// cmiStrings = formatCmiDataResults("");
// next update the model with the results from browser.
// updateClientModel(itemId, cmiStrings);
// update prerequisite table
if(status == null) {
status = SequencerModel.ITEM_NOT_ATTEMPTED;
}
addtoPrereqTable(itemId, status, true);
// If an LMSFinish() was made by the sco then we do not need to update
// anything client side
String nextAction = _inputBean.getNextAction();
// String nextAction = "";
if (nextAction.equals("none") && !getAutoNav()) {
isUpdating = false;
}
// ELSE IF THE USER HAD CLICKED NEXT/PREV OR A TREE NODE THEN WE NEED TO
// GET NEXT ITEMs DATA
else {
if (getAutoNav()) {
// need nextAction to point to next item...
nextAction = Integer.toString(getSequenceFromId(findFirstItemToLaunch()));
}
isUpdating = true;
// now get and return new sco
return getCMIData(nextAction);
}
}
// must be asset
else {
isSco = false;
isUpdating = false;
}
// return the updated dataModel
return new LMSResultsBean(itemId, Boolean.toString(isSco), cmiStrings, Boolean.toString(isUpdating), getPreReqStrings(), Boolean
.toString(isItemCompleted), Boolean.toString(isCourseCompleted), Boolean.toString(hasPrerequisites));
}
/**
* @param dataAsMap
* @return a 2d String array
*/
private String[][] convertTo2dArray(Map<String,String> dataAsMap) {
String[][] cmiData = new String[dataAsMap.size()][2];
int j = 0;
for (Iterator<String> it = dataAsMap.keySet().iterator(); it.hasNext(); j++) {
String l = it.next();
String r = dataAsMap.get(l);
cmiData[j][0] = l;
cmiData[j][1] = r;
if (l.toString().equals("cmi.core.lesson_status")) {
status = r.toString();
}
}
return cmiData;
}
/**
* A method to get a new item, based on the values given from the input bean
*
* @param itemIndex
* @return LMSResultsBean
*/
public LMSResultsBean getCMIData(String itemIndex) {
// <OLATCE-289>
//ignore completed state -> ability to launch the scorm depends on the number of attempts
if (itemIndex.equals(Integer.toString(SequenceManager.COURSE_COMPLETED_VALUE))) {
itemIndex = "0";
}
// </OLATCE-289>
// HAS THIS COURSE BEEN COMPLETED
if (itemIndex.equals(Integer.toString(SequenceManager.COURSE_COMPLETED_VALUE))) {
isCourseCompleted = true;
generatePrereqBean();
}
// COURSE NOT COMPLETED SO CHECK THIS ITEM
else {
itemId = findItemFromIndex(Integer.parseInt(itemIndex));
// has this particular item been completed?
// <OLATCE-289>
//if (hasItemBeenCompleted(itemId)) {
// isItemCompleted = true;
//}
// does this item have prerequisites?
//else if (!checkItemsPrerequisites(itemId)) {
// hasPrerequisites = true;
// generatePrereqBean();
//}
// WE CAN LAUNCH THIS ITEM
//else {
// </OLATCE-289>
// if this is a sco
if (isItemSco(itemId)) {
// load this scos model
loadinModel(itemId);
// get it
cmiStrings = getScoModel(itemId);
isSco = true;
isUpdating = true;
}
// must be asset
else {
// Update status of this ASSET to completed
addtoPrereqTable(itemId, SequencerModel.ITEM_COMPLETED, true);
isSco = false;
isUpdating = false;
}
//}
}
return new LMSResultsBean(itemIndex, Boolean.toString(isSco), cmiStrings, Boolean.toString(isUpdating), getPreReqStrings(), Boolean
.toString(isItemCompleted), Boolean.toString(isCourseCompleted), Boolean.toString(hasPrerequisites));
}
/**
* Format the string containing the cmi data into a nice 2d array.
*
* @param cmiString
* @return
*/
protected String[][] formatCmiDataResults(String cmiString) {
String[] cmiBits = cmiString.split("\\^r\\@l\\@ad\\^");
String[][] cmiComponents = new String[cmiBits.length][2];
for (int i = 0; i < cmiBits.length; i++) {
String[] cmiNameValue = cmiBits[i].split("\\~r\\@l\\@ad\\~");
cmiComponents[i][0] = cmiNameValue[0];
if (cmiNameValue[0].equals("cmi.core.lesson_status")) {
status = cmiNameValue[1];
}
if (cmiNameValue.length > 1) {
cmiComponents[i][1] = cmiNameValue[1];
} else {
cmiComponents[i][1] = "";
}
if (log.isDebug()){
log.debug("name: " + cmiComponents[i][0] + " value:" + cmiComponents[i][1]);
}
}
return cmiComponents;
}
protected String[][] getPreReqStrings() {
String[][] pTable = getPackageStatus();
return pTable;
}
/**
* Wrapper method from SequenceManager
*
* @param index
* @return
*/
protected String findItemFromIndex(int index) {
return theCourse.getSequence().findItemFromIndex(index);
}
protected String[][] getPackageStatus() {
return theCourse.getSequence().getPackageStatus();
}
/**
* Wrapper method from SequenceManager
*
* @param item
* @return
*/
protected String getTitle(String item) {
return theCourse.getSequence().getItem(item).getTitle();
}
/**
* Wrapper method from SequenceManager
*
* @param item
* @return
*/
protected boolean isItemSco(String item) {
return theCourse.getSequence().isItemSco(item);
}
/**
* Wrapper method from SequenceManager
*
* @return
*/
protected String findFirstItemToLaunch() {
return theCourse.getSequence().findFirstItemToLaunch();
}
/**
* Wrapper method from SequenceManager
*
* @param item
* @return
*/
protected int getSequenceFromId(String item) {
return theCourse.getSequence().getSequenceFromId(item);
}
/**
* Wrapper method from SequenceManager
*
* @param item
* @return
*/
protected boolean hasItemBeenCompleted(String item) {
return theCourse.getSequence().hasItemBeenCompleted(item);
}
/**
* Wrapper method from SequenceManager
*
* @param item
* @return
*/
protected boolean checkItemsPrerequisites(String item) {
return theCourse.getSequence().checkItemsPrerequisites(item);
}
/**
* Wrapper method from SequenceManager
*
* @param itemId
*/
protected void loadinModel(String itemId) {
theCourse.getSequence().getItem(itemId).loadInModel();
}
/**
* Wrapper method from SequenceManager
*
* @param itemId
* @return
*/
protected String[][] getScoModel(String itemId) {
return theCourse.getSequence().getItem(itemId).getScoModel();
}
/**
* Wrapper method from SequenceManager
*
* @param itemId
* @param itemStatus
* @param save
*/
protected void addtoPrereqTable(String itemId, String itemStatus, boolean save) {
theCourse.getSequence().addtoPrereqTable(itemId, itemStatus, true);
}
/**
* Wrapper method from SequenceManager
*
* @param itemId
* @param cmiStrings
*/
protected void updateClientModel(String itemId, String[][] cmiStrings) {
theCourse.getSequence().getItem(itemId).updateClientModel(cmiStrings);
}
protected boolean getAutoNav() {
return theCourse.isAutoProgressionEnabled();
}
protected void generatePrereqBean() {
// not needed
// HttpSession session = ScormLaunch.getHttpSession();
// StatusBean sb = new StatusBean(getPreReqStrings());
// System.out.println("from generatePrereqBean()");
// String[][] strArr = getPreReqStrings();
// if(strArr != null){
// for(int i=0;i<strArr.length;i++){
// System.out.println("");
// for(int j=0;j<strArr[i].length;j++){
// System.out.print(strArr[i][j] + " : ");
// }
//
// }
// }
// System.out.println("from generatePrereqBean() end");
// session.setAttribute("prereqBean", sb);
}
}