/**
* Copyright © 2002 Instituto Superior Técnico
*
* This file is part of FenixEdu Academic.
*
* FenixEdu Academic is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FenixEdu Academic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FenixEdu Academic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.fenixedu.academic.domain;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import org.fenixedu.academic.domain.curriculum.EnrollmentState;
import org.fenixedu.academic.domain.exceptions.DomainException;
import org.fenixedu.commons.i18n.LocalizedString;
public class Grade implements Serializable, Comparable<Grade> {
private static Grade emptyGrade = new EmptyGrade();
private static Map<String, Grade> gradeMap = new HashMap<String, Grade>();
private final String value;
private final GradeScale gradeScale;
protected Grade() {
value = null;
gradeScale = null;
}
protected Grade(String value, GradeScale gradeScale) {
if (EmptyGrade.qualifiesAsEmpty(value)) {
throw new DomainException("error.grade.invalid.argument");
}
if (!gradeScale.belongsTo(value)) {
throw new DomainException("error.grade.invalid.grade");
}
this.value = value.trim().toUpperCase();
this.gradeScale = gradeScale;
}
@Override
public int compareTo(final Grade otherGrade) {
return gradeScale.compareGrades(this, otherGrade);
}
public BigDecimal getNumericValue() {
return value == null ? null : new BigDecimal(getValue());
}
public String getValue() {
return value;
}
public Integer getIntegerValue() {
return isNumeric() ? Integer.valueOf(getValue()) : null;
}
public GradeScale getGradeScale() {
return gradeScale;
}
public static Grade createGrade(String value, GradeScale gradeScale) {
if (EmptyGrade.qualifiesAsEmpty(value)) {
return createEmptyGrade();
}
Grade grade = gradeMap.get(exportAsString(gradeScale, value));
if (grade == null) {
grade = new Grade(value, gradeScale);
gradeMap.put(grade.exportAsString(), grade);
}
return grade;
}
public static Grade createEmptyGrade() {
return emptyGrade;
}
public static Grade importFromString(String string) {
if (EmptyGrade.qualifiesAsEmpty(string)) {
return emptyGrade;
}
String[] tokens = string.split(":");
return createGrade(tokens[1], GradeScale.valueOf(tokens[0]));
}
@Override
public String toString() {
return exportAsString();
}
public String exportAsString() {
return exportAsString(getGradeScale(), getValue());
}
private static String exportAsString(GradeScale gradeScale, String value) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(gradeScale);
stringBuilder.append(":");
stringBuilder.append(value.trim().toUpperCase());
return stringBuilder.toString();
}
public boolean isEmpty() {
return false;
}
public boolean isNumeric() {
/**
*
* This was the original implementation, but it is very slow...
* especially when generating reports that have to call this method for
* practically every enrollment.
*
* try { Double.parseDouble(getValue()); return true; } catch
* (NumberFormatException e) { return false; }
*
*
* This alternative implementation is roughly 30-40x faster! So I
* suggest you keep this ugly code where it is. Using StringUtils may
* appear to be nicer, but beware that it will produce different
* results!
*
*/
if (value.isEmpty()) {
return false;
}
boolean foundSeperator = false;
for (int i = 0; i < value.length(); i++) {
final char c = value.charAt(i);
if (c == '.' || c == ',') {
if (foundSeperator) {
return false;
} else {
foundSeperator = true;
}
} else if (!Character.isDigit(c)) {
return false;
}
}
return true;
}
public boolean isApproved() {
return getGradeScale().isApproved(this);
}
public boolean isNotApproved() {
return getGradeScale().isNotApproved(this);
}
public boolean isNotEvaluated() {
return getGradeScale().isNotEvaluated(this);
}
public LocalizedString getExtendedValue() {
return gradeScale.getExtendedValue(this);
}
public EnrollmentState getEnrolmentState() {
if (isNotEvaluated()) {
return EnrollmentState.NOT_EVALUATED;
} else if (isNotApproved()) {
return EnrollmentState.NOT_APROVED;
} else if (isApproved()) {
return EnrollmentState.APROVED;
} else {
return EnrollmentState.NOT_APROVED;
}
}
}