// Copyright 2012 Georg-August-Universität Göttingen, Germany
//
// Licensed under the Apache 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.apache.org/licenses/LICENSE-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 de.ugoe.cs.autoquest.commands.usability;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import com.google.common.collect.Sets;
import de.ugoe.cs.autoquest.CommandHelpers;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskTreeUtils;
import de.ugoe.cs.autoquest.usability.UsabilityEvaluationResult;
import de.ugoe.cs.autoquest.usability.UsabilitySmell;
import de.ugoe.cs.autoquest.usability.UsabilitySmell.ManualLabel;
import de.ugoe.cs.util.console.Command;
import de.ugoe.cs.util.console.GlobalDataContainer;
/**
*
* TODO comment
*
*
* @author Patrick Harms
* @version 1.0
*/
public class CMDusabilityStatistics implements Command {
private static int COUNT = 0;
private static int DUPLICATES = 1;
private static int INTENSITY_LVL = 2;
private static int TRUE_POSITIVE = 3;
private static int TRUE_POSITIVE_DUPLICATES = 4;
private static int TRUE_POSITIVE_INTENSITY_LVL = 5;
private static int UNASSESSED = 6;
private static int MP_COUNT = 7;
private static int MP_DUPLICATES = 8;
private static int MP_INTENSITY_LVL = 9;
private static int MP_TRUE_POSITIVE = 10;
private static int MP_TRUE_POSITIVE_DUPLICATES = 11;
private static int MP_TRUE_POSITIVE_INTENSITY_LVL = 12;
private static int MP_UNASSESSED = 13;
/*
* (non-Javadoc)
*
* @see de.ugoe.cs.util.console.Command#run(java.util.List)
*/
@Override
public void run(List parameters) {
List usabilityResultNames = new ArrayList<>(parameters.size());
try {
for (Object parameter : parameters) {
usabilityResultNames.add((String) parameter);
}
}
catch (Exception e) {
throw new IllegalArgumentException();
}
List usabilityResults = new ArrayList<>(usabilityResultNames.size());
for (String usabilityResultName : usabilityResultNames) {
Object dataObject = GlobalDataContainer.getInstance().getData(usabilityResultName);
if (dataObject == null) {
CommandHelpers.objectNotFoundMessage(usabilityResultName);
return;
}
if (!(dataObject instanceof UsabilityEvaluationResult)) {
CommandHelpers.objectNotType(usabilityResultName, "UsabilityEvaluationResult");
return;
}
usabilityResults.add((UsabilityEvaluationResult) dataObject);
}
// analyse all smells
Map> allSmells = new TreeMap<>();
Map> mostProminentSequences = new TreeMap<>();
Set smellTypes = new TreeSet<>();
for (int i = 0; i < usabilityResults.size(); i++) {
String usabilityResultName = usabilityResultNames.get(i);
allSmells.put(usabilityResultName, usabilityResults.get(i).getAllSmells());
for (UsabilitySmell smell : usabilityResults.get(i).getAllSmells()) {
smellTypes.add(smell.getBriefDescription());
}
if (!mostProminentSequences.containsKey(usabilityResultName)) {
mostProminentSequences.put(usabilityResultName,
TaskTreeUtils.getMostProminentTasks
(usabilityResults.get(i).getTaskModel()));
}
}
analyseAndDump("all smells", allSmells, mostProminentSequences);
for (String smellType : smellTypes) {
Map> relevantSmells = new TreeMap<>();
for (int i = 0; i < usabilityResults.size(); i++) {
List smellList = new LinkedList<>();
for (UsabilitySmell smell : usabilityResults.get(i).getAllSmells()) {
if (smellType.equals(smell.getBriefDescription())) {
smellList.add(smell);
}
}
relevantSmells.put(usabilityResultNames.get(i), smellList);
}
analyseAndDump(smellType, relevantSmells, mostProminentSequences);
}
}
/**
*
*/
private void analyseAndDump(String setName,
Map> smells,
Map> mostProminentSequences)
{
System.out.println("\n\n###################################################################");
System.out.println("usability statistics for " + setName + "\n");
// determine statistics
int[][] basicResultData = new int[14][];
for (int i = 0; i < basicResultData.length; i++) {
basicResultData[i] = new int[smells.size()];
}
Map>> tagCounters = new TreeMap<>();
List columnNames = new LinkedList<>();
int index = 0;
for (Map.Entry> smellGroup : smells.entrySet()) {
String usabilityResultName = smellGroup.getKey();
columnNames.add(usabilityResultName);
basicResultData[COUNT][index] = smellGroup.getValue().size();
basicResultData[DUPLICATES][index] = getDuplicates(smellGroup.getValue());
basicResultData[INTENSITY_LVL][index] = getIntensityLevel(smellGroup.getValue());
List truePositives = new LinkedList<>();
List unassessed = new LinkedList<>();
List mps = new LinkedList<>();
List mpTruePositives = new LinkedList<>();
List mpUnassessed = new LinkedList<>();
for (UsabilitySmell smell : smellGroup.getValue()) {
if (smell.getManualLabel() == ManualLabel.TRUE_POSITIVE) {
truePositives.add(smell);
}
else if (smell.getManualLabel() == ManualLabel.UNCHECKED) {
unassessed.add(smell);
}
if (mostProminentSequences.get(smellGroup.getKey()).contains(smell.getSmellingTask())) {
mps.add(smell);
if (smell.getManualLabel() == ManualLabel.TRUE_POSITIVE) {
mpTruePositives.add(smell);
}
else if (smell.getManualLabel() == ManualLabel.UNCHECKED) {
mpUnassessed.add(smell);
}
}
Set tagList = new HashSet<>(smell.getTags());
Set> powerSetTags = Sets.powerSet(tagList);
for (Set tagSet : powerSetTags) {
List tags = new LinkedList<>(tagSet);
//{List tags = new LinkedList<>(tagList);
Collections.sort(tags);
String tagCombinationKey = tags.toString();
Map> counterMap = tagCounters.get(tagCombinationKey);
if (counterMap == null) {
counterMap = new HashMap<>();
tagCounters.put(tagCombinationKey, counterMap);
}
List smellWithSameTagCombination =
counterMap.get(usabilityResultName);
if (smellWithSameTagCombination == null) {
smellWithSameTagCombination = new LinkedList<>();
counterMap.put(usabilityResultName, smellWithSameTagCombination);
}
smellWithSameTagCombination.add(smell);
}
}
basicResultData[TRUE_POSITIVE][index] = truePositives.size();
basicResultData[TRUE_POSITIVE_DUPLICATES][index] = getDuplicates(truePositives);
basicResultData[TRUE_POSITIVE_INTENSITY_LVL][index] = getIntensityLevel(truePositives);
basicResultData[UNASSESSED][index] = unassessed.size();
basicResultData[MP_COUNT][index] = mps.size();
basicResultData[MP_DUPLICATES][index] = getDuplicates(mps);
basicResultData[MP_INTENSITY_LVL][index] = getIntensityLevel(mps);
basicResultData[MP_TRUE_POSITIVE][index] = mpTruePositives.size();
basicResultData[MP_TRUE_POSITIVE_DUPLICATES][index] = getDuplicates(mpTruePositives);
basicResultData[MP_TRUE_POSITIVE_INTENSITY_LVL][index] = getIntensityLevel(mpTruePositives);
basicResultData[MP_UNASSESSED][index] = mpUnassessed.size();
index++;
}
int maxTagNameLength = 0;
for (String tagCombination : tagCounters.keySet()) {
maxTagNameLength = Math.max(maxTagNameLength, tagCombination.length());
}
maxTagNameLength = Math.max(maxTagNameLength, " intensity level".length());
List lines = new LinkedList<>();
lines.add(createBorderLine(maxTagNameLength, columnNames));
lines.add(new StringBuffer("overall"));
lines.add(createDataLine(" count", maxTagNameLength, basicResultData[COUNT], columnNames));
lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[DUPLICATES], columnNames));
lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[INTENSITY_LVL], columnNames));
lines.add(createDataLine(" true positives", maxTagNameLength, basicResultData[TRUE_POSITIVE], columnNames));
lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[TRUE_POSITIVE_DUPLICATES], columnNames));
lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[TRUE_POSITIVE_INTENSITY_LVL], columnNames));
lines.add(createDataLine(" unassessed", maxTagNameLength, basicResultData[UNASSESSED], columnNames));
lines.add(createBorderLine(maxTagNameLength, columnNames));
lines.add(new StringBuffer("most prominent"));
lines.add(createDataLine(" count", maxTagNameLength, basicResultData[MP_COUNT], columnNames));
lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[MP_DUPLICATES], columnNames));
lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[MP_INTENSITY_LVL], columnNames));
lines.add(createDataLine(" true positives", maxTagNameLength, basicResultData[MP_TRUE_POSITIVE], columnNames));
lines.add(createDataLine(" duplicates", maxTagNameLength, basicResultData[MP_TRUE_POSITIVE_DUPLICATES], columnNames));
lines.add(createDataLine(" intensity level", maxTagNameLength, basicResultData[MP_TRUE_POSITIVE_INTENSITY_LVL], columnNames));
lines.add(createDataLine(" unassessed", maxTagNameLength, basicResultData[MP_UNASSESSED], columnNames));
lines.add(createBorderLine(maxTagNameLength, columnNames));
for (Map.Entry>> tagStats : tagCounters.entrySet()) {
StringBuffer line = new StringBuffer();
line.append(tagStats.getKey());
for (int i = tagStats.getKey().length(); i < maxTagNameLength; i++) {
line.append(' ');
}
for (String columnName : columnNames) {
String numberStr = "";
if (tagStats.getValue().get(columnName) != null) {
numberStr += tagStats.getValue().get(columnName).size();
while (numberStr.length() < 5) {
numberStr += ' ';
}
numberStr += "(" + getIntensityLevel(tagStats.getValue().get(columnName)) + ")";
}
line.append(" | ");
line.append(numberStr);
for (int i = numberStr.length(); i < columnName.length(); i++) {
line.append(' ');
}
}
lines.add(line);
}
for (int i = 0; i < maxTagNameLength; i++) {
System.out.print(' ');
}
for (String columnName : columnNames) {
System.out.print(" | " + columnName);
}
System.out.println();
for (StringBuffer line : lines) {
System.out.println(line);
}
}
/**
*
*/
private StringBuffer createBorderLine(int firstColumnWith, List columnNames) {
StringBuffer line = new StringBuffer();
for (int i = 0; i < firstColumnWith; i++) {
line.append('-');
}
for (String columnName : columnNames) {
line.append("-|-");
for (int j = 0; j < columnName.length(); j++) {
line.append('-');
}
}
return line;
}
/**
*
*/
private StringBuffer createDataLine(String lineName,
int firstColumnWith,
int[] values,
List columnNames)
{
StringBuffer line = new StringBuffer();
line.append(lineName);
for (int i = lineName.length(); i < firstColumnWith; i++) {
line.append(' ');
}
for (int i = 0; i < values.length; i++) {
String numberStr = "" + values[i];
line.append(" | ");
line.append(numberStr);
for (int j = numberStr.length(); j < columnNames.get(i).length(); j++) {
line.append(' ');
}
}
return line;
}
/**
*
*/
private int getDuplicates(List allSmells) {
int duplicateCount = 0;
for (UsabilitySmell smell1 : allSmells) {
if (smell1.getSmellingTask() != null) {
for (UsabilitySmell smell2 : allSmells) {
if ((smell2.getSmellingTask() != null) &&
(smell1.getSmellingTask() != smell2.getSmellingTask()) &&
(TaskTreeUtils.isChild(smell1.getSmellingTask(), smell2.getSmellingTask())))
{
duplicateCount++;
break;
}
}
}
}
return duplicateCount;
}
/**
*
*/
private int getIntensityLevel(List smellList) {
if (smellList.size() <= 0) {
return -1;
}
LinkedList smellsToConsider = new LinkedList<>();
// determine the smells with the highest intensity
for (UsabilitySmell smell : smellList) {
boolean added = false;
ListIterator it = smellsToConsider.listIterator();
while (it.hasNext()) {
if (it.next().getIntensity().getRatio() < smell.getIntensity().getRatio()) {
it.previous();
it.add(smell);
added = true;
break;
}
}
if (!added) {
smellsToConsider.add(smell);
}
while (smellsToConsider.size() > 5) {
smellsToConsider.removeLast();
}
}
// calculate the average intensity of the smells with the highest intensity
int cummulativeIntensity = 0;
for (UsabilitySmell smell : smellsToConsider) {
cummulativeIntensity += smell.getIntensity().getRatio();
}
return cummulativeIntensity / smellsToConsider.size();
}
/*
* (non-Javadoc)
*
* @see de.ugoe.cs.util.console.Command#help()
*/
@Override
public String help() {
return "usabilityStatistics []*";
}
}