001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 the ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package org.conqat.lib.commons.assessment;
018
019import java.awt.Color;
020import java.text.DecimalFormat;
021import java.text.NumberFormat;
022import java.util.ArrayList;
023import java.util.List;
024
025import org.conqat.lib.commons.color.ECCSMColor;
026
027/**
028 * Utility methods for dealing with ratings.
029 */
030public class AssessmentUtils {
031
032        /** Number format that adds + or - as necessary. */
033        public static final NumberFormat PLUS_MINUS_NUMBERFORMAT = new DecimalFormat("+#;-#");
034
035        /** Returns the color used for visualizing a traffic light color. */
036        public static Color getColor(ETrafficLightColor color) {
037                switch (color) {
038                case RED:
039                        return ECCSMColor.RED.getColor();
040                case YELLOW:
041                        return ECCSMColor.YELLOW.getColor();
042                case GREEN:
043                        return ECCSMColor.GREEN.getColor();
044                case BASELINE:
045                        return ECCSMColor.LIGHT_BLUE.getColor();
046
047                case UNKNOWN:
048                default:
049                        return ECCSMColor.DARK_GRAY.getColor();
050                }
051        }
052
053        /**
054         * Compares two {@link Assessment}s returning which is "better" than another
055         * one.
056         * 
057         * @return the value 0 if o1 is equal to o2; a value less than 0 if o1 is worse
058         *         than o2; and a value greater than 0 if o1 is better than o2.
059         */
060        public static int compareAssessments(Assessment o1, Assessment o2) {
061                double red1 = o1.getColorFrequency(ETrafficLightColor.RED) / (double) o1.getSize();
062                double red2 = o2.getColorFrequency(ETrafficLightColor.RED) / (double) o2.getSize();
063                double yellow1 = o1.getColorFrequency(ETrafficLightColor.YELLOW) / (double) o1.getSize();
064                double yellow2 = o2.getColorFrequency(ETrafficLightColor.YELLOW) / (double) o2.getSize();
065
066                // chosen by a close look at the sorting result.
067                double yFactor = 0.4;
068                return Double.compare(red1 + yFactor * yellow1, red2 + yFactor * yellow2);
069        }
070
071        /**
072         * Calculates a delta string for two given assessments. Only colors RED, YELLOW
073         * and GREEN.
074         */
075        public static String calculateAndFormatDelta(Assessment oldAssessment, Assessment newAssessment) {
076                List<String> builder = new ArrayList<>();
077                for (ETrafficLightColor color : ETrafficLightColor.getTrafficLightColors()) {
078                        if (computeRelativeFrequencyDelta(color, oldAssessment, newAssessment) == 0) {
079                                continue;
080                        }
081                        builder.add(calculateAndFormatDelta(color, oldAssessment, newAssessment));
082                }
083                return String.join(", ", builder);
084        }
085
086        /**
087         * Calculates a delta string for a given color for two given assessments
088         * containing the color frequency delta and the relative delta change.
089         */
090        public static String calculateAndFormatDelta(ETrafficLightColor color, Assessment oldAssessment,
091                        Assessment newAssessment) {
092                String colorName = color.getShortDisplayText();
093
094                String colorFrequencyDeltaFormatted = PLUS_MINUS_NUMBERFORMAT
095                                .format(newAssessment.getColorFrequency(color) - oldAssessment.getColorFrequency(color));
096
097                double colorRelativeDelta = computeRelativeFrequencyDelta(color, oldAssessment, newAssessment);
098                String colorRelativeDeltaFormatted = Assessment.PERCENT_FORMAT.format(colorRelativeDelta);
099
100                String formattedDelta = colorName + ": " + colorFrequencyDeltaFormatted + " (";
101                if (colorRelativeDelta > 0) {
102                        formattedDelta += "+";
103                }
104                formattedDelta += colorRelativeDeltaFormatted + ")";
105                return formattedDelta;
106        }
107
108        /**
109         * Calculate the relative color frequency delta to the given assessments
110         */
111        public static double computeRelativeFrequencyDelta(ETrafficLightColor color, Assessment oldAssessment,
112                        Assessment newAssessment) {
113                return (double) newAssessment.getColorFrequency(color) / newAssessment.getSize()
114                                - (double) oldAssessment.getColorFrequency(color) / oldAssessment.getSize();
115        }
116
117}