/**
   * @param customerUser The Customer User
   * @return A HAL representation of the result
   */
  @DELETE
  @Timed
  public Response deregisterUser(@RestrictedTo({Authority.ROLE_CUSTOMER}) User customerUser) {

    Preconditions.checkNotNull(customerUser);

    // Remove all identifying information from the User
    // but leave the entity available for audit purposes
    // We leave the secret key in case the user has been
    // accidentally deleted and the user wants to be
    // reinstated
    customerUser.setApiKey("");
    customerUser.setContactMethodMap(Maps.<ContactMethod, ContactMethodDetail>newHashMap());
    customerUser.setUsername("");
    customerUser.setPasswordDigest("");
    customerUser.setPasswordResetAt(DateUtils.nowUtc());
    customerUser.setLocked(true);
    customerUser.setDeleted(true);
    customerUser.setReasonForDelete("Customer deregistered");
    customerUser.setUserFieldMap(Maps.<UserField, UserFieldDetail>newHashMap());

    // Persist the User with cascade for the Customer
    User persistentUser = userDao.saveOrUpdate(customerUser);

    // Provide a minimal representation to the client
    // so that they can see their secret key as a last resort
    // manual recovery option
    ClientUserBridge bridge = new ClientUserBridge(uriInfo, Optional.of(customerUser));
    URI location = uriInfo.getAbsolutePathBuilder().path(persistentUser.getApiKey()).build();

    return created(bridge, persistentUser, location);
  }
/**
 * Business object to provide the following to {@link org.multibit.mbm.core.model.Item}:
 *
 * <ul>
 *   <li>Calculation of price based on purchase order
 * </ul>
 *
 * <p>A price can only be determined as a result of the application of rules against and original
 * value.
 *
 * @since 0.0.1
 */
public class PriceBuilder {

  private int quantity = 0;
  private DateTime start = DateUtils.nowUtc();
  private DateTime end = DateUtils.nowUtc();
  private BigMoney startingPrice = MoneyUtils.parse("GBP 0.0");
  private Optional<Customer> customer = Optional.absent();
  private Optional<Supplier> supplier = Optional.absent();

  private List<PricingRule> pricingRules = Lists.newArrayList();

  private boolean isBuilt = false;

  /** @return A new instance of the builder */
  public static PriceBuilder newInstance() {
    return new PriceBuilder();
  }

  public PriceBuilder() {}

  /** Handles the building process. No further configuration is possible after this. */
  public BigMoney build() {
    validateState();

    // Price is not a DTO
    BigMoney price = startingPrice;

    for (PricingRule pricingRule : pricingRules) {
      pricingRule.setCustomer(customer);
      pricingRule.setSupplier(supplier);
      pricingRule.setQuantity(quantity);
      // TODO Consider date ranges (use discriminator value e.g. R(A,B], R(o,o))
      // Test filtering rules
      if (pricingRule.skip()) {
        continue;
      }
      if (pricingRule.halt()) {
        break;
      }
      price = pricingRule.applyTo(price);
    }

    isBuilt = true;

    return price;
  }

  private void validateState() {
    if (isBuilt) {
      throw new IllegalStateException("The entity has been built");
    }
  }

  public PriceBuilder withPricingRule(PricingRule pricingRule) {
    pricingRules.add(pricingRule);
    return this;
  }

  /**
   * Add the Customer in case it affects the price (one permitted)
   *
   * @return The builder
   */
  public PriceBuilder withCustomer(Customer customer) {
    this.customer = Optional.fromNullable(customer);
    return this;
  }

  /**
   * Add the Supplier in case it affects the price (one permitted)
   *
   * @return The builder
   */
  public PriceBuilder withSupplier(Supplier supplier) {
    this.supplier = Optional.fromNullable(supplier);
    return this;
  }

  /**
   * @param startingPrice The starting price (default is GBP0.0)
   * @return The builder
   */
  public PriceBuilder withStartingPrice(BigMoney startingPrice) {
    this.startingPrice = startingPrice;
    return this;
  }
}