package scrum.server.sprint;
import ilarkesto.base.Str;
import ilarkesto.base.Utl;
import ilarkesto.base.time.Date;
import ilarkesto.core.logging.Log;
import java.util.List;
import java.util.Set;
import scrum.server.admin.User;
import scrum.server.common.Numbered;
import scrum.server.project.Project;
import scrum.server.project.Requirement;
import scrum.server.project.RequirementDao;
import scrum.server.release.Release;
import scrum.server.release.ReleaseDao;
public class Sprint extends GSprint implements Numbered {
private static final Log LOG = Log.get(Sprint.class);
// --- dependencies ---
private static RequirementDao requirementDao;
private static TaskDao taskDao;
private static SprintDaySnapshotDao sprintDaySnapshotDao;
private static ReleaseDao releaseDao;
public static void setReleaseDao(ReleaseDao releaseDao) {
Sprint.releaseDao = releaseDao;
}
public static void setRequirementDao(RequirementDao storyDao) {
Sprint.requirementDao = storyDao;
}
public static void setTaskDao(TaskDao taskDao) {
Sprint.taskDao = taskDao;
}
public static void setSprintDaySnapshotDao(SprintDaySnapshotDao sprintDaySnapshotDao) {
Sprint.sprintDaySnapshotDao = sprintDaySnapshotDao;
}
// --- ---
public Release getRelease() {
Set<Release> releases = getReleases();
return releases.isEmpty() ? null : Utl.getElement(releases, 0);
}
public Set<Release> getReleases() {
return releaseDao.getReleasesBySprint(this);
}
public void close() {
float velocity = 0;
StringBuilder sb = new StringBuilder();
for (Requirement requirement : getRequirements()) {
if (requirement.isClosed()) {
Float work = requirement.getEstimatedWork();
if (work != null) velocity += work;
sb.append("* ");
sb.append(requirement.getLabel());
sb.append("\n");
for (Task task : requirement.getTasks()) {
taskDao.deleteEntity(task);
}
} else {
for (Task task : requirement.getTasks()) {
if (task.isClosed()) {
taskDao.deleteEntity(task);
} else {
task.reset();
}
}
}
requirement.setSprint(null);
}
setCompletedRequirementLabels(sb.toString());
setVelocity(velocity);
Project project = getProject();
project.setVelocity(Math.round(velocity));
setProductOwners(project.getProductOwners());
setScrumMasters(project.getScrumMasters());
setTeamMembers(project.getTeamMembers());
}
public String getProductOwnersAsString() {
return Str.concat(User.getNames(getProductOwners()), ", ");
}
public String getScrumMastersAsString() {
return Str.concat(User.getNames(getScrumMasters()), ", ");
}
public String getTeamMembersAsString() {
return Str.concat(User.getNames(getTeamMembers()), ", ");
}
public List<SprintDaySnapshot> getDaySnapshots() {
return sprintDaySnapshotDao.getSprintDaySnapshots(this);
}
public Set<SprintDaySnapshot> getExistingDaySnapshots() {
return sprintDaySnapshotDao.getSprintDaySnapshotsBySprint(this);
}
public Integer getLengthInDays() {
if (!isBeginSet() || !isEndSet()) return null;
return getBegin().getPeriodTo(getEnd()).toDays();
}
public SprintDaySnapshot getDaySnapshot(Date date) {
return sprintDaySnapshotDao.getSprintDaySnapshot(this, date, true);
}
public int getRemainingWork() {
int sum = 0;
for (Task task : getTasks()) {
Integer effort = task.getRemainingWork();
if (effort != null) sum += effort;
}
return sum;
}
public int getBurnedWork() {
int sum = 0;
for (Task task : getTasks()) {
sum += task.getBurnedWork();
}
return sum;
}
public Set<Requirement> getRequirements() {
return requirementDao.getRequirementsBySprint(this);
}
public Set<Task> getTasks() {
return taskDao.getTasksBySprint(this);
}
public String getReference() {
return scrum.client.sprint.Sprint.REFERENCE_PREFIX + getNumber();
}
@Override
public void updateNumber() {
if (getNumber() == 0) setNumber(getProject().generateSprintNumber());
}
@Override
public void ensureIntegrity() {
super.ensureIntegrity();
updateNumber();
if (getProject().isCurrentSprint(this)) {
if (!isBeginSet()) setBegin(Date.today());
if (!isEndSet()) setEnd(getBegin().addDays(14));
}
// delete when not current and end date older than 4 weeks
// if (isEndSet() && !getProject().isCurrentSprint(this) && getEnd().isPast()
// && getEnd().getPeriodToNow().toWeeks() > 4) {
// LOG.info("Deleting sprint, which ended on", getEnd(), "->", toString());
// getDao().deleteEntity(this);
// }
}
@Override
public boolean isVisibleFor(User user) {
return getProject().isVisibleFor(user);
}
public String getReferenceAndLabel() {
return getReference() + " " + getLabel();
}
@Override
public String toString() {
return getReferenceAndLabel();
}
public void burndownTasksRandomly(Date begin, Date end) {
int days = getBegin().getPeriodTo(getEnd()).toDays();
days -= (days / 7) * 2;
int defaultWorkPerDay = getRemainingWork() / days;
getDaySnapshot(begin).updateWithCurrentSprint();
begin = begin.nextDay();
while (begin.isBefore(end)) {
if (!begin.isWeekend()) {
int toBurn = Utl.randomInt(0, defaultWorkPerDay + (defaultWorkPerDay * 2));
int totalRemaining = getRemainingWork();
for (Task task : getTasks()) {
if (toBurn == 0) break;
int remaining = task.getRemainingWork();
int burn = Math.min(toBurn, remaining);
remaining -= burn;
toBurn -= burn;
task.setBurnedWork(task.getBurnedWork() + burn);
if (Utl.randomInt(1, 10) == 1) {
remaining += Utl.randomInt(-defaultWorkPerDay * 2, defaultWorkPerDay * 3);
}
if (totalRemaining == 0) {
remaining += Utl.randomInt(defaultWorkPerDay * 3, defaultWorkPerDay * 5);
totalRemaining = remaining;
}
task.setRemainingWork(remaining);
}
}
getDaySnapshot(begin).updateWithCurrentSprint();
begin = begin.nextDay();
}
}
}