@SuppressWarnings("unchecked")
  @ResponseBody
  @RequestMapping(value = "/order/checkSpecialOffer.ajax", method = RequestMethod.POST)
  public ResponseEntity<byte[]> checkSpecialOfferAvailability(
      HttpServletRequest request, @RequestParam(value = "body") String body) throws Exception {

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Checking if special offer is applicable for order");
    }

    Map<String, Object> model = new HashMap<String, Object>();

    try {

      // Extract request parameters
      Map<String, Object> params = (Map<String, Object>) jsonUtils.deserialize(body);
      String restaurantId = (String) params.get("restaurantId");
      String orderId = (String) params.get("orderId");
      String specialOfferId = (String) params.get("specialOfferId");

      // Get the restaurant object
      Restaurant restaurant = restaurantRepository.findByRestaurantId(restaurantId);
      SpecialOffer specialOffer = restaurant.getSpecialOffer(specialOfferId);

      // Get the order object
      if (orderId != null) {
        Order order = orderRepository.findByOrderId(orderId);
        model.put("success", true);
        model.put("applicable", specialOffer.isApplicableTo(order));
      } else {
        model.put("success", true);
        model.put("applicable", specialOffer.isAvailableAt(new DateTime()));
      }
    } catch (Exception ex) {
      LOGGER.error("", ex);
      model.put("success", false);
      model.put("message", ex.getMessage());
    }
    return buildOrderResponse(model);
  }
  @SuppressWarnings("unchecked")
  @ResponseBody
  @RequestMapping(value = "/order/addSpecialOffer.ajax", method = RequestMethod.POST)
  public ResponseEntity<byte[]> addSpecialOfferToOrder(
      HttpServletRequest request, @RequestParam(value = "body") String body) throws Exception {

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Adding special offer to order: " + body);
    }

    Map<String, Object> model = new HashMap<String, Object>();

    try {

      // Extract request parameters
      Map<String, Object> params = (Map<String, Object>) jsonUtils.deserialize(body);
      String restaurantId = (String) params.get("restaurantId");
      String specialOfferId = (String) params.get("specialOfferId");
      List<String> itemChoices = (List<String>) params.get("itemChoices");
      List<String> itemChoiceCosts = (List<String>) params.get("itemChoiceCosts");
      Integer quantity = Integer.valueOf(params.get("quantity").toString());

      // Get the restaurant object
      Restaurant restaurant = restaurantRepository.findByRestaurantId(restaurantId);
      SpecialOffer specialOffer = restaurant.getSpecialOffer(specialOfferId);

      // Get the order out of the session
      HttpSession session = request.getSession(true);
      String orderId = (String) session.getAttribute("orderid");
      Order order;
      if (orderId == null) {
        order = buildAndRegister(session, restaurantId);
      } else {
        order = orderRepository.findByOrderId(orderId);
        if (order == null) {
          order = buildAndRegister(session, restaurantId);
        }
      }

      // Check if the special offer is applicable to this order
      if (!specialOffer.isApplicableTo(order)) {
        model.put("success", true);
        model.put("applicable", false);
      } else {
        // Wipe existing order if a new restaurant is selected
        if (!restaurantId.equals(order.getRestaurantId())) {
          order.setRestaurantId(restaurantId);
          order.setRestaurant(restaurant);
          order.getOrderItems().clear();
          order.getOrderDiscounts().clear();
        }

        // Build new order item
        OrderItem orderItem = new OrderItem();
        orderItem.setMenuItemNumber(specialOffer.getNumber());
        orderItem.setMenuItemId(specialOfferId);
        orderItem.setMenuItemTitle(specialOffer.getTitle());
        orderItem.setAdditionalItems(itemChoices);
        orderItem.setQuantity(quantity);
        double additionalCost = 0d;
        for (String itemChoiceCost : itemChoiceCosts) {
          additionalCost += Double.valueOf(itemChoiceCost);
        }
        orderItem.setCost(specialOffer.getCost() + additionalCost);

        // Add new order item to order and update
        order.addOrderItem(orderItem);
        order = orderRepository.saveOrder(order);

        // Update can checkout status of order
        session.setAttribute("cancheckout", order.getCanCheckout());

        // Update order restaurant id session attribute if any items present
        if (order.getOrderItems().size() > 0) {
          session.setAttribute("orderrestaurantid", order.getRestaurantId());
          session.setAttribute("orderrestauranturl", order.getRestaurant().getUrl());
        } else {
          session.removeAttribute("orderrestaurantId");
          session.removeAttribute("orderrestauranturl");
        }

        // Return success
        model.put("success", true);
        model.put("applicable", true);
        model.put("order", order);
      }
    } catch (Exception ex) {
      LOGGER.error("", ex);
      model.put("success", false);
      model.put("message", ex.getMessage());
    }
    return buildOrderResponse(model);
  }