/* vim: set ts=2 et sw=2 cindent fo=qroca: */ package com.globant.katari.gadgetcontainer.domain; import org.apache.commons.lang.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.LinkedList; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.ManyToOne; import javax.persistence.DiscriminatorValue; import com.globant.katari.hibernate.coreuser.domain.CoreUser; import com.globant.katari.shindig.domain.Application; /** A gadget group that can be customized by the user. * * Customizable gadget groups always have an owner and the ownar can reorganize * the gadgets, add and remove gadgets. */ @Entity @DiscriminatorValue("customizable") public class CustomizableGadgetGroup extends GadgetGroup { /** The class logger. */ private static Logger log = LoggerFactory.getLogger( CustomizableGadgetGroup.class); /** The owner of this gadget group. * * If null, this is a static group. */ @ManyToOne(optional = true, fetch = FetchType.EAGER) private CoreUser owner = null; /** Hibernate constructor. */ CustomizableGadgetGroup() { } /** Constructor. * * @param user the user that owns the gadget group. It cannot be null. * * @param groupName name of the group. It cannot be null * * @param viewName name of the view. This gadget will only contain gadgets * that support this view or the default view. It cannot be null * * @param columns the number of columns in the group. It must be 1 or * greater. */ public CustomizableGadgetGroup(final CoreUser user, final String groupName, final String viewName, final int columns) { super(groupName, viewName, columns); Validate.notNull(user, "The user name cannot be null."); owner = user; } /** Returns the owner of a customizable group. * * @return the group owner, never return null. */ public CoreUser getOwner() { return owner; } /** Tells if this gadget group is customizable. * * A customizable gadget group allows the user to move, add and remove * gadgets. * * @return this implementation always returns true. */ @Override public boolean isCustomizable() { return true; } /** Adds a gadget to the group. * * The gadget's column must be between 0 and the number of columns in this * group. The gadget must support this column's view. * * @param instance the gadget to add to this group. It cannot be null. */ public void add(final GadgetInstance instance) { Validate.notNull(instance, "The gadget instance cannot be null."); Validate.isTrue(instance.getColumn() < getNumberOfColumns(), "The gadget group " + getName() + " has " + getNumberOfColumns() + " columns, and you are trying to add gadget " + instance.getApplication().getUrl() + " at column " + instance.getColumn()); Validate.isTrue(instance.getApplication().isViewSupported(getView()), "The gadget " + instance.getApplication().getUrl() + " does not support group " + getName() + "'s view."); for (GadgetInstance gadget: getGadgets()) { if (gadget.getColumn() == instance.getColumn() && gadget.getOrder() >= instance.getOrder()) { gadget.move(gadget.getColumn(), gadget.getOrder() + 1); } } super.add(instance); } /** Removes the gadget instance with the provided id from the group. * * @param instanceId the id of the gadget instance to remove. * * @return true if the gadget was removed, false if it was not in the group. */ public boolean remove(final long instanceId) { for (GadgetInstance gadget: getGadgets()) { if (gadget.getId() == instanceId) { super.remove(gadget); return true; } } return false; } /** Moves a gadget in the group to a new column and position in the column. * * The gadget instance id must exist in the gadget group, and the column must * be lower than numberOfColumns. * * @param gadgetInstanceId The id of the gadget instance to move. * * @param column The column to move the gadget to, starting from 0. * * @param order The position of the gadget in the column, starting from 0. */ public void move(final long gadgetInstanceId, final int column, final int order) { Validate.isTrue(isCustomizable(), "The group is not customizable"); Validate.isTrue(column < getNumberOfColumns(), "You cannot move past the last column"); Validate.isTrue(column >= 0, "Negative columns are not accepted."); Validate.isTrue(column >= 0, "Negative orders are not accepted."); log.trace("Entering move({}, ...)", gadgetInstanceId); // The list of gadgets in the target column. List<GadgetInstance> gadgetsInColumn = new LinkedList<GadgetInstance>(); // Finds all the gagdets in the same column. Also find the gadget to move. // The gadget to move is not in gadgetsInColumn. GadgetInstance gadgetToMove = null; for (GadgetInstance gadget : getGadgets()) { if (gadget.getId() == gadgetInstanceId) { gadgetToMove = gadget; } else if (gadget.getColumn() == column) { log.debug("Adding gadget id = {} for column {}.", gadget.getId(), column); gadgetsInColumn.add(gadget); } } Validate.notNull(gadgetToMove, "The gadget to move was not found."); // Sorts them by order. Collections.sort(gadgetsInColumn, new Comparator<GadgetInstance>() { public int compare(final GadgetInstance g1, final GadgetInstance g2) { return g1.getOrder() - g2.getOrder(); } }); // Inserts the new gadget. if (order < gadgetsInColumn.size()) { log.debug("Inserting gadget id = {} in position {}.", gadgetToMove.getId(), order); gadgetsInColumn.add(order, gadgetToMove); } else { log.debug("Adding gadget id = {} at the end of the column.", gadgetToMove.getId()); gadgetsInColumn.add(gadgetToMove); } // Renumbers the gadgets. int newOrder = 0; for (GadgetInstance gadget : gadgetsInColumn) { log.debug("Moving gadget with id {} to {}.", gadget.getId(), newOrder); gadget.move(column, newOrder); ++newOrder; } log.trace("Leaving move"); } /** Finds if there is a gadget in the group for the application. * * @param application The application to look for in the gadget group. It * cannot be null. * * @return true if the application was found in the group, false otherwise. */ public boolean contains(final Application application) { Validate.notNull(application, "The application cannot be null."); for (GadgetInstance instance: getGadgets()) { if (application.getUrl().equals(instance.getApplication().getUrl())) { // The application is already in the group. return true; } } return false; } }