/* * Copyright [2014] [Christian Loehnert, krampenschiesser@gmail.com] * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.ks.idnadrev.entity; import de.ks.idnadrev.entity.information.ChartInfo; import de.ks.idnadrev.entity.information.Information; import de.ks.idnadrev.entity.information.TextInfo; import de.ks.idnadrev.entity.information.UmlDiagramInfo; import de.ks.persistence.converter.DurationConverter; import de.ks.persistence.converter.LocalDateConverter; import de.ks.persistence.converter.LocalDateTimeConverter; import de.ks.persistence.converter.LocalTimeConverter; import de.ks.persistence.entity.NamedPersistentObject; import de.ks.scheduler.Schedule; import javax.persistence.*; import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.*; @Entity public class Task extends NamedPersistentObject<Task> implements FileContainer<Task>, Tagged { private static final long serialVersionUID = 1L; private static final String TASK_TAG_JOINTABLE = "task_tag"; @Lob protected String description; @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "task") @OrderBy("start ASC") protected SortedSet<WorkUnit> workUnits = new TreeSet<>(); //tracking @Column(columnDefinition = "TIMESTAMP") @Convert(converter = LocalDateTimeConverter.class) protected LocalDateTime finishTime; @Column(columnDefinition = "BIGINT(19)") @Convert(converter = DurationConverter.class) protected Duration estimatedTime; @Column(columnDefinition = "DATE") @Convert(converter = LocalDateConverter.class) protected LocalDate dueDate;//must be done before this date (and time) @Column(columnDefinition = "TIME") @Convert(converter = LocalTimeConverter.class) protected LocalTime dueTime;//if null, only date relevant @ManyToOne(cascade = CascadeType.ALL) protected Schedule schedule; @ManyToOne protected Task parent; @OneToMany(mappedBy = "parent", cascade = {CascadeType.PERSIST, CascadeType.REMOVE}) protected Set<Task> children = new HashSet<>(); @Enumerated(EnumType.STRING) protected TaskState state = TaskState.NONE; protected String delegationReason; @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) protected Context context; @Embedded protected final Effort physicalEffort = new Effort(Effort.EffortType.PHSYICAL); @Embedded protected final Effort mentalEffort = new Effort(Effort.EffortType.MENTAL); @Embedded protected final Effort funFactor = new Effort(Effort.EffortType.FUN); protected boolean project; @Embedded protected Outcome outcome = new Outcome(); @ManyToMany(cascade = CascadeType.PERSIST) @JoinTable(name = TASK_TAG_JOINTABLE) protected Set<Tag> tags = new HashSet<>(); @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.DETACH}, orphanRemoval = true) @JoinTable(name = "task_file") protected Set<FileReference> files = new HashSet<>(); @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.DETACH}, mappedBy = "task") protected Set<ChartInfo> chartInfos = new HashSet<>(); @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.DETACH}, mappedBy = "task") protected Set<TextInfo> textInfos = new HashSet<>(); @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.DETACH}, mappedBy = "task") protected Set<UmlDiagramInfo> umlInfos = new HashSet<>(); protected Task() { // } public Task(String name) { super(name); } public Task(String name, String description) { this(name); this.description = description; } @Override public Set<FileReference> getFiles() { return files; } public String getDescription() { return description; } public String getShortDescription() { if ((description != null) && (description.length() > 50)) { return description.substring(0, 50); } else { return description; } } public Task setDescription(String description) { this.description = description; return this; } public long getSpentMinutes() { Duration duration = Duration.ZERO; for (WorkUnit workUnit : getWorkUnits()) { duration = duration.plus(workUnit.getDuration()); } return duration.toMinutes(); } public void start() { WorkUnit workUnit = new WorkUnit(this); getWorkUnits().add(workUnit); } public void stop() { WorkUnit last = getWorkUnits().last(); if (last.getEnd() == null) { last.stop(); } } public Task setFinished(boolean finished) { if (finished) { setState(TaskState.NONE); this.finishTime = LocalDateTime.now(); } else { this.finishTime = null; } return this; } public void setFinishTime(LocalDateTime finishTime) { this.finishTime = finishTime; } public boolean isFinished() { return finishTime != null; } public LocalDateTime getFinishTime() { return finishTime; } public SortedSet<WorkUnit> getWorkUnits() { return workUnits; } public Task getParent() { return parent; } public boolean hasParent(Task possibleParent) { for (Task current = this; current.getParent() != null; current = current.getParent()) { if (current.getParent().getId() == possibleParent.getId()) { return true; } } return false; } public void setParent(Task parent) { if (this.parent != null) { this.parent.getChildren().remove(this); } this.parent = parent; if (parent != null) { parent.addChild(this); } } public TaskState getState() { return state; } public Task setState(TaskState state) { this.state = state; return this; } public String getDelegationReason() { return delegationReason; } public Task setDelegationReason(String delegationReason) { this.delegationReason = delegationReason; return this; } public Context getContext() { return context; } public Task setContext(Context context) { this.context = context; return this; } public Effort getPhysicalEffort() { return physicalEffort; } public Effort getMentalEffort() { return mentalEffort; } public Effort getFunFactor() { return funFactor; } public boolean isProject() { return project; } public Task setProject(boolean project) { this.project = project; return this; } public Set<Task> getChildren() { return children; } public Task addChild(Task child) { getChildren().add(child); if (!this.equals(child.getParent())) { child.setParent(this); } this.setProject(true); return this; } public Duration getEstimatedTime() { if (estimatedTime == null) { return Duration.ofMinutes(0); } else { return estimatedTime; } } public Duration getRemainingTime() { return getEstimatedTime().minus(Duration.ofMinutes(getSpentMinutes())); } public Task setEstimatedTime(Duration estimatedTime) { this.estimatedTime = estimatedTime; return this; } @Override public Set<Tag> getTags() { return tags; } public Outcome getOutcome() { return outcome; } public Duration getTotalEstimatedTime() { Duration duration = estimatedTime; for (Task task : getChildren()) { Duration childDuration = task.getTotalEstimatedTime(); if (childDuration != null) { if (duration == null) { duration = childDuration; } else { duration = duration.plus(childDuration); } } } return duration; } public Duration getTotalWorkDuration() { if (getWorkUnits().isEmpty()) { return Duration.ofMillis(0); } Duration totalTime = getWorkUnits().stream().reduce(Duration.ofMillis(0), (duration, workunit) -> workunit.getDuration().plus(duration), (dur1, dur2) -> dur1.plus(dur2)); Duration took; if (getWorkUnits().last().getEnd() == null) { LocalDateTime start = getWorkUnits().last().getStart(); Duration lastDuration = Duration.between(start, LocalDateTime.now()); took = totalTime.plus(lastDuration); } else { took = totalTime; } return took; } public Schedule getSchedule() { return schedule; } public Task setSchedule(Schedule schedule) { this.schedule = schedule; return this; } public List<Information<?>> getInformation() { List<Information<?>> retval = new ArrayList<>(); retval.addAll(getUmlInfos()); retval.addAll(getTextInfos()); retval.addAll(getChartInfos()); return retval; } public Set<UmlDiagramInfo> getUmlInfos() { return umlInfos; } public Set<TextInfo> getTextInfos() { return textInfos; } public Set<ChartInfo> getChartInfos() { return chartInfos; } @Override public String toString() { return "Task [name=" + name + ", finishTime=" + finishTime + "]"; } }