/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/postem/trunk/postem-hbm/src/java/org/sakaiproject/component/app/postem/data/GradebookImpl.java $
* $Id: GradebookImpl.java 125618 2013-06-11 16:41:26Z matthew@longsight.com $
***********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 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.component.app.postem.data;
import java.io.Serializable;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import org.apache.commons.lang.StringEscapeUtils;
//import org.apache.commons.math.stat.descriptive.SummaryStatistics;
import org.sakaiproject.api.app.postem.data.Gradebook;
import org.sakaiproject.api.app.postem.data.StudentGrades;
import org.sakaiproject.api.app.postem.data.Template;
import org.sakaiproject.user.api.UserNotDefinedException;
import org.sakaiproject.user.cover.UserDirectoryService;
public class GradebookImpl implements Gradebook, Comparable, Serializable {
protected String title;
protected String creator;
protected String fileReference;
protected String creatorEid;
protected Timestamp created;
protected String lastUpdater;
protected String lastUpdaterEid;
protected DateFormat dateFormat = new SimpleDateFormat("d MMM yyyy HH:mm");
protected Timestamp lastUpdated;
protected String context;
protected String firstUploadedUsername;
protected Set students = new TreeSet();
protected Template template;
protected List headings = new ArrayList();
protected Long id;
protected Integer lockId;
protected Boolean released = new Boolean(false);
protected Boolean releaseStatistics = new Boolean(false);
protected List<String> usernames;
private static String units = "px";
public static Comparator TitleAscComparator;
public static Comparator TitleDescComparator;
public static Comparator CreatorAscComparator;
public static Comparator CreatorDescComparator;
public static Comparator ModByAscComparator;
public static Comparator ModByDescComparator;
public static Comparator ModDateAscComparator;
public static Comparator ModDateDescComparator;
public static Comparator ReleasedAscComparator;
public static Comparator ReleasedDescComparator;
public GradebookImpl() {
}
public GradebookImpl(String title, String creator, String context,
List headings, SortedSet students, Template template) {
Timestamp now = new Timestamp(new Date().getTime());
this.title = title;
this.creator = creator;
this.created = now;
this.lastUpdater = creator;
this.lastUpdated = now;
this.context = context;
if (headings != null) {
this.headings = headings;
} else {
this.headings = new ArrayList();
}
if (students != null) {
this.students = students;
} else {
this.students = new TreeSet();
}
this.template = template;
}
public Integer getLockId() {
return lockId;
}
public void setLockId(Integer lockId) {
this.lockId = lockId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getFileReference() {
return fileReference;
}
public void setFileReference(String fileReference) {
this.fileReference = fileReference;
}
public String getCreator() {
return creator;
}
public void setCreator(String creator) {
this.creator = creator;
setCreatorEid(creator);
}
public String getCreatorEid() {
return creatorEid;
}
public void setCreatorEid(String creatorUserId) {
if(creatorUserId != null) {
try {
this.creatorEid = UserDirectoryService.getUserEid(creatorUserId);
} catch(UserNotDefinedException e) {
this.creatorEid = null;
}
}
}
public Timestamp getCreated() {
return created;
}
public void setCreated(Timestamp created) {
this.created = created;
}
public String getLastUpdater() {
return lastUpdater;
}
public void setLastUpdater(String lastUpdater) {
this.lastUpdater = lastUpdater;
setLastUpdaterEid(lastUpdater);
}
public String getLastUpdaterEid() {
return lastUpdaterEid;
}
public void setLastUpdaterEid(String lastUpdaterUserId) {
if (lastUpdaterUserId != null) {
try {
this.lastUpdaterEid = UserDirectoryService.getUserEid(lastUpdaterUserId);
} catch(UserNotDefinedException e) {
this.lastUpdaterEid = null;
}
}
}
public String getUpdatedDateTime() {
return dateFormat.format((Date) lastUpdated);
}
public Timestamp getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(Timestamp lastUpdated) {
this.lastUpdated = lastUpdated;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
public Set getStudents() {
return students;
}
public void setStudents(Set students) {
this.students = students;
}
public Template getTemplate() {
return template;
}
public void setTemplate(Template template) {
this.template = template;
}
public List getHeadings() {
return headings;
}
public void setHeadings(List headings) {
if (headings == null) {
this.headings = new ArrayList();
} else {
this.headings = headings;
}
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Boolean getReleased() {
return released;
}
public void setReleased(Boolean released) {
this.released = released;
}
public boolean getRelease() {
return released.booleanValue();
}
public void setRelease(boolean release) {
this.released = new Boolean(release);
}
public Boolean getReleaseStatistics() {
return releaseStatistics;
}
public void setReleaseStatistics(Boolean releaseStatistics) {
this.releaseStatistics = releaseStatistics;
}
public boolean getReleaseStats() {
return releaseStatistics.booleanValue();
}
public void setReleaseStats(boolean releaseStats) {
this.releaseStatistics = new Boolean(releaseStats);
}
public void setFirstUploadedUsername(String firstUploadedUsername) {
this.firstUploadedUsername = firstUploadedUsername;
}
public String getFirstUploadedUsername() {
return firstUploadedUsername;
}
public void setUsernames(List<String> usernames) {
this.usernames = usernames;
}
public List<String> getUsernames() {
return usernames;
}
public String getHeadingsRow() {
List h2 = new ArrayList(headings);
h2.remove(0);
StringBuilder headingBuffer = new StringBuilder();
// headingBuffer.append("<table><tr>");
int totalWidth = 0;
Iterator jj = h2.iterator();
int ii = 0;
while (jj.hasNext()) {
String current = (String) jj.next();
String width = getProperWidth(ii);
int iwidth = Integer.parseInt(width.substring(0, width.length() - 2));
totalWidth += iwidth;
/*headingBuffer.append("<th width='");
headingBuffer.append(width);
headingBuffer.append("' style='min-width: ");
headingBuffer.append(width);
headingBuffer.append("; width: ");
headingBuffer.append(width);
headingBuffer.append(";' >");
headingBuffer.append(current);
headingBuffer.append("</th>");*/
headingBuffer.append("<th style=\"padding: 0.6em;\" scope=\"col\">" + StringEscapeUtils.escapeHtml(current) + "</th>");
ii++;
}
/*StringBuilder newBuffer = new StringBuilder();
newBuffer.append("<table width='");
newBuffer.append(totalWidth);
newBuffer.append("px' style='min-width: ");
newBuffer.append(totalWidth);
newBuffer.append("px; width: ");
newBuffer.append(totalWidth);
newBuffer.append("px;' ><tr>");
newBuffer.append(headingBuffer);
newBuffer.append("</tr></table>");
return newBuffer.toString();*/
return headingBuffer.toString();
}
public int compareTo(Object other) {
if (this == other)
return 0;
final Gradebook that = (Gradebook) other;
return this.getTitle().compareTo(that.getTitle());
}
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof Gradebook))
return false;
final Gradebook that = (Gradebook) other;
return this.getTitle().equals(that.getTitle());
}
public int hashCode() {
return getTitle().hashCode();
}
public boolean hasStudent(String username) {
Iterator iter = getStudents().iterator();
while (iter.hasNext()) {
if (((StudentGrades) iter.next()).getUsername().equalsIgnoreCase(username)) {
return true;
}
}
return false;
}
public String getProperWidth(int column) {
int maxWidth = 50;
int tops = 150;
try {
List h2 = new ArrayList(headings);
h2.remove(0);
int hchars = ((String) h2.get(column)).length();
int hwidth = hchars * 10;
if (hwidth >= tops) {
maxWidth = tops;
return "" + maxWidth + units;
}
if (hwidth >= maxWidth) {
maxWidth = hwidth;
}
} catch (Exception exception) {
}
Iterator iter = getStudents().iterator();
while (iter.hasNext()) {
StudentGrades sg = (StudentGrades) iter.next();
try {
int chars = ((String) sg.getGrades().get(column)).length();
int width = chars * 10;
if (width >= tops) {
maxWidth = tops;
return "" + maxWidth + units;
}
if (width >= maxWidth) {
maxWidth = width;
}
} catch (Exception exception) {
}
}
return "" + maxWidth + units;
}
public List getRawData(int column) {
List rawData = new ArrayList();
Iterator iter = getStudents().iterator();
while (iter.hasNext()) {
StudentGrades sg = (StudentGrades) iter.next();
try {
rawData.add(new Pair(sg.getUsername(), sg.getGrades().get(column)));
} catch (IndexOutOfBoundsException exception) {
rawData.add(new Pair(sg.getUsername(), ""));
}
}
return rawData;
}
public List getAggregateData(int column) throws Exception {
List aggregateData = new ArrayList();
// This code has never actually been used. The stats feature has been
// commented out since Postem's sakai introduction.
// Commenting out the implementation of this method since it
// deploys commons-math to shared. This method
// should probably not be part of the Gradebook api and should probably
// be moved to the GradebookManager if it is ever actually implemented.
/*SummaryStatistics stats = SummaryStatistics.newInstance();
int blanks = 0;
Iterator iter = getStudents().iterator();
while (iter.hasNext()) {
StudentGrades sg = (StudentGrades) iter.next();
try {
String value = (String) sg.getGrades().get(column);
if ("".equals(value.trim())) {
// TODO: do blanks count as zeros for stats?
// stats.addValue(0);
blanks++;
} else {
stats.addValue(Double.parseDouble(value));
}
} catch (IndexOutOfBoundsException exception) {
blanks++;
}
}
aggregateData.add(new Pair("Average", new Double(stats.getMean())));
aggregateData.add(new Pair("Std. Dev.", new Double(stats
.getStandardDeviation())));
aggregateData.add(new Pair("Highest", new Double(stats.getMax())));
aggregateData.add(new Pair("Lowest", new Double(stats.getMin())));
aggregateData.add(new Pair("Range", new Double(stats.getMax()
- stats.getMin())));
aggregateData.add(new Pair("N=count(non-blank)", new Double(stats.getN())));
aggregateData.add(new Pair("count(blank)", new Integer(blanks)));*/
return aggregateData;
}
public StudentGrades studentGrades(String username) {
Iterator iter = getStudents().iterator();
while (iter.hasNext()) {
StudentGrades current = (StudentGrades) iter.next();
if (current.getUsername().equalsIgnoreCase(username)) {
return current;
}
}
return null;
}
public TreeMap getStudentMap() {
TreeMap studentMap = new TreeMap();
studentMap.put(" ", "blank");
Iterator iter = getUsernames().iterator();
while (iter.hasNext()) {
String username = (String) iter.next();
studentMap.put(username, username);
}
return studentMap;
}
private static int compareTitles(Gradebook gradebook, Gradebook otherGradebook) {
String title1 = gradebook.getTitle().toUpperCase();
String title2 = otherGradebook.getTitle().toUpperCase();
int val = title1.compareTo(title2);
if (val != 0)
return val;
else
return 1; //we want "Test" and "test" to appear together
}
static
{
// We have to be careful because the gradebooks use the "SortedSet" structure
// that will only accept one occurrence if the items being compared are equal
TitleAscComparator = new Comparator() {
public int compare(Object gradebook, Object otherGradebook) {
return compareTitles((Gradebook) gradebook, (Gradebook)otherGradebook);
}
};
TitleDescComparator = new Comparator() {
public int compare(Object gradebook, Object otherGradebook) {
return compareTitles((Gradebook) otherGradebook, (Gradebook)gradebook);
}
};
CreatorAscComparator = new Comparator() {
public int compare(Object gradebook, Object otherGradebook) {
String creator1 = ((Gradebook) gradebook).getCreatorEid().toUpperCase();
String creator2 = ((Gradebook) otherGradebook).getCreatorEid().toUpperCase();
if(creator1.equals(creator2)) {
return compareTitles((Gradebook) gradebook, (Gradebook)otherGradebook);
}
return creator1.compareTo(creator2);
}
};
CreatorDescComparator = new Comparator() {
public int compare(Object gradebook, Object otherGradebook) {
String creator1 = ((Gradebook) gradebook).getCreatorEid().toUpperCase();
String creator2 = ((Gradebook) otherGradebook).getCreatorEid().toUpperCase();
if(creator1.equals(creator2)) {
return compareTitles((Gradebook) gradebook, (Gradebook)otherGradebook);
}
return creator2.compareTo(creator1);
}
};
ModByAscComparator = new Comparator() {
public int compare(Object gradebook, Object otherGradebook) {
String modBy1 = ((Gradebook) gradebook).getLastUpdaterEid().toUpperCase();
String modBy2 = ((Gradebook) otherGradebook).getLastUpdaterEid().toUpperCase();
if(modBy1.equals(modBy2)) {
return compareTitles((Gradebook) gradebook, (Gradebook)otherGradebook);
}
return modBy1.compareTo(modBy2);
}
};
ModByDescComparator = new Comparator() {
public int compare(Object gradebook, Object otherGradebook) {
String modBy1 = ((Gradebook) gradebook).getLastUpdaterEid().toUpperCase();
String modBy2 = ((Gradebook) otherGradebook).getLastUpdaterEid().toUpperCase();
if(modBy1.equals(modBy2)) {
return compareTitles((Gradebook) gradebook, (Gradebook)otherGradebook);
}
return modBy2.compareTo(modBy1);
}
};
ModDateAscComparator = new Comparator() {
public int compare(Object gradebook, Object otherGradebook) {
Timestamp modDate1 = ((Gradebook) gradebook).getLastUpdated();
Timestamp modDate2 = ((Gradebook) otherGradebook).getLastUpdated();
if(modDate1.equals(modDate2)) {
return compareTitles((Gradebook) gradebook, (Gradebook)otherGradebook);
}
return modDate1.compareTo(modDate2);
}
};
ModDateDescComparator = new Comparator() {
public int compare(Object gradebook, Object otherGradebook) {
Timestamp modDate1 = ((Gradebook) gradebook).getLastUpdated();
Timestamp modDate2 = ((Gradebook) otherGradebook).getLastUpdated();
if(modDate1.equals(modDate2)) {
return compareTitles((Gradebook) gradebook, (Gradebook)otherGradebook);
}
return modDate2.compareTo(modDate1);
}
};
ReleasedAscComparator = new Comparator() {
public int compare(Object gradebook, Object otherGradebook) {
boolean released1 = ((Gradebook) gradebook).getRelease();
boolean released2 = ((Gradebook) otherGradebook).getRelease();
if (released1 == released2)
return compareTitles((Gradebook) gradebook, (Gradebook)otherGradebook);
else if (released1 && !released2)
return -1;
else
return 1;
}
};
ReleasedDescComparator = new Comparator() {
public int compare(Object gradebook, Object otherGradebook) {
boolean released1 = ((Gradebook) gradebook).getRelease();
boolean released2 = ((Gradebook) otherGradebook).getRelease();
if (released1 == released2) {
return compareTitles((Gradebook) gradebook, (Gradebook)otherGradebook);
}
else if (released1 && !released2)
return 1;
else
return -1;
}
};
}
}