/*
* Copyright 2013 - 2014 Felix Müller
*
* This file is part of CodeQ Invest.
*
* CodeQ Invest is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CodeQ Invest 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CodeQ Invest. If not, see <http://www.gnu.org/licenses/>.
*/
package org.codeqinvest.web.investment.roi;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.codeqinvest.investment.InvestmentAmountParser;
import org.codeqinvest.investment.InvestmentParsingException;
import org.codeqinvest.investment.roi.RoiDistribution;
import org.codeqinvest.investment.roi.RoiDistributionCalculator;
import org.codeqinvest.quality.Project;
import org.codeqinvest.quality.analysis.LastQualityAnalysisService;
import org.codeqinvest.quality.analysis.QualityAnalysis;
import org.codeqinvest.quality.repository.ProjectRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* @author fmueller
*/
@Slf4j
@Controller
class RoiDistributionController {
private static final int ROI_THRESHOLD = 0;
private final ProjectRepository projectRepository;
private final LastQualityAnalysisService lastQualityAnalysisService;
private final RoiDistributionCalculator roiDistributionCalculator;
private final InvestmentAmountParser investmentAmountParser;
private final RoiDistributionFilter roiDistributionFilter;
@Autowired
RoiDistributionController(ProjectRepository projectRepository,
LastQualityAnalysisService lastQualityAnalysisService,
RoiDistributionCalculator roiDistributionCalculator,
InvestmentAmountParser investmentAmountParser,
RoiDistributionFilter roiDistributionFilter) {
this.projectRepository = projectRepository;
this.lastQualityAnalysisService = lastQualityAnalysisService;
this.roiDistributionCalculator = roiDistributionCalculator;
this.investmentAmountParser = investmentAmountParser;
this.roiDistributionFilter = roiDistributionFilter;
}
@RequestMapping(value = "/projects/{projectId}/roidistribution", method = RequestMethod.GET)
@ResponseBody
EnhancedRoiDistribution retrieveRoiDistribution(@PathVariable long projectId, @RequestParam(required = false) String basePackage) throws InvestmentParsingException {
Project project = projectRepository.findOne(projectId);
QualityAnalysis lastAnalysis = lastQualityAnalysisService.retrieveLastSuccessfulAnalysis(project);
Set<RoiDistribution> roiDistributions = Sets.newHashSet();
for (int i = 0; i < RoiDistributionChartRepresentation.DEFAULT_INVESTMENTS.length; i++) {
int investment = investmentAmountParser.parseMinutes(RoiDistributionChartRepresentation.DEFAULT_INVESTMENTS[i]);
roiDistributions.add(roiDistributionCalculator.calculateRoiDistribution(lastAnalysis, basePackage, investment));
}
Collection<RoiDistributionChartRepresentation> bestRois = convertToChartRepresentations(roiDistributionFilter.filterHighestRoi(
roiDistributions, RoiDistributionChartRepresentation.DEFAULT_INVESTMENTS.length + 1));
return new EnhancedRoiDistribution(
new TreeSet<RoiDistributionChartRepresentation>(filterChartDataByThreshold(convertToChartRepresentations(roiDistributions))),
new TreeSet<RoiDistributionChartRepresentation>(filterChartDataByThreshold(bestRois)));
}
private Collection<RoiDistributionChartRepresentation> convertToChartRepresentations(Collection<RoiDistribution> roiDistributions) throws InvestmentParsingException {
Map<String, RoiDistributionChartRepresentation> chartData = Maps.newHashMap();
for (RoiDistribution roiDistribution : roiDistributions) {
for (Map.Entry<String, Integer> roiOfArtefact : roiDistribution.getRoiByArtefact().entrySet()) {
String artefact = getLastPackageName(roiOfArtefact.getKey());
if (!chartData.containsKey(artefact)) {
chartData.put(artefact, new RoiDistributionChartRepresentation(artefact));
}
final int i = findInvestmentIndex(roiDistribution);
chartData.get(artefact).setValue(i, new ValueTuple(RoiDistributionChartRepresentation.DEFAULT_INVESTMENTS[i], roiOfArtefact.getValue()));
}
}
return chartData.values();
}
private int findInvestmentIndex(RoiDistribution roiDistribution) throws InvestmentParsingException {
for (int i = 0; i < RoiDistributionChartRepresentation.DEFAULT_INVESTMENTS.length; i++) {
if (investmentAmountParser.parseMinutes(RoiDistributionChartRepresentation.DEFAULT_INVESTMENTS[i]) == roiDistribution.getInvestInMinutes()) {
return i;
}
}
return -1;
}
private Collection<RoiDistributionChartRepresentation> filterChartDataByThreshold(Collection<RoiDistributionChartRepresentation> chartData) {
Set<RoiDistributionChartRepresentation> filteredChartData = Sets.newHashSet();
for (RoiDistributionChartRepresentation roiDistribution : chartData) {
for (ValueTuple value : roiDistribution.getValues()) {
if (value.getY() > ROI_THRESHOLD) {
filteredChartData.add(roiDistribution);
break;
}
}
}
return filteredChartData;
}
private String getLastPackageName(String artefactName) {
int indexOfLastPackageStart = artefactName.lastIndexOf(".");
return indexOfLastPackageStart != -1
? artefactName.substring(indexOfLastPackageStart + 1)
: artefactName;
}
}