@ApplicationException
public class ApiError extends WebApplicationException {

	private static final long serialVersionUID = 1L;

	/**
	 * 
	 * @param status
	 *            a HTTP status code.
	 * @param message
	 *            a description of the error cause.
	 */
	public ApiError(Response.Status status, String message) {
		this(status, message, new Object[] {});
	}

	/**
	 * @param status
	 *            a HTTP status code
	 * @param message
	 *            a description of the error cause, may be a formatted string.
	 * @param args
	 *            for format string, may be zero, see {@link String#format test}
	 *            .
	 */
	public ApiError(Response.Status status, String message, Object... args) {
		super(ResponseSurrogate.of(status, null, Notification.of(String.format(message, args))));
	}
} @Named
@Stateless
public class GoalDAO {
	@PersistenceContext(unitName = PersistenceUnit.PROJECT)
	private EntityManager em;

	/**
	 * Stores a new goal in the data base.
	 * 
	 * @param goal
	 *            The goal which should be stored in the data base.
	 * @return The id of the {@link Goal}.
	 */
	public int insertGoal(Goal goal) {
		em.persist(goal);
		em.flush();
		return goal.getId();
	}

	/**
	 * Stores a new finished goal in the data base.
	 * 
	 * @param goal
	 *            The finished goal which should be stored in the data base.
	 * @return The id of the {@link FinishedGoal}.
	 */
	public int insertFinishedGoal(FinishedGoal goal) {
		em.persist(goal);
		em.flush();
		return goal.getId();
	}

	/**
	 * Gets an goal from the data base.
	 * 
	 * @param id
	 *            The id of the goal.
	 * @param apiKey
	 *           The API key of the organisation to which the goal belongs to. 
	 * @return The {@link Goal} object or null if it wasn't found.
	 */
	public Goal getGoal(int id, String apiKey) {
		Query query = em.createQuery("select g from Goal g where g.belongsTo.apiKey=:apiKey and g.id=:id", Goal.class);
		List list = QueryUtils.configureQuery(query, id, apiKey);
		if (list.isEmpty()) {
			return null;
		}
		return (Goal) list.get(0);
	}


	/**
	 * Gets all goals which are associated to a specific rule.
	 * 
	 * @param rule
	 *           The rule to which the goals are associated. 
	 * @param apiKey
	 *           The API key of the organisation to which the goal belongs to. 
	 * @return A {@link List} of all {@link Goal}s which are associated to the specific rule.
	 */
	public List<Goal> getGoalsByRule(GoalRule rule, String apiKey) {

		Query query = em.createQuery("select g from Goal g where g.rule.id =:ruleId and g.belongsTo.apiKey=:apiKey");
		query.setParameter("apiKey", apiKey);
		query.setParameter("ruleId", rule.getId());

		return query.getResultList();
	}
	


	/**
	 * Gets all goals which belong to the specific passed API key.
	 * 
	 * @param apiKey
	 *            The API key affiliated to one specific organisation, to which 
	 *            the goals belongs to.
	 * @return A {@link List} of all {@link Goal}s which are associated to the specific API key.
	 */
	public List<Goal> getGoals(String apiKey) {
		Query query = em.createQuery("select g from Goal g join g.belongsTo a where a.apiKey=:apiKey");
		query.setParameter("apiKey", apiKey);
		return query.getResultList();
	}
	
	/**
	 * Deletes a goal by its id and checks if it belongs to the passed organisation.
	 * 
	 * @param goal
	 *            The goal that should be deleted.
	 * @param apiKey
	 *           The API key of the organisation to which the goal belongs to. 
	 * @return The {@link Goal} that should be deleted.
	 */
	public Goal deleteGoal(Goal goal, String apiKey) {
		
		if(goal!= null){
			em.remove(goal);
		}
		return goal;
	}
} @Named
@Stateless
public class OrganisationDAO {

	@PersistenceContext(unitName = PersistenceUnit.PROJECT)
	private EntityManager em;

	/**
	 * Stores a new organisation in the data base.
	 * 
	 * @param organisation
	 *            The {@link Organisation} that should be stored in the data base.
	 */
	public void insertOrganisation(Organisation organisation) {
		em.persist(organisation);
	}

	/**
	 * Gets the organisation from the data base.
	 * 
	 * @param id
	 *           The id of the requsted organisaiton.
	 * @return The {@link Organisation} that is associated with the passed id.
	 */
	public Organisation getOrganisation(int id) {
		Query query = em.createQuery("select o from Organisation o where o.id=:id", Organisation.class);
		query.setParameter("id", id);
		List list = query.getResultList();
		if (list.isEmpty()) {
			return null;
		}
		return ((Organisation) list.get(0));
	}

	/**
	 * Gets all organisations which belong to an email address.
	 * 
	 * @param email
	 *            The email address of the requested organisaiton.
	 * @return The {@link List} of {@link Organisation}s that are associated with the passed email address.
	 */
	public List<Organisation> getAllOrganisations(String email) {
		Query query = em.createQuery("select entity from Organisation entity join entity.managers m where m.email=:email");
		query.setParameter("email", email);

		List list = query.getResultList();
		if (list.isEmpty()) {
			return null;
		}

		return list;
	}

