PlaceBean.java 8.5 KB
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package fi.insomnia.bortal.beans;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Resource;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fi.insomnia.bortal.exceptions.BortalCatchableException;
import fi.insomnia.bortal.facade.GroupMembershipFacade;
import fi.insomnia.bortal.facade.PlaceFacade;
import fi.insomnia.bortal.facade.PlaceGroupFacade;
import fi.insomnia.bortal.model.EventMap;
import fi.insomnia.bortal.model.EventPk;
import fi.insomnia.bortal.model.GroupMembership;
import fi.insomnia.bortal.model.LanEvent;
import fi.insomnia.bortal.model.Place;
import fi.insomnia.bortal.model.PlaceGroup;
import fi.insomnia.bortal.model.Product;
import fi.insomnia.bortal.model.User;

/**
 * 
 * @author tuukka
 */
@Stateless
@DeclareRoles({ "MAP/READ", "MAP/WRITE", "MAP/EXECUTE", "SHOP/EXECUTE" })
public class PlaceBean implements PlaceBeanLocal {
	private static final String PLACE_RESERVE_TIMEOUTER = "Map reserve timeouter";
	private static final Logger logger = LoggerFactory.getLogger(PlaceBean.class);
	@EJB
	private GroupMembershipFacade gmemfacade;
	@Resource
	private TimerService ts;

	@EJB
	private PlaceFacade placeFacade;

	@EJB
	private PlaceGroupFacade pgfacade;
	@EJB
	private UserBeanLocal userbean;

	@EJB
	private ProductBeanLocal productBean;

	@EJB
	private EventBeanLocal eventBean;

	@EJB
	private LoggingBeanLocal secubean;
	@EJB
	private PermissionBeanLocal permbean;

	@Override
	@RolesAllowed("MAP/WRITE")
	public Place mergeChanges(Place place) {
		return placeFacade.merge(place);
	}

	@Override
	public BigDecimal totalReservationPrice(EventMap e, Place newPlace) {

		Set<Place> places = new HashSet<Place>();
		places.addAll(placeFacade.findUsersReservations(e, permbean.getCurrentUser()));

		if (newPlace != null) {
			places.add(newPlace);
		}

		Map<Product, Integer> mockmap = getPlaceProductcount(places);

		BigDecimal total = BigDecimal.ZERO;

		for (Entry<Product, Integer> entry : mockmap.entrySet()) {
			logger.debug("Adding to price {} of {}", entry.getValue(), entry.getKey().getName());
			if (entry.getKey() != null) {
				total = total.add(productBean.calculateTotal(entry.getKey(), new BigDecimal(entry.getValue())));
			}
		}
		return total;
	}

	private static Map<Product, Integer> getPlaceProductcount(Collection<Place> places) {
		HashMap<Product, Integer> mockmap = new HashMap<Product, Integer>();

		for (Place p : places) {
			if (p != null) {
				Product prod = p.getProduct();
				Integer val = mockmap.get(prod);
				if (val == null) {
					val = 0;
				}
				mockmap.put(prod, ++val);
			}
		}

		return mockmap;

	}

	// TODO: Kantakysely tähän!
	@Override
	public Place findPlace(EventMap e, int x, int y) {
		for (Place place : e.getPlaces()) {
			if (place.isCoordinateInPlace(x, y)) {
				return place;
			}
		}
		return null;

	}

	@Override
	@RolesAllowed("MAP/EXECUTE")
	public boolean reservePlace(Place p, User user) {
		boolean ret = placeFacade.reservePlace(p, user);

		boolean foundTimeout = false;
		for (Timer t : ts.getTimers()) {
			if (t.getInfo().equals(PLACE_RESERVE_TIMEOUTER)) {
				foundTimeout = true;
			}
		}
		if (!foundTimeout) {
			logger.info("Place timeout calculator not started. Starting new.");
			ts.createTimer(new Date(), 1000 * 60, PLACE_RESERVE_TIMEOUTER);
		}
		return ret;
	}

	@Timeout
	public void checkTimedOutPlaces(Timer timer) {
		// logger.debug("Checking Timed out places at {}", new Date());
		placeFacade.timeoutPlaces();
	}

	@Override
	public void releaseUsersPlaces() {
		logger.debug("timeouting places");
		placeFacade.releasePlaces(permbean.getCurrentUser());
	}

	@Override
	public boolean releasePlace(Place place, User user) {
		return placeFacade.releasePlace(user, place);

	}

