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.Contributor;
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 the statistics of the contributors
*
* This class collect the statistics from a List of Contributor objects and
* put them in a more compact way.
* Specifically, the fields which have always the same value are storaged for
* only once. The counts and dates are put into an array of their own.
*
*/
public class ContributorStats {
private String name;
private List<String> organizationName;
private String url;
private List<Integer> organizationalCommitsCounts;
private List<Integer> personalCommitsCounts;
private List<Integer> organizationalProjectsCounts;
private List<Integer> personalProjectsCounts;
private List<Date> snapshotDates;
public ContributorStats(List<Contributor> contributions) {
Contributor first = contributions.get(0);
name = first.getName();
organizationName = new ArrayList<>();
url = first.getUrl();
contributions.sort((o1, o2) -> o1.getSnapshotDate().compareTo(o2.getSnapshotDate()));
int size = contributions.size();
organizationalCommitsCounts = new ArrayList<>(size);
personalCommitsCounts = new ArrayList<>(size);
organizationalProjectsCounts = new ArrayList<>(size);
personalProjectsCounts = new ArrayList<>(size);
snapshotDates = new ArrayList<>(size);
int i = 0;
Date lastSnapshotDate = null;
String lastOrganizationName = null;
for (Contributor c : contributions) {
String loginId = c.getLoginId();
if (loginId.isEmpty()) {
throw new IllegalArgumentException("Contributor loginId could not be determinated.");
}
if (!loginId.equals(first.getLoginId())) {
throw new IllegalArgumentException("All the contributors in the list must have the same loginId.");
}
if (lastSnapshotDate == null || !c.getSnapshotDate().equals(lastSnapshotDate)) {
organizationalCommitsCounts.add(i, c.getOrganizationalCommitsCount());
personalCommitsCounts.add(i, c.getPersonalCommitsCount());
organizationalProjectsCounts.add(i, c.getOrganizationalProjectsCount());
personalProjectsCounts.add(i, c.getPersonalProjectsCount());
snapshotDates.add(i, c.getSnapshotDate());
if (lastOrganizationName == null || !c.getOrganizationName().equals(lastOrganizationName)) {
organizationName.add(c.getOrganizationName());
}
i++;
}
// sum up the statistics if they are on the same day but for different organizations.
// the prerequisite condition is to have all entries ordered by the name, date,
if (lastSnapshotDate != null && c.getSnapshotDate().equals(lastSnapshotDate)) {
if (!c.getOrganizationName().equals(lastOrganizationName)) {
organizationalCommitsCounts.set(
i-1, organizationalCommitsCounts.get(i-1)+c.getOrganizationalCommitsCount());
//personalCommitsCounts.set(
// i-1, personalCommitsCounts.get(i-1)+c.getPersonalCommitsCount());
organizationalProjectsCounts.set(
i-1, organizationalProjectsCounts.get(i-1)+c.getOrganizationalProjectsCount());
personalProjectsCounts.set(
i-1, personalProjectsCounts.get(i-1)+c.getPersonalProjectsCount());
}
}
lastSnapshotDate = c.getSnapshotDate();
lastOrganizationName = c.getOrganizationName();
}
}
@JsonProperty(value="name")
public String getName() {return name;}
@JsonProperty(value="organization_name")
public List<String> getOrganizationName() {return organizationName;}
@JsonProperty(value="url")
public String getUrl() {return url;}
@JsonProperty(value="organization_commit_counts")
public List<Integer> getOrganizationalCommitsCounts() {return organizationalCommitsCounts;}
@JsonProperty(value="personal_commit_counts")
public List<Integer> getPersonalCommitsCounts() {return personalCommitsCounts;}
@JsonProperty(value="organization_project_counts")
public List<Integer> getOrganizationalProjectsCounts() {return organizationalProjectsCounts;}
@JsonProperty(value="personal_project_counts")
public List<Integer> getPersonalProjectsCounts() {return personalProjectsCounts;}
@JsonProperty(value="snapshot_dates")
@JsonSerialize(using = JsonDateListSerializer.class)
public List<Date> getSnapshotDates() { return snapshotDates; }
/**
* Take a list of contributors and return a list their statistics that are seperated
* by different contributors.
*
* @param contributors a list consisting of contributors.
* @return a list, each entry of which consists of statistics of the same contributors
* at different date.
*/
public static List<ContributorStats> buildStats(List<Contributor> contributors) {
Map<String, List<Contributor>> contributorByLoginId = getDistinctContributors(contributors);
return contributorByLoginId.values().stream()
.map(ContributorStats::new)
.collect(Collectors.toCollection(LinkedList::new));
}
/**
* Take a list of contributors and return a map of lists where contributors have been partitioned
* by loginId.
*
* @param contributors a list consisting of potentially different contributors.
* @return a map which contains the list separated by contributors, using the loginId as index.
*/
public static Map<String, List<Contributor>> getDistinctContributors(List<Contributor> contributors) {
Map<String, List<Contributor>> result = new HashMap<>();
for (Contributor contributor : contributors) {
String loginId = contributor.getLoginId();
if (loginId.isEmpty()) {
throw new IllegalArgumentException("Could not determinate loginId.");
}
List<Contributor> list = result.get(loginId);
if (list == null) {
list = new LinkedList<>();
result.put(loginId, list);
}
list.add(contributor);
}
return result;
}
@Override
public String toString() {
return String.format(
"ContributorStats(%s, %s, %s, %s)", name, organizationName, url, snapshotDates);
}
}