	/**
	 * Gets all organisations which are associated with the specific API key. The result
	 * should only be one organisation.
	 * 
	 * @param apiKey
	 *           The API key to which the organisation belongs to.
	 * @return A {@link List} of {@link Organisation}s that are associated to the passed
	 * 			API key. 
	 */
	public Organisation getOrganisationByApiKey(String apiKey) {
		Query query = em.createQuery("select entity from Organisation entity where entity.apiKey=:apiKey");
		query.setParameter("apiKey", apiKey);

		List list = query.getResultList();

		if (list.isEmpty()) {
			return null;
		}

		return ((Organisation) list.get(0));
	}

	/**
	 * Checks whether the data base contains the passed API key.
	 * 
	 * @param apiKey
	 *           The API key that is tested. This is represented by a {@link CharSequence} 
	 *           or null.
	 * @return True if the API key exists in data base, if null false is returned.
	 */
	public boolean checkApiKey(CharSequence apiKey) {
		if (apiKey != null) {
			try {
				Query query = em.createQuery("select entity from Organisation entity where entity.apiKey=:apiKey");
				query.setParameter("apiKey", apiKey);
				return query.getSingleResult() != null;
			} catch (NoResultException e) {
				// don't care
			}
		}
		return false;
	}
} @Named
@Stateless
public class RewardDAO {
	@PersistenceContext(unitName = PersistenceUnit.PROJECT)
	private EntityManager em;

	/**
	 * Stores a new reward in the data base.
	 * 
	 * @param reward
	 * 			The reward which should be stored in the data base.
	 * @return The generated id of the reward. 
	 */
	public int insertReward(Reward reward) {
		em.persist(reward);
		em.flush();
		return reward.getId();
	}

	/**
	 * Gets the reward by its id.
	 * 
	 * @param id
	 * 			The id of the requested reward.
	 * @param apiKey
	 *           The API key of the organisation to which the reward belongs to. 
	 * @return The {@link Reward} which is associated with the passed id and API key. 
	 */
	public Reward getReward(int id, String apiKey) {
		Query query = em.createQuery("select r from Reward r where r.belongsTo.apiKey=:apiKey and r.id=:id", Reward.class);
		List list = QueryUtils.configureQuery(query, id, apiKey);
		if (list.isEmpty()) {
			return null;
		}
		return ((Reward) list.get(0));
	}


	/**
	 * Gets all rewards which are associated with the passed API key.
	 * 
	 * @param apiKey
	 * 			The API key of the organisation to which the rewards belong to. 
	 * @return A {@link List} of {@link Reward}s which are associated with the passed 
	 * 			API key.
	 */
	public List<Reward> getRewards(String apiKey) {
		Query query = em.createQuery("select r from Reward r join r.belongsTo a where a.apiKey=:apiKey");
		query.setParameter("apiKey", apiKey);
		return query.getResultList();
	}


	/**
	 * Gets all rewards with the passed ids which match also the passed API key.
	 * 
	 * @param ids
	 * 			A list of reward ids. 
	 * @param apiKey
	 * 			The API key of the organisation to which the rewards belong to. 
	 * @return A {@link List} of {@link Reward}s which are associated with the passed 
	 * 			API key.
	 */
	public List<Reward> getRewards(List<Integer> ids, String apiKey) {
		Query query = em.createQuery("select r from Reward r where r.belongsTo.apiKey=:apiKey and r.id in (:ids)", Reward.class);
		query.setParameter("apiKey", apiKey);
		query.setParameter("ids", ids);
		return query.getResultList();
	}
	
	/**
	 * Removes a reward from the data base.
	 * 
	 * @param id
	 * 		 The id of the reward which should be deleted.
	 * @param apiKey
	 *           The API key of the organisation to which the reward belongs to. 
	 * @return The {@link Reward} that is associated with the passed id and API key.
	 */
	public Reward deleteReward(int id, String apiKey) {
		Reward reward = getReward(id, apiKey);
		
		if(reward!=null){
			em.remove(reward);
		}
		return reward;
	}
} @Entity
public class Organisation implements Serializable {

	private static final long serialVersionUID = -6830220885028070098L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@NotNull
	@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	private Collection<Account> managers;

	private String name;

	@NotNull
	@Column(unique = true)
	private String apiKey;

	public Organisation(String name) {
		super();
		this.name = name;
		managers = new HashSet<Account>();
	}

	public Organisation() {
		super();
		managers = new HashSet<Account>();
	}

	/**
	 * Sets the id of the created organisation.
	 * 
	 * @param id 
	 *           The new id of the organisation
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * Gets the organisation's id.
	 * 
	 * @return organisation's id as int
	 */
	public int getId() {
		return id;
	}

	/**
	 * Gets all accounts of the organisation which are associated to this organisation. 
	 * Each account belongs to a manager.
	 * 
	 * @return Collection of all organisation's manager accounts
	 */
	public Collection<Account> getManagers() {
		return managers;
	}

