package info.interactivesystems.gamificationengine.entities.marketPlace; import info.interactivesystems.gamificationengine.dao.MarketPlaceDAO; import info.interactivesystems.gamificationengine.dao.PlayerDAO; import info.interactivesystems.gamificationengine.entities.Organisation; import info.interactivesystems.gamificationengine.entities.Player; import info.interactivesystems.gamificationengine.entities.Role; import info.interactivesystems.gamificationengine.entities.task.Task; import info.interactivesystems.gamificationengine.utils.OfferMarketPlace; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; /** * Players can create an offer with a task for the marketplace so another player can * bid to do this task and get its rewards. Via Bids an initial bid by the creator can be * raised. To be able to create offers, a marketplace for the organisation is needed. * If none exists yet, it first has to be created. */ @Entity @JsonIgnoreProperties({ "belongsTo" }) public class MarketPlace { private static final Logger LOGGER = LoggerFactory.getLogger(MarketPlace.class); @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @ManyToOne private Organisation belongsTo; /** * All offers in one marketplace, which a player can bid for */ @ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER) private List<Offer> offers; public MarketPlace() { offers = new ArrayList<>(); } /** * Gets the id of a marketplace. * * @return The markeptlace's id as int. */ public int getId() { return id; } /** * Sets the id of a marketplace. * * @param id * The new id of the marketplace. */ public void setId(int id) { this.id = id; } /** * Gets the organisation a marketplace belongs to. * * @return The organisation of the marketplace as an object. */ public Organisation getBelongsTo() { return belongsTo; } /** * Sets the organisation a marketplace belongs to. * * @param belongsTo * The marketplace's organisation. */ public void setBelongsTo(Organisation belongsTo) { this.belongsTo = belongsTo; } /** * Gets all offers of one marketplace, which a player can bid for. * * @return A list of all existing offers a player can bid for. */ public List<Offer> getOffers() { return offers; } /** * Sets the list of offers of a marketplace. * * @param offers * The new list of offers of a marketplace. */ public void setOffers(List<Offer> offers) { this.offers = offers; } /** * Adds one new offer to the list of offers. * * @param offer * The offer that is added to the list of offers. */ public void addOffer(Offer offer) { if(!offers.contains(offer)){ this.offers.add(offer); } } /** * Removes an offer from a marketplace's list of offers. * * @param offer * The offer that should be removed. */ public void removeOffer(Offer offer) { if(offers.contains(offer)){ this.offers.remove(offer); } } /** * This method filters all existing offers in a marketplace by a passed role of a player. * So a list is returned which contains only offers which at least match one role of * the player. * * @param roles * The player whose roles are checked if they match an offer. * The list of Roles which are the hint for filtering. * @return The list of all offers which are in the marketplace and a player is allowed * to complete. */ public List<Offer> filterOfferByRole(List<Role> roles) { List<Offer> matchingOffers = new ArrayList<>(); for (Offer offer : this.getOffers()) { for (Role r : roles) { if (offer.getTask().getAllowedFor().contains(r)) { matchingOffers.add(offer); break; } } } return matchingOffers; } /** * This method filters all matching offers to the player's roles and filters it by the * date so the latest offers are presented. * A list with a specific count of offers are returned that are the latest and match at least one role of * the player. * * @param matchingOffers * All offers which match at least one role of the player. * @param count * The number of offers that are returned with the list. * @return The list with the number of the second parameter and matching offers to the * player's roles is returned. */ public List<Offer> filterOfferByDate(List<Offer> matchingOffers, int count) { Comparator<Offer> byOfferDate = (o1, o2) -> o1.getOfferDate().compareTo(o2.getOfferDate()); return filterOfferByParam(matchingOffers, count, byOfferDate, true); } /** * This method filters all matching offers to the player's roles and filters it by the * prize that can be earned. * A list with x offers are returned that have the highest prize and match at least one * role of the player. * * @param matchingOffers * All offers which match at least one role of the player. * @param count * The number of offers that are returned with the list. * @return The list with the number of the second parameter and matching offers to the * player's roles is returned. */ public List<Offer> filterOffersByPrize(List<Offer> matchingOffers, int count) { Comparator<Offer> byOfferPrize = (o1, o2) -> Integer.compare(o1.getPrize(), o2.getPrize()); return filterOfferByParam(matchingOffers, count, byOfferPrize, true); } /** * This method filters the offers thate are matching at least one role of the player * by the passed conditions. * * @param matchingOffers * All offers which match at least one role of the player. * @param count * The number of offers that are returned with the list. * @param comp * The comparator which defines the filter method. This can be for example * compare the offers' prize or their dates of creation. * @param reverse * Boolean i the order of the result list should be reversed (true) or not * (false). * @return The list of filtered offers. */ private List<Offer> filterOfferByParam(List<Offer> matchingOffers, int count, Comparator<Offer> comp, boolean reverse) { int toIndex; if (reverse) { Collections.sort(matchingOffers, Collections.reverseOrder(comp)); } else { Collections.sort(matchingOffers, comp); } if (count < matchingOffers.size() && count >= 0) { toIndex = count; } else { toIndex = matchingOffers.size(); } return matchingOffers.stream().limit(toIndex).collect(Collectors.toList()); } /** * Every prize of every offer in the passed list is added and obtained to the * player who has finished the task. Then every offer in the passed list is * removed from the appropriated marketplace and deleted from the database. * * @param taskOffers * A list of offers that contain the same task. Additionally the list * contains for each offer the id of the marketplace is * @param player * The player that has fulfilled the task. * @param marketPlDao * DAO to get the marketplace of the database. * @param playerDao * DAO to update the player. * @param apiKey * The valid query parameter API key affiliated to one specific organisation, * to which this task belongs to. */ public static void completeAssociatedOffers(List<OfferMarketPlace> taskOffers, Player player, MarketPlaceDAO marketPlDao, PlayerDAO playerDao, String apiKey){ int prizeReward = 0; HashSet<MarketPlace> marketPls = new HashSet<>(); List<Offer> offersToComplete = new ArrayList<>(); List<Offer> offersToDelete = new ArrayList<>(); for (OfferMarketPlace offerMarketPlace : taskOffers) { offersToComplete.add(offerMarketPlace.getOffer()); marketPls.add(marketPlDao.getMarketplace(offerMarketPlace.getMarketPlaceId(), apiKey)); } for (MarketPlace places : marketPls) { List<Offer> removeOffers = new ArrayList<>(); //Bids are deleted by cascading. for (Offer offer2 : offersToComplete) { if(places.offers.contains(offer2)){ prizeReward += offer2.getPrize(); removeOffers.add(offer2); LOGGER.debug("Offer removed and prize = " + prizeReward); } } offersToComplete.removeAll(removeOffers); offersToDelete.addAll(removeOffers); places.offers.removeAll(removeOffers); marketPlDao.insertMarketPlace(places); LOGGER.debug("MarketPlace updated " + places.getId()); } marketPlDao.deleteOffers(offersToDelete, apiKey); player.setCoins(player.getCoins() + prizeReward); LOGGER.debug("reward awarded: " + prizeReward + " coins" ); playerDao.insert(player); } /** * This methods creates an ArrayList of all offers that contains a specific * task. Additionally to every offer the id of the marketplace is added where * the offer can be find. * * @param marketPlDao * The DAO to get the marketplace of the database. * @param task * All offers of the marketplaces are returned in the list that * contains this task. * @param apiKey * The valid query parameter API key affiliated to one specific organisation, * to which the offer belongs to. * @return The List of all offers and their marketplace ids which contain the passed task. */ public static ArrayList<OfferMarketPlace> getAllOfferMarketPlaces(MarketPlaceDAO marketPlDao, Task task, String apiKey){ List<Offer> offers = marketPlDao.getOffersByTask(task, apiKey); ArrayList<OfferMarketPlace> offList = new ArrayList<>(); List<MarketPlace> markets = marketPlDao.getAllMarketPlaces(apiKey); for (MarketPlace marketPlace : markets) { List<Offer> marketOffers = marketPlace.getOffers(); for (Offer offer : offers) { if(marketOffers.contains(offer)){ OfferMarketPlace offMarP = new OfferMarketPlace(offer, marketPlace.getId()); offList.add(offMarP); } } } return offList; } }