package com.github.andlyticsproject.model;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import android.annotation.SuppressLint;
public class AppStatsSummary extends StatsSummary<AppStats> {
private Integer highestRatingChange = 0;
private Integer lowestRatingChange = 0;
public AppStatsSummary() {
overallStats = new AppStats();
}
@Override
public void addStat(AppStats stat) {
stat.init();
stats.add(stat);
}
@SuppressLint("SimpleDateFormat")
@Override
public void calculateOverallStats(int limit, boolean smoothEnabled) {
Collections.reverse(stats);
List<AppStats> missingAppStats = new ArrayList<AppStats>();
List<Integer> missingAppStatsPositionOffest = new ArrayList<Integer>();
int positionInsertOffset = 0;
// add missing sync days
if (stats.size() > 1) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
for (int currentIndex = 1; currentIndex < stats.size(); currentIndex++) {
String olderEntryDate = stats.get(currentIndex - 1).getRequestDateString();
String newerEntryDate = stats.get(currentIndex).getRequestDateString();
try {
Date olderDate = dateFormat.parse(olderEntryDate);
Date newerDate = dateFormat.parse(newerEntryDate);
long daysDistance = ((newerDate.getTime() - olderDate.getTime()) / 1000 / 60 / 60 / 24);
for (int i = 1; i < daysDistance; i++) {
AppStats missingEntry = new AppStats(stats.get(currentIndex - 1));
missingEntry.setDate(new Date(missingEntry.getDate()
.getTime() + (i * 1000 * 60 * 60 * 24)));
missingAppStats.add(missingEntry);
missingAppStatsPositionOffest.add(currentIndex + positionInsertOffset);
positionInsertOffset++;
}
} catch (ParseException e) {
e.printStackTrace();
}
}
}
for (int i = 0; i < missingAppStatsPositionOffest.size(); i++) {
stats.add(missingAppStatsPositionOffest.get(i), missingAppStats.get(i));
}
// calculate daily downloads
int nullStartIndex = -1;
boolean greaterNullDetected = false;
for (int currentIndex = 1; currentIndex < stats.size(); currentIndex++) {
// normalize daily, total & active
int olderTotalValue = stats.get(currentIndex - 1).getTotalDownloads();
int newerTotalValue = stats.get(currentIndex).getTotalDownloads();
int totalValueDiff = newerTotalValue - olderTotalValue;
int olderActiveValue = stats.get(currentIndex - 1).getActiveInstalls();
int newerActiveValue = stats.get(currentIndex).getActiveInstalls();
int activeValueDiff = newerActiveValue - olderActiveValue;
if (nullStartIndex > -1) {
if (totalValueDiff > 0) {
greaterNullDetected = true;
}
}
if (totalValueDiff == 0 && nullStartIndex < 0) {
nullStartIndex = currentIndex;
} else {
if (nullStartIndex != -1 && greaterNullDetected && smoothEnabled) {
// distance to fill with values
int distance = currentIndex - nullStartIndex + 1;
// smoothen values
int totalSmoothvalue = Math.round(totalValueDiff / distance);
int activeSmoothvalue = Math.round(activeValueDiff / distance);
// rounding
int roundingErrorTotal = newerTotalValue
- (olderTotalValue + ((totalSmoothvalue * (distance))));
int roundingErrorActive = newerActiveValue
- (olderActiveValue + ((activeSmoothvalue * (distance))));
;
int totalDownload = stats.get(nullStartIndex - 1).getTotalDownloads();
int activeInstall = stats.get(nullStartIndex - 1).getActiveInstalls();
for (int j = nullStartIndex; j < currentIndex + 1; j++) {
totalDownload += totalSmoothvalue;
activeInstall += activeSmoothvalue;
// for the last value, take rounding error in account
if (currentIndex == j) {
stats.get(j)
.setDailyDownloads(totalSmoothvalue + roundingErrorTotal);
stats.get(j).setTotalDownloads(totalDownload + roundingErrorTotal);
stats.get(j).setActiveInstalls(activeInstall + roundingErrorActive);
} else {
stats.get(j).setDailyDownloads(totalSmoothvalue);
stats.get(j).setTotalDownloads(totalDownload);
stats.get(j).setActiveInstalls(activeInstall);
}
stats.get(j).setSmoothingApplied(true);
}
nullStartIndex = -1;
greaterNullDetected = false;
} else {
stats.get(currentIndex).setDailyDownloads(totalValueDiff);
}
}
}
// reduce if limit exceeded (only if sync < 24h)
if (stats.size() > limit) {
stats = stats.subList(stats.size() - limit, stats.size());
}
float overallActiveInstallPercent = 0;
float overallAvgRating = 0;
// create rating diff
AppStats prevStats = null;
int value = 0;
for (int i = 0; i < stats.size(); i++) {
AppStats stat = stats.get(i);
if (prevStats != null) {
value = stat.getRating1() - prevStats.getRating1();
if (value > highestRatingChange)
highestRatingChange = value;
if (value < lowestRatingChange)
lowestRatingChange = value;
stat.setRating1Diff(value);
value = stat.getRating2() - prevStats.getRating2();
if (value > highestRatingChange)
highestRatingChange = value;
if (value < lowestRatingChange)
lowestRatingChange = value;
stat.setRating2Diff(value);
value = stat.getRating3() - prevStats.getRating3();
if (value > highestRatingChange)
highestRatingChange = value;
if (value < lowestRatingChange)
lowestRatingChange = value;
stat.setRating3Diff(value);
value = stat.getRating4() - prevStats.getRating4();
if (value > highestRatingChange)
highestRatingChange = value;
if (value < lowestRatingChange)
lowestRatingChange = value;
stat.setRating4Diff(value);
value = stat.getRating5() - prevStats.getRating5();
if (value > highestRatingChange)
highestRatingChange = value;
if (value < lowestRatingChange)
lowestRatingChange = value;
stat.setRating5Diff(value);
stat.setAvgRatingDiff(stat.getAvgRating() - prevStats.getAvgRating());
stat.setRatingCountDiff(stat.getRatingCount() - prevStats.getRatingCount());
stat.setNumberOfCommentsDiff(stat.getNumberOfComments()
- prevStats.getNumberOfComments());
stat.setActiveInstallsDiff(stat.getActiveInstalls()
- prevStats.getActiveInstalls());
}
prevStats = stat;
overallActiveInstallPercent += stat.getActiveInstallsPercent();
overallAvgRating += stat.getAvgRating();
}
if (stats.size() > 0) {
AppStats first = stats.get(0);
AppStats last = stats.get(stats.size() - 1);
overallStats.setActiveInstalls(last.getActiveInstalls() - first.getActiveInstalls());
overallStats.setTotalDownloads(last.getTotalDownloads() - first.getTotalDownloads());
overallStats.setRating1(last.getRating1() - first.getRating1());
overallStats.setRating2(last.getRating2() - first.getRating2());
overallStats.setRating3(last.getRating3() - first.getRating3());
overallStats.setRating4(last.getRating4() - first.getRating4());
overallStats.setRating5(last.getRating5() - first.getRating5());
overallStats.init();
overallStats.setDailyDownloads((last.getTotalDownloads() - first.getTotalDownloads())
/ stats.size());
BigDecimal avgBigDecimal = new BigDecimal(overallAvgRating / stats.size());
avgBigDecimal = avgBigDecimal.setScale(3, BigDecimal.ROUND_HALF_UP);
overallStats.setAvgRatingString(avgBigDecimal.toPlainString() + "");
BigDecimal percentBigDecimal = new BigDecimal(overallActiveInstallPercent
/ stats.size());
percentBigDecimal = percentBigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP);
overallStats.setActiveInstallsPercentString(percentBigDecimal.toPlainString() + "");
double totalRevenue = 0;
String currency = null;
for (AppStats as : stats) {
if (as.getTotalRevenue() != null) {
totalRevenue += as.getTotalRevenue().getAmount();
if (currency == null) {
currency = as.getTotalRevenue().getCurrencyCode();
}
}
}
if (currency != null) {
overallStats
.setTotalRevenue(new Revenue(Revenue.Type.TOTAL, totalRevenue, currency));
}
}
}
@Override
public boolean applySmoothedValues() {
for (AppStats stat : stats) {
if (stat.isSmoothingApplied()) {
return true;
}
}
return false;
}
public void setLowestRatingChange(Integer lowestRatingChange) {
this.lowestRatingChange = lowestRatingChange;
}
public Integer getLowestRatingChange() {
return lowestRatingChange;
}
public void setHighestRatingChange(Integer highestRatingChange) {
this.highestRatingChange = highestRatingChange;
}
public Integer getHighestRatingChange() {
return highestRatingChange;
}
}