	/**
	 * Sets the list of the organisation's accounts. Each account belongs to a
	 * manager.
	 * 
	 * @param managers
	 *             List of all organisation's accounts
	 */
	public void setManagers(Collection<Account> managers) {
		this.managers = managers;
	}

	/**
	 * Gets the organisation's name and returns it as a String.
	 * 
	 * @return name of the organisation as String.
	 */
	public String getName() {
		return name;
	}

	/**
	 * Sets the name of an organisation.
	 * 
	 * @param name
	 *            The name of the organisation.
	 * 
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * Gets the organisation's unique API key and returns it.
	 * 
	 * @return the apiKey as a String
	 */
	public String getApiKey() {
		return apiKey;
	}

	/**
	 * Sets the organisation's API key.
	 * 
	 * @param apiKey
	 *		 	 The API key which is unique and specific for one organisation.
	 */
	public void setApiKey(@NotNull String apiKey) {
		this.apiKey = apiKey;
	}

	/**
	 * Adds a new manager's account to the organisation's list of accounts.
	 * 
	 * @param account
	 *            which should be added to the list
	 */
	public void addManager(@NotNull Account account) {
		this.managers.add(account);
	}
} @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;
	}
} @Entity
@DiscriminatorValue("RewAchieve")
@JsonIgnoreProperties({ "belongsTo", "imageIcon" })
public class Achievement extends PermanentReward {


	private URL iconURL;
	
	@Lob
//	@Basic(fetch = FetchType.LAZY)
	@Column(columnDefinition = "BLOB")
	private byte[] imageIcon;


	/**
	 * Gets the achievement's icon as byte[].
	 * 
	 * @return byte[] of the achievement's icon
	 */
	public byte[] getImageIcon() {
		return imageIcon;
	}

	/**
	 * Sets the byte[] as an icon of an achievement.
	 * 
	 * @param iconImage
	 *            The icon that should be connected with the achievement.
	 */
	public void setImageIcon(byte[] iconImage) {
		this.imageIcon = iconImage;
	}


	/**
	 * Gets the URL of the achievement's icon, but only when it was created.
	 * 
	 * @return The URL of the icon.
	 */
	public URL getIconURL() {
		return iconURL;
	}

	/**
	 * Sets the URL value of the achievement's icon, when it was created.
	 * 
	 * @param icon 
	 *            The URL of the icon that should be set.
	 */
	public void setIconURL(URL icon) {
		this.iconURL = icon;
	}

	/**
	 * With this method the player awards an achievement if she/he hasn't awarded it, yet. 
	 * Therefore the achievement is added to her/his list of permanent rewards.
	 * 
	 * @param player
	 *            The player who should award the achievement. This parameter must
	 *            not be null.
	 * @param goalDao
	 *            The goal DAO is required to access created goals. 
	 * @param ruleDao
	 *            The rule DAO is required to access the created rules. 
	 */
	@Override
	public void addReward(Player player, GoalDAO goalDao, RuleDAO ruleDao) {
		if(!player.getRewards().contains(this)){
			player.addPermanentReward(this);
		}
	}

	/**
	 * With this method a group awards an achievement and adds it to the list with permanent
	 * rewards, but only if this achievement isn't already in the list of permanent rewards.
	 * 
	 * @param group
	 *            The group of players which should award the achievement. This 
	 *            parameter must not be null.
	 * @param goalDao
	 *            The goal DAO is required to access created goals. 
	 * @param ruleDao
	 *            The rule DAO is required to access the created rules. 
	 */
	@Override
	public void addReward(PlayerGroup group, GoalDAO goalDao, RuleDAO ruleDao) {
		if(!group.getRewards().contains(this)){
			group.addPermanentReward(this);
		}
	}

} @Entity
@DiscriminatorValue("RewBadge")
@JsonIgnoreProperties({ "belongsTo", "imageIcon" })
public class Badge extends PermanentReward {


	private URL iconURL;

	@Lob
	@Column(columnDefinition = "BLOB")
	private byte[] imageIcon;



	/**
	 * Gets the URL of the badge's icon, when it was created.
	 * 
	 * @return The URL of the associated icon.
	 */
	public URL getIconURL() {
		return iconURL;
	}

	/**
	 * Sets the URL value of the badge's icon, when it was created.
	 * 
	 * @param icon
	 *            The URL of the associated icon.
	 */
	public void setIconURL(URL icon) {
		this.iconURL = icon;
	}

	/**
	 * Gets the badge's icon as byte[].
	 * 
	 * @return Byte[] of the badge's icon that is stored in the database.
	 */
	public byte[] getImageIcon() {
		return imageIcon;
	}

	/**
	 * Sets the byte[] as an icon of a badge that is stored in the database.
	 * 
	 * @param icon
	 *            The icon that should be connected with the badge as byte[].
	 */
	public void setImageIcon(byte[] icon) {
		imageIcon = icon;
	}

