package org.zalando.catwatch.backend.util;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.zalando.catwatch.backend.model.Project;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Class to collect Projects stats
*
* This class collects the statistics from a List of Project objects in a more compact manner
* so that it can then be returned from the /statistics/projects REST endpoint.
*
* Essentially, the fields which are always the same (such as "name"...) are stored only once
* and the counts (such as "commitCounts") are put into arrays of their own.
*
*/
public class ProjectStats {
private String name;
private String organizationName;
private String url;
private String description;
private String primaryLanguage;
private List<Integer> commitCounts;
private List<Integer> forkCounts;
private List<Integer> contributorsCounts;
private List<Integer> scores;
private List<Date> snapshotDates;
public ProjectStats(List<Project> projects) {
Project first = projects.get(0);
name = first.getName();
organizationName = first.getOrganizationName();
url = first.getUrl();
description = first.getDescription();
primaryLanguage = first.getPrimaryLanguage();
projects.sort((o1, o2) -> o1.getSnapshotDate().compareTo(o2.getSnapshotDate()));
int size = projects.size();
commitCounts = new ArrayList<>(size);
forkCounts = new ArrayList<>(size);
snapshotDates = new ArrayList<>(size);
contributorsCounts = new ArrayList<>(size);
scores = new ArrayList<>(size);
int i = 0;
Date lastSnapshotDate = null;
for (Project p: projects) {
if (!p.getName().equals(name)) {
throw new IllegalArgumentException("All projects in the list must refer to the same project!");
}
if (lastSnapshotDate == null || !p.getSnapshotDate().equals(lastSnapshotDate)) {
commitCounts.add(i, p.getCommitsCount());
forkCounts.add(i, p.getForksCount());
contributorsCounts.add(i, p.getContributorsCount());
scores.add(i, p.getScore());
snapshotDates.add(i, p.getSnapshotDate());
i++;
}
lastSnapshotDate = p.getSnapshotDate();
}
}
@JsonProperty(value="name")
public String getName() { return name; }
@JsonProperty(value="organization_name")
public String getOrganizationName() { return organizationName; }
@JsonProperty(value="url")
public String getUrl() { return url; }
@JsonProperty(value="primary_language")
public String getPrimaryLanguage() { return primaryLanguage; }
@JsonProperty(value="description")
public String getDescription() { return description; }
@JsonProperty(value="commit_counts")
public List<Integer> getCommitCounts() { return commitCounts; }
@JsonProperty(value="fork_counts")
public List<Integer> getForkCounts() { return forkCounts; }
@JsonProperty(value="contributors_counts")
public List<Integer> getContributorsCounts() { return contributorsCounts; }
@JsonProperty(value="scores")
public List<Integer> getScores() { return scores; }
@JsonProperty(value="snapshot_dates")
@JsonSerialize(using = JsonDateListSerializer.class)
public List<Date> getSnapshotDates() { return snapshotDates; }
public static List<ProjectStats> buildStats(List<Project> projects) {
Map<String,List<Project>> projectsByName = getDistinctProjects(projects);
return projectsByName.values().stream()
.map(ProjectStats::new)
.collect(Collectors.toCollection(LinkedList::new));
}
/**
* Take a list of projects and return a map of lists where projects have been partitioned
* by names.
*
* @param projects list consisting of potentially different projects
* @return a map which contains the list separated by project, using the name as index.
*/
public static Map<String,List<Project>> getDistinctProjects(List<Project> projects) {
Map<String,List<Project>> result = new HashMap<>();
for (Project project: projects) {
String name = project.getName();
List<Project> list = result.get(name);
if (list == null) {
list = new LinkedList<>();
result.put(name, list);
}
list.add(project);
}
return result;
}
@Override
public String toString() {
return String.format("ProjectStats(%s, commitCounts=%s, forkCounts=%s, snapshotDates=%s)", name, commitCounts, forkCounts, snapshotDates);
}
}