package info.interactivesystems.gamificationengine.entities.goal; import info.interactivesystems.gamificationengine.entities.task.FinishedTask; import info.interactivesystems.gamificationengine.entities.task.Task; import info.interactivesystems.gamificationengine.utils.Progress; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; import javax.persistence.Inheritance; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A DoAnyTaskRule defines a task rule by which only one of all mentioned tasks have to be fulfilled. If is this * task is finsihed the goal rule an so the associated goal is completed. */ @Entity @Inheritance @DiscriminatorValue("TRULEANY") public class DoAnyTaskRule extends TaskRule { private static final Logger LOGGER = LoggerFactory.getLogger(DoAllTasksRule.class); /** * Gets the tasks of a DoAnyTaskRule that are already finished. So the user gets a status which tasks she/he * dosen't have to complete any more. Therefore a list of finished tasks that were done by a specific * player is filtered if they already needed for this rule. If a task was done and is needed for fulfilling * the rule it is added to a list. * * @param finishedPlayerTasks * The list of all tasks a specific player has already done. * @param lastDate * Optionally a date can be passed. If it isn't null all tasks after this date are checked. * @return The list of already completed tasks of a task rule. */ public List<Task> getCompletedTasks(List<FinishedTask> finishedPlayerTasks, LocalDateTime lastDate) { List<Task> completedTasks = new ArrayList<>(); List<Task> finishedTasks; if (lastDate != null) { // grouping and counting finished tasks finishedTasks = finishedPlayerTasks.stream().filter(o -> tasks.contains(o.getTask()) && o.getFinishedDate().isAfter(lastDate)) .map(FinishedTask::getTask).collect(Collectors.toList()); } else { // grouping and counting finished tasks finishedTasks = finishedPlayerTasks.stream().filter(o -> tasks.contains(o.getTask())).map(FinishedTask::getTask) .collect(Collectors.toList()); } for (Task task : tasks) { if (finishedTasks.remove(task)) { completedTasks.add(task); } } return completedTasks; } /** * Gets the tasks of a DoAnyTaskRule that are not finished yet. So the user gets a status which tasks she/he * can complete for fulfilling this rule. Therefore a list of finished tasks that were done by a specific * player is filtered if they needed for this rule. If a task wasn't already done and is needed for fulfilling * the rule it is added to a list. * * @param finishedPlayerTasks * The list of all tasks a specific player has already done. * @param lastDate * The date after all tasks are checked if they were completed in this period of time. * @return A list of missing tasks which have to be completed until the task rule is fulfilled. */ public List<Task> getUncompletedTasks(List<FinishedTask> finishedPlayerTasks, LocalDateTime lastDate) { // grouping and counting unfinished tasks List<Task> uncompletedTasks = tasks.stream().filter(o -> !getCompletedTasks(finishedPlayerTasks, lastDate).contains(o)) .collect(Collectors.toList()); return uncompletedTasks; } /** * This method checks if a DoAnyTaskRule is fulfilled. Therefore the list of all already finished tasks is * checked if all needed tasks are in this list. If they are, they are added to a list. In the end it is * checked if at least one task of the rule is completed. If it does, true is returned otherwise false is * returned. * * @param finishedPlayerTasks * The list of already finished tasks a player has already completed. * @param lastDate * Optionally a date can be passed. If it isn't null all tasks after this date are checked. */ @Override public boolean checkRule(List<FinishedTask> finishedPlayerTasks, LocalDateTime lastDate) { Map<String, Long> finishedTasks; LOGGER.debug("DoAnyTaskRule! "); if (lastDate != null) { // grouping and counting finished tasks after last finishedDate finishedTasks = finishedPlayerTasks.stream().filter(o -> tasks.contains(o.getTask()) && o.getFinishedDate().isAfter(lastDate)) .collect(Collectors.groupingBy(o -> o.getTask().getTaskName(), Collectors.counting())); } else { // grouping and counting finished tasks finishedTasks = finishedPlayerTasks.stream().filter(o -> tasks.contains(o.getTask())) .collect(Collectors.groupingBy(o -> o.getTask().getTaskName(), Collectors.counting())); } // check if at least one task has been completed if (finishedTasks.isEmpty()) { return false; } return true; } /** * Returns the progress of the task rule. This progress is represented by the number of the already * finished tasks and the number of tasks which has to be completed for fulfilling this rule. * * @param finishedPlayerTasks * The number of finished tasks a player has already completed. This list is checked which * tasks are needed for the rule. * @param lastDate * Optionally a date can be passed. If it isn't null all tasks after this date are checked. */ @Override public Progress getProgress(List<FinishedTask> finishedPlayerTasks, LocalDateTime lastDate) { Progress progress = new Progress(getCompletedTasks(finishedPlayerTasks, lastDate).size(), getTasks().size()); return progress; } }