	/**
	 * With this method the player awards an badge if she/he hasn't awarded it, yet. 
	 * Therefore the badge is added to her/his list of permanent rewards.
	 * 
	 * @param player
	 *            The player who should award the badge. This parameter must
	 *            not be null.
	 * @param goalDao
	 *            The goal DAO is required to access created goals. 
	 * @param ruleDao
	 *            The rule DAO is required to access the created rules. 
	 */
	@Override
	public void addReward(Player player, GoalDAO goalDao, RuleDAO ruleDao) {
		if(!player.getRewards().contains(this)){
			player.addPermanentReward(this);
		}
	}

	/**
	 * With this method a group awards an badge and adds it to the list with permanent
	 * rewards, but only if this badge isn't already in the list of permanent rewards.
	 * 
	 * @param group
	 *            The group of players which should award the badge. This 
	 *            parameter must not be null.
	 * @param goalDao
	 *            The goal DAO is required to access created goals. 
	 * @param ruleDao
	 *            The rule DAO is required to access the created rules. 
	 */
	@Override
	public void addReward(PlayerGroup group, GoalDAO goalDao, RuleDAO ruleDao) {
		if(!group.getRewards().contains(this)){
			group.addPermanentReward(this);
		}
	}
} @Entity
@DiscriminatorValue("RewCoins")
public class Coins extends VolatileReward {

	@NotNull
	private int amount;

	/**
	 * Gets the concrete amount of coins which can be earned as a reward.
	 * 
	 * @return The current amount as int.
	 */
	public int getAmount() {
		return amount;
	}

	/**
	 * Sets a specific amount of coins which can be earned as a reward.
	 * 
	 * @param amount
	 *            The amount of coins which can be earned by the reward.
	 */
	public void setAmount(int amount) {
		this.amount = amount;
	}

	/**
	 * With this method the player awards the amount of coins. Therefore the coins
	 * are added to her/his current amount of coins.
	 * 
	 * @param player
	 *            The player who should award the coins. This parameter must
	 *            not be null.
	 * @param goalDao
	 *            The goal DAO is required to access created goals. 
	 * @param ruleDao
	 *            The rule DAO is required to access the created rules. 
	 */
	@Override
	public void addReward(Player player, GoalDAO goalDao, RuleDAO ruleDao) {
		player.awardCoins(amount);
	}

	/**
	 * Awards a group the amount of coins and adds it to group's current amount.
	 * 
	 * @param group
	 *            The group of players which should award the coins. This parameter 
	 *            must not be null.
	 * @param goalDao
	 *            The goal DAO is required to access created goals. 
	 * @param ruleDao
	 *            The rule DAO is required to access the created rules. 
	 */
	@Override
	public void addReward(PlayerGroup group, GoalDAO goalDao, RuleDAO ruleDao) {
		group.awardCoins(amount);
	}
} @Entity
@DiscriminatorValue("RewPoints")
public class Points extends VolatileReward {

	private static final Logger LOGGER = LoggerFactory.getLogger(Points.class);

	@NotNull
	private int amount;

	/**
	 * Gets the concrete amount of points which a player can earn as a
	 * reward.
	 * 
	 * @return The concrete amount as int.
	 */
	public int getAmount() {
		return amount;
	}

	/**
	 * Sets a specific amount of points which a player can earn as a reward.
	 * 
	 * @param amount
	 *            The amount of points which a player can earn as int.
	 */
	public void setAmount(int amount) {
		this.amount = amount;
	}