	@Override
	@RolesAllowed("MAP/EXECUTE")
	public boolean buySelectedPlaces(EventMap e) throws BortalCatchableException {
		LanEvent event = eventBean.getCurrentEvent();
		User user = permbean.getCurrentUser();

		List<Place> places = placeFacade.findUsersReservations(e, user);
		if (places.size() <= 0) {
			return false;
		}
		PlaceGroup pg = new PlaceGroup(event, Calendar.getInstance(), Calendar.getInstance(), true);
		pg.setCreator(user);
		pgfacade.create(pg);

		// PlaceGroup pg = pgbean.createPlaceGroup(user);
		BigDecimal totalprice = totalReservationPrice(e, null);
		BigDecimal balance = permbean.getCurrentUser().getAccountBalance();
		if (balance.compareTo(totalprice) < 0) {
			logger.debug("User {} Could not buy things because account balance is too low!", user);
			return false;
		}

		for (Place p : places) {
			if (!p.buy(pg)) {
				throw new BortalCatchableException("Error while buying places");
			}
			placeFacade.merge(p);
			GroupMembership membership = new GroupMembership(event, pg, p, gmemfacade.createInviteToken(event));
			pg.getMembers().add(membership);
		}

		for (Entry<Product, Integer> line : getPlaceProductcount(places).entrySet()) {
			productBean.createAccountEvent(line.getKey(), new BigDecimal(line.getValue()), user);
		}
		return true;
	}

	@Override
	public void lockPlaceProduct(User user, Product prod, BigDecimal quantity) {

		BigDecimal loop = BigDecimal.ZERO;
		LanEvent event = eventBean.getCurrentEvent();
		PlaceGroup pg = new PlaceGroup(event, Calendar.getInstance(), Calendar.getInstance(), true);
		pg.setCreator(user);

		for (Place p : prod.getPlaces()) {

			if (!p.isTaken()) {

				p.buy(pg);
				GroupMembership currgm = new GroupMembership(event, pg, p, gmemfacade.createInviteToken(event));
				placeFacade.merge(p);
				currgm.setPlaceGroup(pg);
				pg.getMembers().add(currgm);

				loop = loop.add(BigDecimal.ONE);
				if (quantity.equals(BigDecimal.ONE)) {
					boolean gmassoc = false;
					for (GroupMembership gm : user.getGroupMemberships()) {
						if (gm.getId().getEventId().equals(event.getId())) {
							gmassoc = true;
							break;
						}

					}
					if (!gmassoc) {
						logger.debug("Group membership not found. Associating user {} to place {}", user.getNick(), currgm.getPlaceReservation().getName());
						user.getGroupMemberships().add(currgm);
						currgm.setUser(user);
					}
				}
				if (loop.compareTo(quantity) >= 0) {
					break;
				}
			}
		}
		user.getPlaceGroups().add(pg);

	}

	@Override
	@RolesAllowed("MAP/WRITE")
	public int setBuyable(EventMap map, String like, boolean b) {
		return placeFacade.setBuyable(map, like, b);

	}

	@Override
	@RolesAllowed("MAP/READ")
	public Place find(EventPk id) {
		return placeFacade.find(id);
	}

	@Override
	public void checkMemberships() {
		List<Place> all = placeFacade.findAll(eventBean.getCurrentEvent());
		for (Place p : all) {
			if (p.getGroup() != null && p.getPlaceReserver() == null) {
				LanEvent event = eventBean.getCurrentEvent();
				String token = gmemfacade.createInviteToken(event);

				GroupMembership gm = new GroupMembership(event, p.getGroup(), p, token);
				p.getGroup().getMembers().add(gm);
				p.setPlaceReserver(gm);

			}

		}

	}

	@Override
	@RolesAllowed("SHOP/EXECUTE")
	public Place lockPlaces(User user, Place place) throws PermissionDeniedException {
		if (place.isTaken()) {
			logger.warn("Place {} is already taken", place);
			throw new PermissionDeniedException(secubean, permbean.getCurrentUser(), "Place already taken!");
		}

		LanEvent ev = eventBean.getCurrentEvent();
		PlaceGroup pg = new PlaceGroup(ev, Calendar.getInstance(), Calendar.getInstance(), true);
		pg.setCreator(user);

		user.getPlaceGroups().add(pg);

		place.reserve(user);
		place.buy(pg);

		GroupMembership newgm = new GroupMembership(ev, pg, place, gmemfacade.createInviteToken(ev));

		pg.getMembers().add(newgm);

		boolean foundGm = false;
		for (GroupMembership gm : user.getGroupMemberships()) {
			logger.debug("Checking users gm:s found: {}", gm);
			if (gm.getId().getEventId().equals(ev.getId())) {
				foundGm = true;
				break;
			}
		}
		logger.debug("Foundgm {}", foundGm);
		if (!foundGm) {
			logger.debug("Membership not found. associating");
			newgm.setUser(user);
			user.getGroupMemberships().add(newgm);

			userbean.mergeChanges(user);
		}
		pgfacade.create(pg);
		place = placeFacade.merge(place);

		return place;
	}
}