/** Restores the specialized (auto-save) shopping list back into the shopping cart */
  public static String restoreAutoSaveList(
      HttpServletRequest request, HttpServletResponse response) {
    Delegator delegator = (Delegator) request.getAttribute("delegator");
    LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
    GenericValue productStore = ProductStoreWorker.getProductStore(request);

    if (!ProductStoreWorker.autoSaveCart(productStore)) {
      // if auto-save is disabled just return here
      return "success";
    }

    HttpSession session = request.getSession();
    ShoppingCart cart = ShoppingCartEvents.getCartObject(request);

    // safety check for missing required parameter.
    if (cart.getWebSiteId() == null) {
      cart.setWebSiteId(WebSiteWorker.getWebSiteId(request));
    }

    // locate the user's identity
    GenericValue userLogin = (GenericValue) session.getAttribute("userLogin");
    if (userLogin == null) {
      userLogin = (GenericValue) session.getAttribute("autoUserLogin");
    }

    // find the list ID
    String autoSaveListId = cart.getAutoSaveListId();
    if (autoSaveListId == null) {
      try {
        autoSaveListId =
            getAutoSaveListId(delegator, dispatcher, null, userLogin, cart.getProductStoreId());
      } catch (GeneralException e) {
        Debug.logError(e, module);
      }
      cart.setAutoSaveListId(autoSaveListId);
    } else if (userLogin != null) {
      String existingAutoSaveListId = null;
      try {
        existingAutoSaveListId =
            getAutoSaveListId(delegator, dispatcher, null, userLogin, cart.getProductStoreId());
      } catch (GeneralException e) {
        Debug.logError(e, module);
      }
      if (existingAutoSaveListId != null) {
        if (!existingAutoSaveListId.equals(autoSaveListId)) {
          // Replace with existing shopping list
          cart.setAutoSaveListId(existingAutoSaveListId);
          autoSaveListId = existingAutoSaveListId;
          cart.setLastListRestore(null);
        } else {
          // CASE: User first login and logout and then re-login again. This condition does not
          // require a restore at all
          // because at this point items in the cart and the items in the shopping list are same so
          // just return.
          return "success";
        }
      }
    }

    // check to see if we are okay to load this list
    java.sql.Timestamp lastLoad = cart.getLastListRestore();
    boolean okayToLoad = autoSaveListId == null ? false : (lastLoad == null ? true : false);
    if (!okayToLoad && lastLoad != null) {
      GenericValue shoppingList = null;
      try {
        shoppingList =
            EntityQuery.use(delegator)
                .from("ShoppingList")
                .where("shoppingListId", autoSaveListId)
                .queryOne();
      } catch (GenericEntityException e) {
        Debug.logError(e, module);
      }
      if (shoppingList != null) {
        java.sql.Timestamp lastModified = shoppingList.getTimestamp("lastAdminModified");
        if (lastModified != null) {
          if (lastModified.after(lastLoad)) {
            okayToLoad = true;
          }
          if (cart.size() == 0 && lastModified.after(cart.getCartCreatedTime())) {
            okayToLoad = true;
          }
        }
      }
    }

    // load (restore) the list of we have determined it is okay to load
    if (okayToLoad) {
      String prodCatalogId = CatalogWorker.getCurrentCatalogId(request);
      try {
        addListToCart(
            delegator,
            dispatcher,
            cart,
            prodCatalogId,
            autoSaveListId,
            false,
            false,
            userLogin != null ? true : false);
        cart.setLastListRestore(UtilDateTime.nowTimestamp());
      } catch (IllegalArgumentException e) {
        Debug.logError(e, module);
      }
    }

    return "success";
  }
  public static String addListToCart(
      Delegator delegator,
      LocalDispatcher dispatcher,
      ShoppingCart cart,
      String prodCatalogId,
      String shoppingListId,
      boolean includeChild,
      boolean setAsListItem,
      boolean append)
      throws java.lang.IllegalArgumentException {
    String errMsg = null;

    // no list; no add
    if (shoppingListId == null) {
      errMsg =
          UtilProperties.getMessage(
              resource_error, "shoppinglistevents.choose_shopping_list", cart.getLocale());
      throw new IllegalArgumentException(errMsg);
    }

    // get the shopping list
    GenericValue shoppingList = null;
    List<GenericValue> shoppingListItems = null;
    try {
      shoppingList =
          EntityQuery.use(delegator)
              .from("ShoppingList")
              .where("shoppingListId", shoppingListId)
              .queryOne();
      if (shoppingList == null) {
        errMsg =
            UtilProperties.getMessage(
                resource_error,
                "shoppinglistevents.error_getting_shopping_list_and_items",
                cart.getLocale());
        throw new IllegalArgumentException(errMsg);
      }

      shoppingListItems = shoppingList.getRelated("ShoppingListItem", null, null, false);
      if (shoppingListItems == null) {
        shoppingListItems = FastList.newInstance();
      }

      // include all items of child lists if flagged to do so
      if (includeChild) {
        List<GenericValue> childShoppingLists =
            shoppingList.getRelated("ChildShoppingList", null, null, false);
        for (GenericValue v : childShoppingLists) {
          List<GenericValue> items = v.getRelated("ShoppingListItem", null, null, false);
          shoppingListItems.addAll(items);
        }
      }

    } catch (GenericEntityException e) {
      Debug.logError(e, "Problems getting ShoppingList and ShoppingListItem records", module);
      errMsg =
          UtilProperties.getMessage(
              resource_error,
              "shoppinglistevents.error_getting_shopping_list_and_items",
              cart.getLocale());
      throw new IllegalArgumentException(errMsg);
    }

    // no items; not an error; just mention that nothing was added
    if (UtilValidate.isEmpty(shoppingListItems)) {
      errMsg =
          UtilProperties.getMessage(
              resource_error, "shoppinglistevents.no_items_added", cart.getLocale());
      return errMsg;
    }

    // check if we are to clear the cart first
    if (!append) {
      cart.clear();
      // Prevent the system from creating a new shopping list every time the cart is restored for
      // anonymous user.
      cart.setAutoSaveListId(shoppingListId);
    }

    // get the survey info for all the items
    Map<String, List<String>> shoppingListSurveyInfo = getItemSurveyInfos(shoppingListItems);

    // add the items
    StringBuilder eventMessage = new StringBuilder();
    for (GenericValue shoppingListItem : shoppingListItems) {
      String productId = shoppingListItem.getString("productId");
      BigDecimal quantity = shoppingListItem.getBigDecimal("quantity");
      Timestamp reservStart = shoppingListItem.getTimestamp("reservStart");
      BigDecimal reservLength = shoppingListItem.getBigDecimal("reservLength");
      BigDecimal reservPersons = shoppingListItem.getBigDecimal("reservPersons");
      //    String accommodationMapId = shoppingListItem.getString("accommodationMapId");
      //    String accommodationSpotId = shoppingListItem.getString("accommodationSpotId");
      String configId = shoppingListItem.getString("configId");
      try {
        String listId = shoppingListItem.getString("shoppingListId");
        String itemId = shoppingListItem.getString("shoppingListItemSeqId");

        Map<String, Object> attributes = FastMap.newInstance();
        // list items are noted in the shopping cart
        if (setAsListItem) {
          attributes.put("shoppingListId", listId);
          attributes.put("shoppingListItemSeqId", itemId);
        }

        // check if we have existing survey responses to append
        if (shoppingListSurveyInfo.containsKey(listId + "." + itemId)
            && UtilValidate.isNotEmpty(shoppingListSurveyInfo.get(listId + "." + itemId))) {
          attributes.put("surveyResponses", shoppingListSurveyInfo.get(listId + "." + itemId));
        }

        ProductConfigWrapper configWrapper = null;
        if (UtilValidate.isNotEmpty(configId)) {
          configWrapper =
              ProductConfigWorker.loadProductConfigWrapper(
                  delegator,
                  dispatcher,
                  configId,
                  productId,
                  cart.getProductStoreId(),
                  prodCatalogId,
                  cart.getWebSiteId(),
                  cart.getCurrency(),
                  cart.getLocale(),
                  cart.getAutoUserLogin());
        }
        // TODO: add code to check for survey response requirement

        // i cannot get the addOrDecrease function to accept a null reservStart field: i get a null
        // pointer exception a null constant works....
        if (reservStart == null) {
          cart.addOrIncreaseItem(
              productId,
              null,
              quantity,
              null,
              null,
              null,
              null,
              null,
              null,
              attributes,
              prodCatalogId,
              configWrapper,
              null,
              null,
              null,
              dispatcher);
        } else {
          cart.addOrIncreaseItem(
              productId,
              null,
              quantity,
              reservStart,
              reservLength,
              reservPersons,
              null,
              null,
              null,
              null,
              null,
              attributes,
              prodCatalogId,
              configWrapper,
              null,
              null,
              null,
              dispatcher);
        }
        Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productId", productId);
        errMsg =
            UtilProperties.getMessage(
                resource_error,
                "shoppinglistevents.added_product_to_cart",
                messageMap,
                cart.getLocale());
        eventMessage.append(errMsg).append("\n");
      } catch (CartItemModifyException e) {
        Debug.logWarning(
            e,
            UtilProperties.getMessage(
                resource_error, "OrderProblemsAddingItemFromListToCart", cart.getLocale()));
        Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productId", productId);
        errMsg =
            UtilProperties.getMessage(
                resource_error,
                "shoppinglistevents.problem_adding_product_to_cart",
                messageMap,
                cart.getLocale());
        eventMessage.append(errMsg).append("\n");
      } catch (ItemNotFoundException e) {
        Debug.logWarning(
            e, UtilProperties.getMessage(resource_error, "OrderProductNotFound", cart.getLocale()));
        Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productId", productId);
        errMsg =
            UtilProperties.getMessage(
                resource_error,
                "shoppinglistevents.problem_adding_product_to_cart",
                messageMap,
                cart.getLocale());
        eventMessage.append(errMsg).append("\n");
      }
    }

    if (eventMessage.length() > 0) {
      return eventMessage.toString();
    }

    // all done
    return ""; // no message to return; will simply reply as success
  }