	/**
	 * Awards the player the concrete amount of points and add it to the
	 * player's current points. After that it's checked if a PointsRule is
	 * fulfilled so that the player can also earn another reward.
	 * 
	 * @param player
	 *            The player who should award the points. This parameter must
	 *            not be null.
	 * @param goalDao
	 *            The goal DAO is required to access created goals. 
	 * @param ruleDao
	 *            The rule DAO is required to access the created rules. 
	 */
	@Override
	public void addReward(Player player, GoalDAO goalDao, RuleDAO ruleDao) {

		LocalDateTime finishedDate = LocalDateTime.now();
		List<FinishedGoal> fGoalsList = new ArrayList<>();
		List<Reward> recievedRewards = new ArrayList<>();
		List<Role> matchingRoles;

		LOGGER.debug("Add points to player: " + amount);

		player.awardPoints(amount);

		LOGGER.debug("Points recieved -> check all points rules");

		String apiKey = player.getBelongsTo().getApiKey();
		List<GetPointsRule> completedPointsRules = ruleDao.getAllPointsRules(apiKey).stream().map(r -> (GetPointsRule) r).filter(r -> r.checkRule(player))
				.collect(Collectors.toList());

		// for each completed rule
		for (GetPointsRule rule : completedPointsRules) {

			LOGGER.debug("PointsRule: " + rule.getName());

			// get goals which contain this rule
			for (Goal goal : goalDao.getGoalsByRule(rule, apiKey)) {

				if(!goal.isPlayerGroupGoal()){
					//Test, if player role match with one role of the goal 
					if (goal.getCanCompletedBy().size() > 0) {
						LOGGER.debug("Pointsgoal is restricted by roles");
						matchingRoles = goal.getCanCompletedBy().stream().filter(r -> {
							if (player.getBelongsToRoles().contains(r)) {
								LOGGER.debug("Player has required Role to Complete Pointgoal: " + r.getName());
								return true;
							} else {
								return false;
							}
						}).collect(Collectors.toList());
	
						if (matchingRoles.size() > 0) {
							LOGGER.debug("Roles match for PointGoal -> proceed");
						} else {
							LOGGER.debug("Roles don't match for Pointgoal -> Pointgoal can not be completed");
							continue;
						}
					} else {
						LOGGER.debug("Pointgoal is not restricted by roles");
					}
					
					List<FinishedGoal> oldFinishedGoals = player.getFinishedGoalsByGoal(goal);
					
					// check if goal is already finished (if not list ist empty)
					if(oldFinishedGoals.isEmpty()){
						// goal has not yet been finished
						LOGGER.debug("Points Goal: is NOT on finished Goals list");
						// check if points are reached
						if (rule.checkRule(player)) {
							// add goal to tempFinishedGoals list
							LOGGER.debug("Points Goal: Rule is completed! -> add to fGoalsList (temp)");
							FinishedGoal fGoal = new FinishedGoal();
							fGoal.setGoal(goal);
							fGoal.setFinishedDate(finishedDate);
							fGoalsList.add(fGoal);
							// for each reward -> addReward
							for (Reward reward : goal.getRewards()) {
								recievedRewards.add(reward);
							}
						}
						//TODO: Check, if PointsGoal is awarded again
					} else if(goal.isRepeatable()){
						// goal has been finished but it is repeatable
						// check if points are reached
						if (rule.checkRule(player)) {
							// add goal to tempFinishedGoals list
							LOGGER.debug("Again: Points Goal: Rule is completed! -> add to fGoalsList (temp)");
							FinishedGoal fGoal = new FinishedGoal();
							fGoal.setGoal(goal);
							fGoal.setFinishedDate(finishedDate);
							fGoalsList.add(fGoal);
							// for each reward -> addReward
							for (Reward reward : goal.getRewards()) {
								recievedRewards.add(reward);
							}
						}
					}
				}
			
			}
			
		}

		LOGGER.debug("add finishedGoals to player");
		// add Goals to finishedGaolsList
		if(fGoalsList.size() > 0){
			player.addFinishedGoal(fGoalsList);
		}

		LOGGER.debug("add Rewards to player");
		// add Rewards to rewardList
		for (Reward reward : recievedRewards) {
			reward.addReward(player, goalDao, ruleDao);
		}

	}

	/**
	 * Awards the group of players the concrete amount of points and add them to
	 * the group's current points. After that it is checked if a PointsRule is
	 * fulfilled so that another reward can also be earned.
	 * 
	 * @param group
	 *            The group of players which should award the points. This parameter 
	 *            must not be null.
	 * @param goalDao
	 *            The goal DAO is required to access created goals. 
	 * @param ruleDao
	 *            The rule DAO is required to access the created rules. 
	 */
	@Override
	public void addReward(PlayerGroup group, GoalDAO goalDao, RuleDAO ruleDao) {

		LocalDateTime finishedDate = LocalDateTime.now();
		List<FinishedGoal> fGoalsList = new ArrayList<>();
		List<Reward> recievedRewards = new ArrayList<>();
		List<Role> matchingRoles = new ArrayList<Role>();
		
		LOGGER.debug("Add points to group: " + amount);

		group.awardPoints(amount);

		LOGGER.debug("Group: Points recieved -> check all points rules");

		//  check for organisation and check for group goal
		String apiKey = group.getBelongsTo().getApiKey();
		List<GetPointsRule> completedPointsRules = ruleDao.getAllPointsRules(apiKey).stream().map(r -> (GetPointsRule) r).filter(r -> r.checkRule(group))
				.collect(Collectors.toList());

		// for each completed rule
		for (GetPointsRule rule : completedPointsRules) {

			LOGGER.debug("Group: PointsRule: " + rule.getName());

			// get goals which contain this rule
			for (Goal goal : goalDao.getGoalsByRule(rule, apiKey)) {
				
				if(goal.isPlayerGroupGoal()){
					//Test, if one player role of the group match with role of the goal 
					if (goal.getCanCompletedBy().size() > 0) {
						LOGGER.debug("Pointsgoal is restricted by roles");
						
						for(Player everyGroupPlayer : group.getPlayers()){
								matchingRoles.addAll(goal.getCanCompletedBy().stream().filter(r -> {
							
								if (everyGroupPlayer.getBelongsToRoles().contains(r)) {
									LOGGER.debug("Player has required Role to Complete Pointgoal: " + r.getName());
									return true;
								} else {
									return false;
								}
							}).collect(Collectors.toList()));
						}
							
						if (matchingRoles.size() > 0) {
							LOGGER.debug("Roles match for PointGoal -> proceed");
						} else {
							LOGGER.debug("Roles don't match for Pointgoal -> Pointgoal can not be completed");
							continue;
						}
					} else {
						LOGGER.debug("Pointgoal is not restricted by roles");
					}			
					
					List<FinishedGoal> oldFinishedGoals = group.getFinishedGoalsByGoal(goal);
	
					// check if goal is already finished (if not list is empty)
					if(oldFinishedGoals.isEmpty()){
						// goal has not yet been finished
						LOGGER.debug("Group: Points Goal: is NOT on finished Goals list");
						// check if points are reached
						if (rule.checkRule(group)) {
							// add goal to tempFinishedGoals list
							LOGGER.debug("Group: Points Goal: Rule is completed! -> add to fGoalsList (temp)");
							FinishedGoal fGoal = new FinishedGoal();
							fGoal.setGoal(goal);
							fGoal.setFinishedDate(finishedDate);
							fGoalsList.add(fGoal);
							// for each reward -> addReward
							for (Reward reward : goal.getRewards()) {
								recievedRewards.add(reward);
							}
						}
					}
				}
			}
		}

		LOGGER.debug("Group: add finishedGoals to group");
		// add Goals to finishedGaolsList
		group.getFinishedGoals().addAll(fGoalsList);

		LOGGER.debug("Group: add Rewards to group");
		// add Rewards to rewardList
		for (Reward reward : recievedRewards) {
//			reward.addReward(group, goalDao, ruleDao);		//Test, if points are correct
			if(reward instanceof Points){
				((Points) reward).addReward(group, goalDao, ruleDao);
			} else {
				reward.addReward(group, goalDao, ruleDao);
			}
		}

	}

	
} @Entity
@DiscriminatorValue("RewRLevel")
@JsonIgnoreProperties({ "belongsTo" })
public class ReceiveLevel extends VolatileReward {

