package info.interactivesystems.gamificationengine.entities.goal;
import info.interactivesystems.gamificationengine.entities.Organisation;
import info.interactivesystems.gamificationengine.entities.Player;
import info.interactivesystems.gamificationengine.entities.PlayerGroup;
import info.interactivesystems.gamificationengine.entities.Role;
import info.interactivesystems.gamificationengine.entities.rewards.Reward;
import info.interactivesystems.gamificationengine.entities.task.FinishedTask;
import info.interactivesystems.gamificationengine.utils.StringUtils;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.validation.constraints.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* A Goal comprises one or more tasks and is associated with a goal rule. If the player wants to earn the
* connected awards the rule has to be fulfilled. To create a goal some already created components are needed.
* So the condition when a goal is completed is defined in the goal rule and the connected tasks. Who can
* complete a goal is defined by the role of a player and whether it can be done by a group. It is also
* possible to define whether a goal is repeatable so that the player can complete the tasks and obtains its
* coins and points as rewards again. All goals that are associated with the organisation can be requested
* or like the elements before only one specific goal, if the correspondent id is used. The name, the
* associated rewards and also the rule for completion can be changed as well as the indication if the goal is
* repeatable or a goal that can be reached by a group. Is is also possible to change the roles so different
* people can complete the goal.
*
*/
@Entity
@JsonIgnoreProperties({ "belongsTo", "finishedGoals" })
public class Goal {
private static final Logger LOGGER = LoggerFactory.getLogger(Goal.class);
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@NotNull
@ManyToOne
private Organisation belongsTo;
private String name;
@NotNull
@ManyToOne
private GoalRule rule;
private boolean repeatable;
private boolean playerGroupGoal;
@ManyToMany(fetch = FetchType.EAGER)
@JsonBackReference
private List<Reward> rewards;
@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
private List<Role> canCompletedBy;
@OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER, mappedBy="goal")
private List<FinishedGoal> finishedGoals;
public List<FinishedGoal> getFinishedGoals() {
return finishedGoals;
}
public Goal() {
rewards = new ArrayList<>();
}
/**
Gets the id of the goal.
*
* @return The goal's id as int.
*/
public int getId() {
return id;
}
/**
* Sets the id of the goal.
*
* @param id
* The id of the goal henceforth.
*/
public void setId(int id) {
this.id = id;
}
/**
* The organisation the goal belongs to. This parameter must
* not be null
*
* @return The organisations object the goal belongs to.
*/
public Organisation getBelongsTo() {
return belongsTo;
}
/**
* Sets the organisation to which this goal belongs. The parameter
* must not be null.
*
* @param belongsTo
* The organisation to which the goal belongs to henceforth.
*/
public void setBelongsTo(Organisation belongsTo) {
this.belongsTo = belongsTo;
}
/**
* Gets the name of the goal.
*
* @return The name of the goal as String.
*/
public String getName() {
return name;
}
/**
* Sets the name of the goal.
*
* @param name
* The new name of the goal as String.
*/
public void setName(String name) {
this.name = name;
}
/**
* Gets the rule that defines which tasks have to be completed how to fulfil the goal.
*
* @return The goal rule of this goal.
*/
public GoalRule getRule() {
return rule;
}
/**
* Sets the rule of this goal which defines the needed tasks for fulfilling the goal.
*
* @param rule
* The rule for this goal.
*/
public void setRule(GoalRule rule) {
this.rule = rule;
}
/**
* Gets the value if the goal is repeatable. If it is this method returns true otherwise false.
*
* @return The value if the goal is repeatable (true) or not (false).
*/
public boolean isRepeatable() {
return repeatable;
}
/**
* Sets the value if the goal is repeatable (true) or not (false).
*
* @param repeatable
* Value of the goal's repeatability. True if it is, otherwise false.
*/
public void setRepeatable(boolean repeatable) {
this.repeatable = repeatable;
}
/**
* Gets the value if the goal if a group goal. If it is this method returns true otherwise false.
*
* @return The value if the goal is also a group goal (true) or not (false).
*/
public boolean isPlayerGroupGoal() {
return playerGroupGoal;
}
/**
* Sets the value if the goal is also a group goal (true) or not (false).
*
* @param playerGroupGoal
* Value if the goal is a group goal. True if it is, otherwise false.
*/
public void setPlayerGroupGoal(boolean playerGroupGoal) {
this.playerGroupGoal = playerGroupGoal;
}
/**
* Gets the List of rewards that are associated with the goal. All rewards can be earned
* by the player who completes the goal.
*
* @return All rewards a player can earn by fulfilling the goal as a List.
*/
public List<Reward> getRewards() {
return rewards;
}
/**
* Sets the List of that are associated with the goal. All rewards can be earned
* by the player who completes the goal.
*
* @param rewards List of rewards a player can earn by fulfilling the goal as List.
*/
public void setRewards(List<Reward> rewards) {
this.rewards = rewards;
}
/**
* Adds one or more rewards to the list of rewards which can be earned by a player.
*
* @param reward The rewards that should be added to the list of rewards.
*/
public void addRewards(List<Reward> reward) {
rewards.addAll(rewards);
}
/**
* Adds one reward to the list of rewards which can be earned by a player.
*
* @param reward The reward that should be added to the list of rewards.
*/
public void addReward(Reward reward) {
rewards.add(reward);
}
/**
* This method checks if a goal belongs to a specific organisation. Therefore
* it is tested if the organisation's API key matchs the group's API key.
*
* @param organisation
* The organisation object a goal may belongs to.
* @return Boolean value if the API key of the goal is the same
* of the tested organisation (true) or not (false).
*/
public boolean belongsTo(Organisation organisation) {
return getBelongsTo().getApiKey().equals(organisation.getApiKey());
}
/**
* Gets all a roles to check if a player is allowed to fulfil a goal. Therefore a player has to own
* at least one of these roles.
*
* @return All roles who are allowed to complete the goal as list.
*/
public List<Role> getCanCompletedBy() {
return canCompletedBy;
}
/**
* Sets all roles which are needed to test if a player is allowed to fulfil a goal. Therefore a player has
* to own at least one of these roles.
*
* @param canCompletedBy All roles who are allowed to complete the goal as list.
*/
public void setCanCompletedBy(List<Role> canCompletedBy) {
this.canCompletedBy = canCompletedBy;
}
/**
* This method checks if a goal is completed after a task is finished. Therefore it is also checked if the
* goal is repeatable. If it is is can be fulfilled one more time otherwise the method stops.
*
* @param oldFinishedGoals
* The list of all goal a player has completed, yet.
* @param finishedTasksList
* The list of all already finished tasks of a player.
* @param rule
* The goal rule which is associated with the goal and indicates when the goal is completed.
* @return The just finished goal when the player hasn't finished it yet or if the goal can be finished one
* more time otherwise null is returned.
*/
public FinishedGoal checkGoal(Player player, PlayerGroup group, List<FinishedGoal> oldFinishedGoals, List<FinishedTask> finishedTasksList,
TaskRule rule) {
Goal goal = this;
LocalDateTime finishedDate = LocalDateTime.now();
LocalDateTime lastDate = null;
// checks if goal is already finished
if (oldFinishedGoals.size() > 0) {
// goal is already finished
LOGGER.debug("Goal: is on finishedGoals list");
// check if goal is repeatable
if (goal.isRepeatable()) {
// get finishedDate of last goal
LOGGER.debug("Goal: is repeatable");
lastDate = oldFinishedGoals.get(oldFinishedGoals.size() - 1).getFinishedDate();
LOGGER.debug("Goal: last finished: " + lastDate);
} else {
LOGGER.debug("Goal: is not repeatable -> break");
return null;
}
// checks if goal/rule is completed after lastDate
if (rule.checkRule(finishedTasksList, lastDate)) {
// add goal to tempFinishedGoals list
LOGGER.debug("Goal: Rule is completed! -> add to fGoalsList (temp)");
FinishedGoal fGoal = new FinishedGoal();
fGoal.setGoal(goal);
fGoal.setFinishedDate(finishedDate);
return fGoal;
}
} else {
// goal has not yet been finished
LOGGER.debug("Goal: is NOT on finished Goals list");
// checks if goal/rule is completed after lastDate
if (rule.checkRule(finishedTasksList, lastDate)) {
// add goal to tempFinishedGoals list
LOGGER.debug("Goal: Rule is completed! -> add to fGoalsList (temp)");
FinishedGoal fGoal = new FinishedGoal();
fGoal.setGoal(goal);
fGoal.setFinishedDate(finishedDate);
return fGoal;
}
}
return null;
}
public static void logGoalDetails(String name, String repeatable, String ruleId, String rewardIds, String roleIds, String isGroupGoal, String apiKey) {
LOGGER.debug("createNewGoal apiKey");
LOGGER.debug("apiKey: " + apiKey);
LOGGER.debug("name: " + name);
LOGGER.debug("repeatable: " + repeatable);
LOGGER.debug("ruleId: " + ruleId);
LOGGER.debug("rewardIds: " + rewardIds);
LOGGER.debug("rewardIds: " + roleIds);
}
/**
* * This method gets the ids of goals that have to be deleted before a specific
* object like a rule or reward can be deleted. These ids are then passed to create
* a message in the response to give the user a hint.
*
* @param goals
* List of goals that are associated with an object that should be deleted.
* @param objectToDelete
* The type of the object that should be deleted. This is only given by a String.
* @param type
* The type of the object that use the object, so it should be deleted before. This is only given
* by a String.
*/
public static void checkGoalsForDeletion(List<Goal> goals, String objectToDelete, String type) {
List<String> ids = getGoalIds(goals);
StringUtils.printIdsForDeletion(ids, objectToDelete , type);
}
/**
* Gets the id each goal that is in the passed List.
*
* @param goals
* List of goals of which the ids are returned.
* @return A list of Integers of the passed goals.
*/
public static List<String> getGoalIds(List<Goal> goals){
List<String> ids = new ArrayList<>();
for (Goal goal : goals) {
ids.add(Integer.toString(goal.getId()));
}
return ids;
}
}