package org.netmelody.cieye.spies.demo;
import static java.util.Collections.unmodifiableList;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
public final class DemoModeFakeCiServer {
private final Map<String, BuildTarget> targets = new HashMap<String, BuildTarget>();
public DemoModeFakeCiServer(String featureName) {
targets.put(featureName + " - Smoke", new BuildTarget(featureName + " - Smoke"));
targets.put(featureName + " - Integration", new BuildTarget(featureName + " - Integration"));
targets.put(featureName + " - Acceptance", new BuildTarget(featureName + " - Acceptance"));
targets.put(featureName + " - Release", new BuildTarget(featureName + " - Release"));
}
public List<String> getTargetNames() {
final List<String> result = new ArrayList<String>();
for (BuildTarget target : targets.values()) {
result.add(target.getName());
}
return result;
}
public void addNote(String targetName, String note) {
final BuildTarget buildTarget = targets.get(targetName);
if (null != buildTarget) {
buildTarget.addNote(note);
}
}
public TargetData getDataFor(String targetName) {
final BuildTarget buildTarget = targets.get(targetName);
synchronized(buildTarget) {
buildTarget.recalculate();
final List<BuildData> buildData = new ArrayList<BuildData>();
for (ActiveBuild build : buildTarget.builds) {
buildData.add(new BuildData(build.progress, build.green, "dracula"));
}
return new TargetData(buildTarget.url, buildTarget.green, buildTarget.note, buildData);
}
}
public static final class TargetData {
public final String url;
public final boolean green;
public final List<BuildData> builds;
public final String note;
public TargetData(String url, boolean green, String note, List<BuildData> buildData) {
this.url = url;
this.green = green;
this.note = note;
this.builds = unmodifiableList(new ArrayList<BuildData>(buildData));
}
}
public static final class BuildData {
public final int progress;
public final boolean green;
public final String checkinComments;
public BuildData(int progress, boolean green, String comment) {
this.progress = progress;
this.green = green;
this.checkinComments = comment;
}
}
private static final class BuildTarget {
private final Random random = new Random();
private final String targetName;
private final String url;
private boolean green;
private String note = "";
private final List<ActiveBuild> builds = new ArrayList<ActiveBuild>();
private long lastUpdateTime = System.currentTimeMillis();
public BuildTarget(String targetName) {
this.targetName = targetName;
this.url = "http://www.example.com/" + targetName;
green = random.nextInt(5) != 0;
if (random.nextInt(5) == 0) {
builds.add(new ActiveBuild());
}
}
public void recalculate() {
final long currentTime = System.currentTimeMillis();
final long ticksPassed = (currentTime - lastUpdateTime) / 1000;
advanceBy((int)ticksPassed);
this.lastUpdateTime = currentTime;
}
public void addNote(String note) {
if (!green) {
this.note = note;
}
}
public String getName() {
return targetName;
}
public void advanceBy(int percent) {
Iterator<ActiveBuild> buildIterator = builds.iterator();
while (buildIterator.hasNext()) {
ActiveBuild build = buildIterator.next();
build.advanceBy(percent);
if (build.complete()) {
buildIterator.remove();
green = build.green;
note = "";
}
}
if (builds.isEmpty()) {
if (random.nextInt(green ? 30 : 10) == 0) {
builds.add(new ActiveBuild(2));
}
}
}
}
private static final class ActiveBuild {
private final Random random = new Random();
private boolean green = true;
private int progress;
public ActiveBuild() {
progress = random.nextInt(101);
}
public synchronized boolean complete() {
return progress >= 100;
}
public ActiveBuild(int initialProgress) {
progress = initialProgress;
}
public void advanceBy(int percent) {
int prob = 0;
synchronized (this) {
final int oldProgress = progress;
progress = Math.min(100, progress + percent);
if (oldProgress > 90 || progress < 60) {
return;
}
prob = Math.max(Math.min(progress, 90) - 60, 0) - Math.min(oldProgress - 60, 0);
}
if (random.nextInt(100) < prob) {
green = false;
}
}
}
}