	@NotNull
	private int levelIndex;
	private String levelLabel;

	/**
	 * Gets the index of the level.
	 * 
	 * @return the level's index as an int.
	 */
	public int getLevelIndex() {
		return levelIndex;
	}

	/**
	 * Sets the level's index which should be awarded.
	 * 
	 * @param levelIndex
	 *            The index of the level which is awarded as int.
	 */
	public void setLevelIndex(int levelIndex) {
		this.levelIndex = levelIndex;
	}

	/**
	 * Gets the level's label which should be awarded.
	 * 
	 * @return The value of the level's label as String. 
	 */
	public String getLevelLabel() {
		return levelLabel;
	}

	/**
	 * Sets the String label of a level.
	 * 
	 * @param levelLabel
	 *            Label of the level as String.
	 */
	public void setLevelLabel(String levelLabel) {
		this.levelLabel = levelLabel;
	}

	/**
	 * This method awards the player a specfic lavel.
	 * 
	 * @param player
	 *            The player who should award the level. This parameter must
	 *            not be null.
	 * @param goalDao
	 *            The goal DAO is required to access created goals. 
	 * @param ruleDao
	 *            The rule DAO is required to access the created rules. 
	 */
	@Override
	public void addReward(Player player, GoalDAO goalDao, RuleDAO ruleDao) {
		player.setLevelIndex(levelIndex);
		player.setLevelLabel(levelLabel);
	}

	/**
	 * Awards a group of player a specific level.
	 * 
	 * @param group
	 *            The group of players which should award the level. This parameter 
	 *            must not be null.
	 * @param goalDao
	 *            The goal DAO is required to access created goals. 
	 * @param ruleDao
	 *            The rule DAO is required to access the created rules. 
	 * 
	 */
	@Override
	public void addReward(PlayerGroup group, GoalDAO goalDao, RuleDAO ruleDao) {
		group.setLevelIndex(levelIndex);
		group.setLevelLabel(levelLabel);
	}

} @Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "REWARD_TYPE", discriminatorType = DiscriminatorType.STRING)
@JsonIgnoreProperties({ "belongsTo", "goals" })
public abstract class Reward {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@NotNull
	@ManyToOne
	private Organisation belongsTo;

	private String name;
	
	private String description;
	
	private int timeToLive;

	@ManyToMany(fetch = FetchType.EAGER, mappedBy = "rewards")
	@JsonManagedReference
	private List<Goal> goals;

	public abstract void addReward(Player player, GoalDAO goalDao, RuleDAO ruleDao);
	public abstract void addReward(PlayerGroup group, GoalDAO goalDao, RuleDAO ruleDao);

	
	/**
	 * Gets the id of the reward which was generated by the creation.
	 * 
	 * @return The reward's id as int.
	 */
	public int getId() {
		return id;
	}

	/**
	 * Sets the id of the reward.
	 * 
	 * @param id
	 *            The id of the reward.
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * Gets the organisation the reward belongs to.
	 * 
	 * @return The organisation of the reward as an object. The organisation must not be
	 * null.
	 */
	public Organisation getBelongsTo() {
		return belongsTo;
	}

	/**
	 * Sets the organisation to which this reward belongs to.
	 * 
	 * @param belongsTo
	 *            The reward's organisation. This parameter must not be null.
	 */
	public void setBelongsTo(Organisation belongsTo) {
		this.belongsTo = belongsTo;
	}

