001: /**********************************************************************************
002: *
003: * $Id: GradeMapping.java 27835 2007-03-26 23:45:15Z ray@media.berkeley.edu $
004: *
005: ***********************************************************************************
006: *
007: * Copyright (c) 2005, 2006 The Regents of the University of California, The MIT Corporation
008: *
009: * Licensed under the Educational Community License, Version 1.0 (the "License");
010: * you may not use this file except in compliance with the License.
011: * You may obtain a copy of the License at
012: *
013: * http://www.opensource.org/licenses/ecl1.php
014: *
015: * Unless required by applicable law or agreed to in writing, software
016: * distributed under the License is distributed on an "AS IS" BASIS,
017: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018: * See the License for the specific language governing permissions and
019: * limitations under the License.
020: *
021: **********************************************************************************/package org.sakaiproject.tool.gradebook;
022:
023: import java.io.Serializable;
024: import java.util.*;
025:
026: import org.apache.commons.lang.builder.ToStringBuilder;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030:
031: /**
032: * A GradeMapping provides a means to convert between an arbitrary set of grades
033: * (letter grades, pass / not pass, 4,0 scale) and numeric percentages.
034: *
035: */
036: public class GradeMapping implements Serializable, Comparable {
037: protected Log log = LogFactory.getLog(GradeMapping.class);
038: protected Long id;
039: protected int version;
040:
041: protected Gradebook gradebook;
042: protected Map<String, Double> gradeMap;
043: private GradingScale gradingScale;
044:
045: public GradeMapping() {
046: }
047:
048: public GradeMapping(GradingScale gradingScale) {
049: setGradingScale(gradingScale);
050: gradeMap = new HashMap<String, Double>(gradingScale
051: .getDefaultBottomPercents());
052: }
053:
054: public String getName() {
055: return getGradingScale().getName();
056: }
057:
058: /**
059: * Sets the percentage values for this GradeMapping to their default values.
060: */
061: public void setDefaultValues() {
062: gradeMap = new HashMap<String, Double>(
063: getDefaultBottomPercents());
064: }
065:
066: /**
067: * Backwards-compatible wrapper to get to grading scale.
068: */
069: public Map<String, Double> getDefaultBottomPercents() {
070: GradingScale gradingScale = getGradingScale();
071: if (gradingScale != null) {
072: return gradingScale.getDefaultBottomPercents();
073: } else {
074: Map<String, Double> defaultBottomPercents = new HashMap<String, Double>();
075: Iterator defaultValuesIter = getDefaultValues().iterator();
076: Iterator gradesIter = getGrades().iterator();
077: while (gradesIter.hasNext()) {
078: String grade = (String) gradesIter.next();
079: Double value = (Double) defaultValuesIter.next();
080: defaultBottomPercents.put(grade, value);
081: }
082: return defaultBottomPercents;
083: }
084: }
085:
086: /**
087: *
088: * @return An (ordered) collection of the available grade values
089: */
090: public Collection<String> getGrades() {
091: return getGradingScale().getGrades();
092: }
093:
094: /**
095: *
096: * @return A List of the default grade values. Only used for backward
097: * compatibility to pre-grading-scale mappings.
098: */
099: public List<Double> getDefaultValues() {
100: throw new UnsupportedOperationException(
101: "getDefaultValues called for GradeMapping " + getName()
102: + " in Gradebook " + getGradebook());
103: }
104:
105: /**
106: * Gets the percentage mapped to a particular grade.
107: */
108: public Double getValue(String grade) {
109: return (Double) gradeMap.get(grade);
110: }
111:
112: /**
113: * This algorithm is slow, since it checks each grade option, starting from
114: * the "top" (in this case an 'A'). We can make it faster by starting in the
115: * middle (as in a bubble sort), but since there are so few grade options, I
116: * think I'll leave it for now.
117: *
118: * @see org.sakaiproject.tool.gradebook.GradeMapping#getGrade(Double)
119: */
120: public String getGrade(Double value) {
121: if (value == null) {
122: return null;
123: }
124: for (Iterator iter = getGrades().iterator(); iter.hasNext();) {
125: String grade = (String) iter.next();
126: Double mapVal = (Double) gradeMap.get(grade);
127: // If the value in the map is less than the value passed, then the
128: // map value is the letter grade for this value
129: if (mapVal != null && mapVal.compareTo(value) <= 0) {
130: return grade;
131: }
132: }
133: // As long as 'F' is zero, this should never happen.
134: return null;
135: }
136:
137: ////// Bean accessors and mutators //////
138:
139: /**
140: * @return Returns the id.
141: */
142: public Long getId() {
143: return id;
144: }
145:
146: /**
147: * @param id
148: * The id to set.
149: */
150: public void setId(Long id) {
151: this .id = id;
152: }
153:
154: /**
155: * @return Returns the version.
156: */
157: public int getVersion() {
158: return version;
159: }
160:
161: /**
162: * @param version
163: * The version to set.
164: */
165: public void setVersion(int version) {
166: this .version = version;
167: }
168:
169: /**
170: * @return Returns the gradeMap.
171: */
172: public Map<String, Double> getGradeMap() {
173: return gradeMap;
174: }
175:
176: /**
177: * @param gradeMap
178: * The gradeMap to set.
179: */
180: public void setGradeMap(Map<String, Double> gradeMap) {
181: this .gradeMap = gradeMap;
182: }
183:
184: /**
185: * @return Returns the gradebook.
186: */
187: public Gradebook getGradebook() {
188: return gradebook;
189: }
190:
191: /**
192: * @param gradebook
193: * The gradebook to set.
194: */
195: public void setGradebook(Gradebook gradebook) {
196: this .gradebook = gradebook;
197: }
198:
199: public int compareTo(Object o) {
200: return getName().compareTo(((GradeMapping) o).getName());
201: }
202:
203: public String toString() {
204: return new ToStringBuilder(this ).append(getName()).append(id)
205: .toString();
206: }
207:
208: /**
209: * Enable any-case input of grades (typically lowercase input
210: * for uppercase grades). Look for a case-insensitive match
211: * to the input text and if it's found, return the official
212: * version.
213: *
214: * @return The normalized version of the grade, or null if not found.
215: */
216: public String standardizeInputGrade(String inputGrade) {
217: String standardizedGrade = null;
218: for (Iterator iter = getGrades().iterator(); iter.hasNext();) {
219: String grade = (String) iter.next();
220: if (grade.equalsIgnoreCase(inputGrade)) {
221: standardizedGrade = grade;
222: break;
223: }
224: }
225: return standardizedGrade;
226: }
227:
228: /**
229: * @return the GradingScale used to define this mapping, or null if
230: * this is an old Gradebook which uses hard-coded scales
231: */
232: public GradingScale getGradingScale() {
233: return gradingScale;
234: }
235:
236: public void setGradingScale(GradingScale gradingScale) {
237: this.gradingScale = gradingScale;
238: }
239: }
|