	/**
	 * Gets the information about how long the reward can exist.
	 * 
	 * @return The value for how long the reward exist.
	 */
	public int getTimeToLive() {
		return timeToLive;
	}

	/**
	 * Sets the information about how long the reward can exist.
	 * 
	 * @param timeToLive
	 * 			Time how long the reward can exist as int.
	 */			
	public void setTimeToLive(int timeToLive) {
		this.timeToLive = timeToLive;
	}

	/**
	 * This method tests if a reward belongs to a specific organisation. Therefore
	 * it is tested if the organisation's API key matchs the reward's API key of the 
	 * assigned organisation. 
	 * 
	 * @param organisation
	 * 			The organisation object a reward may belongs to.
	 * @return
	 *  		Boolean value if the API key of the group is the same 
	 * 			of the tested organisation (true) or not (false).
	 */
	public boolean belongsTo(Organisation organisation) {
		return getBelongsTo().getApiKey().equals(organisation.getApiKey());
	}

	/**
	 * Gets the description of an achievement. This could contains for example the 
	 * different tasks which have to be completed to get this achievement.
	 * 
	 * @return the achievement's description
	 */
	public String getDescription() {
		return description;
	}

	/**
	 * Sets the description of an achievement. This contains for example further 
	 * information about how the achievement can be earned, like all requirements to 
	 * get the achievement or the process to award the achievement.
	 * 
	 * @param description
	 *            of the achievement
	 */
	public void setDescription(String description) {
		this.description = description;
	}

	/**
	 * Gets the name of an achievement which can describe the success in a short
	 * way and can be displayed in the application.
	 * 
	 * @return The achievement's name as String.
	 */
	public String getName() {
		return name;
	}

	/**
	 * Sets the name of an achievement, which can describe the success in a short
	 * way and can be displayed in the application.
	 * 
	 * @param name
	 *            The name of the achievement as a String.
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * Gets the list of goals to which this reward is assigned.
	 * 
	 * @return All goals with this reward as List of Goals.
	 */
	public List<Goal> getGoals() {
		return goals;
	}
	
	/**
	 * Sets the list of goals to which this reward is assigned.
	 * 
	 * @param goals
	 * 			The goals to which this reward should be assigned.
	 */
	public void setGoals(List<Goal> goals) {
		this.goals = goals;
	}
} public class ImageUtils {

	private static final Logger LOGGER = LoggerFactory.getLogger(ImageUtils.class);
	
	/**
	 * The passed String represents an URL. With this URL a byte[] is created from the image file that was passed as a String that
	 * represents an URL. The format of the image has to be .jpg or .png. Otherwise 
	 * an exception is thrown with the hint, that the URL was not valid.
	 * 
	 * @param fileLocation
	 * 			The path an image can be located. This is an URL.
	 * @return byte[] of the image content.
	 */
	public static byte[] imageToByte(String fileLocation) {
		BufferedImage originalImage;
		byte[] byteImage = null;

		String format = fileLocation.substring(fileLocation.lastIndexOf(".") + 1);

		if (format.equals("png") || format.equals("jpg")) {
			try {
				URL fileImage = new URL(fileLocation);
				originalImage = ImageIO.read(fileImage);
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				ImageIO.write(originalImage, format, baos);
				byteImage = baos.toByteArray();
				 
			} catch (IOException e) {
				throw new ApiError(Response.Status.FORBIDDEN, "No valid url was transferred");
			}
		}else{
			throw new ApiError(Response.Status.FORBIDDEN, "The image format has to be .png or .jpg");
		}
		return byteImage;
	}
	
	/**
	 * The passed byte array is Base64-encoded to ensure that the data is transmitted 
	 * correctly as String.  
	 * 
	 * @param bytes
	 * 			The byte array that should be encoded.
	 * @return The Base64 encoded String of the byte array.
	 */
	public static String encodeByteArrayToBase64(byte[] bytes){
		String b64 = Base64.encodeBase64String(bytes);
		return b64;
	}
}
import info.interactivesystems.gamificationengine.api.exeption.ApiError;
import info.interactivesystems.gamificationengine.api.validation.ValidApiKey;
import info.interactivesystems.gamificationengine.api.validation.ValidPositiveDigit;
import info.interactivesystems.gamificationengine.dao.GoalDAO;
import info.interactivesystems.gamificationengine.dao.OrganisationDAO;
import info.interactivesystems.gamificationengine.dao.RewardDAO;
import info.interactivesystems.gamificationengine.entities.Organisation;
import info.interactivesystems.gamificationengine.entities.goal.Goal;
import info.interactivesystems.gamificationengine.entities.rewards.Achievement;
import info.interactivesystems.gamificationengine.entities.rewards.Badge;
import info.interactivesystems.gamificationengine.entities.rewards.Coins;
import info.interactivesystems.gamificationengine.entities.rewards.Points;
import info.interactivesystems.gamificationengine.entities.rewards.ReceiveLevel;
import info.interactivesystems.gamificationengine.entities.rewards.Reward;
import info.interactivesystems.gamificationengine.utils.ImageUtils;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
package info.interactivesystems.gamificationengine.api;






/**
 * A Reward will be awarded in dependent of the goal for a group or one person after 
 * a person fulfilled a task. A reward can be a permanent reward like a badge or achievement 
 * which can be obtained only once or a volatile reward such as coins, points or a 
 * particular level which can be earned several times and so can be changed by getting for 
 * example more coins or decrease the coins by giving a bid for an offer in the marketplace. 
 * Ancillary all possible types for creating a reward, all already created rewards for one 
 * particular organisation or with the associated id only one specific reward can be 
 * requested. 
 * For all rewards the name and description can be changed after they have been created. 
 * Dependent on the reward has an image or an amount of points respectively coins these 
 * attributes also can be changed. 
 */
@Path("/reward")
@Stateless
@Produces(MediaType.APPLICATION_JSON)
public class RewardApi {

	private static final Logger LOGGER = LoggerFactory.getLogger(RewardApi.class);

	@Inject
	OrganisationDAO organisationDao;
	@Inject
	RewardDAO rewardDao;
	@Inject 
	GoalDAO goalDao;

	/**
	 * Returns a list of all rewards associated with the passed API key and so all rewards 
	 * which belong to a specific organisation. If the API key is not valid an analogous 
	 * message is returned. 
	 * 
	 * @param apiKey
	 *           The valid query parameter API key affiliated to one specific organisation, 
	 *           to which this reward belongs to.
	 * @return Response as List of Rewards in JSON.
	 */
	@GET
	@Path("/*")
	@TypeHint(Reward[].class)
	public Response getRewards(@QueryParam("apiKey") @ValidApiKey String apiKey) {

		List<Reward> reward = rewardDao.getRewards(apiKey);
		return ResponseSurrogate.of(reward);
	}

	/**
	 * This method returns one specific player who is identified by the passed id and the 
	 * API key. If the API key is not valid an analogous message is returned. It is also 
	 * checked, if the id is a positive number otherwise a message for an invalid number 
	 * is returned.
	 * 
	 * @param id
	 *           Required integer which uniquely identify the {@link Reward}.
	 * @param apiKey
	 *           The valid query parameter API key affiliated to one specific organisation, 
	 *           to which this reward belongs to.
	 * @return Response of Reward in JSON.
	 */
	@GET
	@Path("/{id}")
	@TypeHint(Reward.class)
	public Response getReward(@PathParam("id") @NotNull @ValidPositiveDigit String id, 
			@QueryParam("apiKey") @ValidApiKey String apiKey) {

		int rewardId = ValidateUtils.requireGreaterThanZero(id);
		Reward reward = rewardDao.getReward(rewardId, apiKey);
		ValidateUtils.requireNotNull(rewardId, reward);

		return ResponseSurrogate.of(reward);
	}

	/**
	 * Creates a new reward and so the method generates the reward-id. The organisation's API
	 * key is mandatory otherwise a warning with the hint for a non valid API key is returned.
	 * It has to be defined which type of reward should be created, its name, description and
	 * respectively it is a permanent or a volatile reward an URL for the icon or the amount 
	 * of coins or points.
	 * 
	 * @param type
	 *          The required type of the reward. A list of available reward types
	 *            can be received by {@link RewardApi#getRewardTypes}. The value of 
	 *            field can be "Achievement", "Badge", "Coins", "Points" and "ReceiveLevel".
	 * @param name
	 *           A string that represents the name of the reward.
	 * @param amount
	 *           If the type is a volatile reward like points or coins this parameter is used
	 *           to represent their amount. 	 
	 * @param url
	 *           If the type is a permanent reward like a badge or achievement this parameter
	 *           represents the URL of the associated image. 
	 * @param description
	 *           Optionally the description of the reward as String.
	 * @param apiKey
	 *           The valid query parameter API key affiliated to one specific organisation, 
	 *           to which this reward belongs to.
	 * @return Response of Reward in JSON.
	 */
	@POST
	@Path("/")
	@TypeHint(Reward.class)
	public Response createNewReward(@QueryParam("type") @NotNull String type, @QueryParam("name") @NotNull String name,
			@QueryParam("amount") @ValidPositiveDigit String amount, @QueryParam("icon") String url, @QueryParam("description") String description,
			@QueryParam("apiKey") @ValidApiKey String apiKey) {
		
		LOGGER.debug("createNewReward called");

		LOGGER.debug("apiKey: " + apiKey);
		LOGGER.debug("type: " + type);
		LOGGER.debug("name: " + name);
		LOGGER.debug("amount: " + amount);
		LOGGER.debug("icon: " + url);
		LOGGER.debug("description: " + description);

		Organisation organisation = organisationDao.getOrganisationByApiKey(apiKey);

		Reward reward;

		switch (type) {
		case "Achievement":
			return createAchievement(name, description, url, apiKey);
		case "Badge":
			return createBadge(name, description, url, apiKey);
		case "Coins":
			return createCoinsReward(name, description, amount, apiKey);
		case "Points":