function FloatCart(jsName, idPrefix, stylePrefix, products)
{
  this.jsName = jsName;
  this.idPrefix = idPrefix;
  this.stylePrefix = stylePrefix;
  this.products = products;
  this.ITEMS_PER_PAGE = 3;
  this.currentPageIndex = 0;
  this.debugMode = false;

  this.cartRequester = new BGRequest(this.jsName + '.cartRequester');
  var thisCart = this;
  this.cartRequester.normalHandler = function(txt, xml) {  FloatCart.prototype.requestHandler.call(thisCart, txt, xml);  }
  this.cartRequester.timeoutHandler = function() {  FloatCart.prototype.timeoutHandler.call(thisCart);  }
  this.cartRequester.errorHandler = function(status) {  FloatCart.prototype.errorHandler.call(thisCart, status);  }
  this.cartRequester.reentrantHandler = function() {  FloatCart.prototype.reentrantHandler.call(thisCart);  }
  this.cartRequester.noXMLHttpHandler = function() {  FloatCart.prototype.seriousError.call(thisCart);  }
  this.cartRequester.timeoutInterval = 20000;
  this.floatSelector = null;
  this.ppSubcatId = 0;
  this.addToCartCallbacks = [];
  this.addToCartCallbackErrors = [];
}

FloatCart.prototype.registerAddToCartCallback = function(f)
{
  this.addToCartCallbacks.push(f);
  this.addToCartCallbackErrors.push(null);
  return;
}

FloatCart.prototype.handleAddToCartCallbacks = function(subcatId, productId, qty)
{
  for (var i = 0; i < this.addToCartCallbacks.length; i++)
  {
    try
    {  this.addToCartCallbacks[i](subcatId, productId, qty);  }
    catch (e)
    {  this.addToCartCallbackErrors[i] = e;  }
  }
  return;
}

FloatCart.prototype.requestHandler = function(txt, xml)
{
  try
  {
    var result = eval('(' + txt + ')');
    this.products = result.cartProducts;
    if ((this.floatSelector != null) && result.popupProducts)
      this.floatSelector.products = result.popupProducts;
    var maxPageIndex = this.getMaxPageIndex();
    if ((result.cmd != 'AdjustQty') || (this.currentPageIndex > maxPageIndex))
      this.displayCart(maxPageIndex);
    else
      this.displayCart(this.currentPageIndex);
    this.scrollToCart();
    if (this.floatSelector != null)
    {
      this.floatSelector.updateButton();
      this.floatSelector.hideWindow();
      this.floatSelector.status = 0;
      this.floatSelector.toggleSelector();
    }
  }
  catch(e)
  {
    if (this.debugMode)
    {
      alert('There was an error displaying the updated shopping cart: ' + e.message);
      throw e;
    }
    alert('There was an error displaying the updated shopping cart.');
  }
  return;
}

FloatCart.prototype.timeoutHandler = function()
{
  alert('There was an error contacting the server. Please try again.');
  return;
}

FloatCart.prototype.errorHandler = function(status)
{
  alert('The server returned an error code. Please try again.');
  return;
}

FloatCart.prototype.reentrantHandler = function()
{
  alert('Still busy, please wait.');
  return;
}

FloatCart.prototype.seriousError = function()
{
  alert('Due to a browser compatibility problem, I can not talk to the server to update the shopping cart.');
  return;
}

FloatCart.padDecimal = function(n, decimals)
{
  if (!decimals)
    decimals = 2;
  var isNeg = (n < 0.0);
  if (isNeg)
    n = -n;
  for (var i = 0; i < decimals; i++)
    n *= 10.0;
  n = '' + Math.round(n);
  while (n.length <= decimals)
    n = '0' + n;
  n = n.substring(0, n.length - 2) + '.' + n.substring(n.length - 2);
  if (isNeg)
    n = '-' + n;
  return n;
}

FloatCart.prototype.getMaxPageIndex = function()
{
  var maxPageIndex = Math.floor((this.products.length - 1) / this.ITEMS_PER_PAGE);
  if (maxPageIndex < 0)
    maxPageIndex = 0;
  return maxPageIndex;
}

FloatCart.prototype.getProductByRCPID = function(rcpId)
{
  for (var i = 0; i < this.products.length; i++)
    if (this.products[i].rcpId == rcpId)
      return this.products[i];
  return null;
}

FloatCart.prototype.getTotal = function()
{
  var total = 0.0;
  for (var i = 0; i < this.products.length; i++)
  {
    var curProduct = this.products[i];
    total += curProduct.price * curProduct.qty;
  }
  return total;
}

FloatCart.prototype.getNumItems = function()
{
  var numItems = 0;
  for (var i = 0; i < this.products.length; i++)
    numItems += this.products[i].qty;
  return numItems;
}

FloatCart.prototype.createHtml = function(pageIndex)
{
  var maxPageIndex = this.getMaxPageIndex();
  if (pageIndex > maxPageIndex)
    return '';
  var t = '<div style="border: 1px solid black; background-color: white; color: black; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 8pt; padding: 5px">\n' +
          '  <div class="' + this.stylePrefix + 'HeaderBar" style="padding: 3px">\n' +
          '    <span style="clear:both; float:right"><a href="javascript:' + this.idPrefix + '.hideCart()" style="color: white; text-decoration: none">close <img src="/images/floatCart/float-cart-close.gif" width=9 height=9 border=0></a></span>\n' +
          '    <span style="width:100%"><a name="' + this.idPrefix + 'TableAnchor"></a><b>SHOPPING CART</b></span>\n' +
          '  </div>\n' +
          '  <table border=0 cellspacing=0 cellpadding=0 style="font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 7pt" width="100%">\n';

  var startIndex = pageIndex * this.ITEMS_PER_PAGE;
  var endIndex = startIndex + this.ITEMS_PER_PAGE;
  if (endIndex > this.products.length)
    endIndex = this.products.length;

  for (var i = startIndex; i < endIndex; i++)
  {
    if (i > startIndex)
    {
      t += '    <tr>\n' +
           '      <td></td>\n' +
           '      <td style="background-color: #808080; height: 1"></td>\n' +
           '    </tr>\n';
    }
    var curProduct = this.products[i];
    t += '    <tr>\n' +
         '      <td valign="top" style="padding: 5px 5px 5px 0px">';
    var hasLink = (curProduct.productLink.length > 0);
    if (hasLink)
      t += '<a href="' + curProduct.productLink + '">';
    t += '<img src="' + curProduct.thumbImage + '" onError="' + this.idPrefix + '.thumbImageComingSoon(this)" width=70 height=70 border=1>';
    if (hasLink)
      t += '</a>';
    t += '</td>\n' +
         '      <td valign="top" style="padding: 5px 0px 5px 5px">\n' +
         '        <div class="' + this.stylePrefix + 'PadTopBottom">';
    if (hasLink)
      t += '<a href="' + curProduct.productLink + '" style="text-decoration: none">';
    t += curProduct.dscr;
    if (hasLink)
      t += '</a>';
    t += '</div>\n' +
         '        <div class="' + this.stylePrefix + 'PadTopBottom">\n' +
         '          <span style="clear:both; float:right"><b>PRICE: $' + FloatCart.padDecimal(curProduct.price * curProduct.qty);
    if (curProduct.discountAmt > 0.0)
      t += '<br><font color="red">(-$' + FloatCart.padDecimal(curProduct.discountAmt * curProduct.qty) + ')</font>';
    t += '</b></span>\n' +
         '          <span style="width:100%"><b>QTY: ' + curProduct.qty + '</b></span>\n' +
         '        </div>\n' +
         '        <div class="' + this.stylePrefix + 'PadTopBottom"><a href="javascript:' + this.idPrefix + '.removeItemByIndex(' + i + ')" style="color: green">Remove</a></div>\n' +
         '      </td>\n' +
         '    </tr>\n';
  }
  var isFirstPage = (pageIndex == 0);
  var isLastPage = (pageIndex == maxPageIndex);
  t += '    <tr>\n' +
       '      <td valign="top" align="center" class="' + this.stylePrefix + 'TotalBar" style="padding: 3px">\n';
  if (!isFirstPage)
    t += '<a href="javascript:' + this.idPrefix + '.displayPage(' + (pageIndex - 1) + ')">';
  t += '<img src="/images/floatCart/float-cart-page-left-' + (isFirstPage ? 'disabled' : 'enabled') + '.gif" width=10 height=13 border=0 style="vertical-align: middle">';
  if (!isFirstPage)
    t += '</a>';
  t += ' <b style="vertical-align: middle">Page ' + (pageIndex + 1) + '</b> ';
  if (!isLastPage)
    t += '<a href="javascript:' + this.idPrefix + '.displayPage(' + (pageIndex + 1) + ')">';
  t += '<img src="/images/floatCart/float-cart-page-right-' + (isLastPage ? 'disabled' : 'enabled') + '.gif" width=10 height=13 border=0 style="vertical-align: middle">';
  if (!isLastPage)
    t += '</a>';
  t += '      </td>\n' +
       '      <td valign="top" class="' + this.stylePrefix + 'TotalBar" style="padding: 3px; font-size: 8pt">\n' +
       '        <span style="clear:both; float:right">Total: <b>$' + FloatCart.padDecimal(this.getTotal()) + '</b></span>\n' +
       '        <span style="width:100%">Items: <b>' + this.getNumItems() + '</b></span>\n' +
       '      </td>\n' +
       '    </tr>\n' +
       '  </table>\n' +
       '  <div style="padding: 10px 0px 5px 0px">\n' +
       '    <table border=0 cellspacing=0 cellpadding=0>\n' +
       '      <tr>\n' +
       '        <td width="87" align="left"><a href="javascript:' + this.idPrefix + '.confirmClearCart()"><img src="/images/floatCart/float-cart-clear.gif" width=74 height=19 border=0 alt="Clear Cart"></a></td>\n' +
       '        <td width="86" align="center"><a href="/customer/cart.jsp"><img src="/images/floatCart/float-cart-view.gif" width=74 height=19 border=0 alt="View Cart"></a></td>\n' +
       '        <td width="87" align="right"><a href="/shopping_cart/orderconfirm.jsp"><img src="/images/floatCart/float-cart-checkout.gif" width=74 height=19 border=0 alt="Checkout"></a></td>\n' +
       '      </tr>\n' +
       '    </table>\n' +
       '  </div>\n' +
       '  <div style="padding: 5px 0px 5px 0px">\n' +
       '    <span style="clear:both; float:right"><a href="javascript:' + this.idPrefix + '.hideCart()" style="color:green"><b>Continue Shopping</b></a></span>\n' +
       '    <span style="width:100%"><a href="/shopping_cart/shippingCalculator.jsp" onClick="window.open(\'/shopping_cart/shippingCalculator.jsp\',\'_new\',\'width=600,height=450,innerHeight=450,innerWidth=600,toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes\');return false" style="color: green">Calculate Shipping</a></span>\n' +
       '  </div>\n' +
       '</div>';
  return t;
}

FloatCart.prototype.createSummaryHtml = function()
{
  return 'Cart: $' + FloatCart.padDecimal(this.getTotal()) + ' | Items: ' + this.getNumItems();
}

FloatCart.prototype.removeItemByIndex = function(itemIndex, customUrl)
{
  this.adjustItemQtyByRCPID(this.products[itemIndex].rcpId, -this.products[itemIndex].qty, customUrl);
  return;
}

FloatCart.prototype.removeItemByRCPID = function(rcpid, customUrl)
{
  var p = this.getProductByRCPID(rcpid);
  if (p != null)
    this.adjustItemQtyByRCPID(rcpid, -p.qty, customUrl);
  return;
}

FloatCart.prototype.adjustItemQtyByIndex = function(itemIndex, qtyDelta, customUrl)
{
  this.adjustItemQtyByRCPID(this.products[itemIndex].rcpId, qtyDelta, customUrl);
  return;
}

FloatCart.prototype.adjustItemQtyByRCPID = function(rcpid, qtyDelta, customUrl)
{
  var t = '/customer/modifyCart.jsp?cmd=AdjustQty&qtyDelta=' + qtyDelta + '&id=' + rcpid;
  this.doActualRequest(t, customUrl);
  return;
}

FloatCart.prototype.confirmClearCart = function(customUrl)
{
  if (!confirm('Are you sure you want to remove all items from your shopping cart?'))
    return;
  this.clearCart(customUrl);
  return;
}

FloatCart.prototype.clearCart = function(customUrl)
{
  var t = '/customer/modifyCart.jsp?cmd=ClearCart';
  this.doActualRequest(t, customUrl);
  return;
}

FloatCart.prototype.addToCart = function(productId, qty, giftWrap, customUrl, subcatId)
{
  var t = '/customer/modifyCart.jsp?cmd=AddProduct&qty=' + qty + '&productId=' + productId;
  if (giftWrap)
    t += '&giftWrap=y';
  this.doActualRequest(t, customUrl);
  if (!subcatId)
    subcatId = 0;
  this.handleAddToCartCallbacks(subcatId, productId, qty);
  return;
}

FloatCart.prototype.addCustomProductToCart = function(customProductId, rcpid, customClubsData, giftWrap, customUrl)
{
  var t = '/customer/modifyCart.jsp?cmd=AddCustom&customProductId=' + customProductId + '&rcpid=' + rcpid + '&customClubsData=' + escape(customClubsData);
  if (giftWrap)
    t += '&giftWrap=y';
  this.doActualRequest(t, customUrl);
  return;
}

FloatCart.prototype.addGiftCertificate = function(productId, qty, valueDollars, purchaserName, recipientName, message, deliveryMethod, emailAddress, printFormatName, addressLine1, addressLine2, addressLine3, addressLine4)
{
  var postContent = 'productId=' + productId
                  + '&qty=' + qty
                  + '&valueDollars=' + valueDollars
                  + '&purchaserName=' + escape(purchaserName)
                  + '&recipientName=' + escape(recipientName)
                  + '&message=' + escape(message)
                  + '&deliveryMethod=' + escape(deliveryMethod)
                  + '&emailAddress=' + escape(emailAddress)
                  + '&printFormatName=' + escape(printFormatName)
                  + '&addressLine1=' + escape(addressLine1)
                  + '&addressLine2=' + escape(addressLine2)
                  + '&addressLine3=' + escape(addressLine3)
                  + '&addressLine4=' + escape(addressLine4);
  var t = '/customer/modifyCart.jsp?cmd=AddGCert';
  this.doActualRequest(t, null, postContent);
  return;
}

FloatCart.prototype.addGiftCard = function(productId, qty, purchaserName, recipientName, message, printFormatName)
{
  var postContent = 'productId=' + productId
                  + '&qty=' + qty
                  + '&purchaserName=' + escape(purchaserName)
                  + '&recipientName=' + escape(recipientName)
                  + '&message=' + escape(message)
                  + '&printFormatName=' + escape(printFormatName);
  var t = '/customer/modifyCart.jsp?cmd=AddGCard';
  this.doActualRequest(t, null, postContent);
  return;
}

FloatCart.prototype.addPersonalizedProductToCart = function(productId, qty, profileId, rcpid, personalizedData, giftWrap, customUrl, subcatId)
{
  var t = '/customer/modifyCart.jsp?cmd=AddPersonal&qty=' + qty + '&productId=' + productId + '&profileId=' + profileId + '&rcpid=' + rcpid + '&personalizedData=' + escape(personalizedData);
  if (giftWrap)
    t += '&giftWrap=y';
  this.doActualRequest(t, customUrl);
  if (!subcatId)
    subcatId = 0;
  this.handleAddToCartCallbacks(subcatId, productId, qty);
  return;
}

FloatCart.prototype.changeGiftWrapByRCPID = function(rcpid, newGiftWrapStatus, customUrl)
{
  var t = '/customer/modifyCart.jsp?cmd=ChangeGiftWrap&status=' + (newGiftWrapStatus ? 'Y' : 'N') + '&id=' + rcpid;
  this.doActualRequest(t, customUrl);
  return;
}

FloatCart.prototype.adjustQtys = function(adjustmentList, customUrl)
{
  var t = '/customer/modifyCart.jsp?cmd=AdjustQtys';
  var qtyDeltas = '';
  for (var i = 0; i < adjustmentList.length; i++)
  {
    if (qtyDeltas.length > 0)
      qtyDeltas += ',';
    qtyDeltas += adjustmentList[i];
  }
  t += '&qtyDeltas=' + escape(qtyDeltas);
  this.doActualRequest(t, customUrl);
  return;
}

FloatCart.prototype.doActualRequest = function(url, customUrl, postContent)
{
  var t = url;
  if (this.ppSubcatId > 0)
    t += '&ppSubcatId=' + this.ppSubcatId;
  if (this.catalogItemPrefix && (this.catalogItemPrefix.length > 0))
    t += '&catalogItemPrefix=' + escape(this.catalogItemPrefix);
  var hasCustom = ((customUrl != null) && (customUrl.length > 0));
  if (hasCustom)
    t += '&url=' + escape(customUrl);
  t += '&rnd=' + Math.random();
  if (hasCustom)
    window.location.href = t;
  else
  {
    if (postContent)
      this.cartRequester.performRequest('POST', t, true, ((typeof postContent) == 'string') ? postContent : null, true);
    else
      this.cartRequester.performRequest('GET', t, true, null);
  }
  return;
}

FloatCart.prototype.refreshSummary = function()
{
  var d = this.getSummaryDiv();
  if (d)
    d.innerHTML = this.createSummaryHtml();
  return;
}

FloatCart.prototype.displayPage = function(pageIndex)
{
  if (pageIndex == null)
    pageIndex = this.currentPageIndex;
  var maxPageIndex = this.getMaxPageIndex();
  if (pageIndex > maxPageIndex)
    return;
  var pageHtml = this.createHtml(pageIndex);
  this.currentPageIndex = pageIndex;
  this.refreshSummary();
  var d = this.getMainDiv();
  if (d)
    d.innerHTML = pageHtml;
  return;
}

FloatCart.prototype.toggleDisplayCart = function()
{
  var d = this.getMainDiv();
  if (d.style.visibility == 'hidden')
    this.displayCart();
  else
    this.hideCart();
  return;
}

FloatCart.prototype.displayCart = function(pageIndex)
{
  this.displayPage(pageIndex);
  var d = this.getMainDiv();
  d.style.visibility= 'inherit';
  return;
}

FloatCart.prototype.hideCart = function()
{
  var d = this.getMainDiv();
  d.style.visibility= 'hidden';
  return;
}

FloatCart.prototype.scrollToCart = function()
{
  try
  {
    window.location.hash = this.idPrefix + 'TableAnchor';
  }
  catch (e)
  {  }
  return;
}

FloatCart.prototype.getMainDiv = function()
{
  return document.getElementById(this.idPrefix + 'MainDiv');
}

FloatCart.prototype.getSummaryDiv = function()
{
  return document.getElementById(this.idPrefix + 'SummaryDiv');
}

FloatCart.prototype.thumbImageComingSoon = function(img)
{
  if (img.src.indexOf('/images/products/coming-soon-icon.jpg') < 0)
    img.src = '/images/products/coming-soon-icon.jpg';
  return;
}

function FCProduct(rcpId, prodId, subcatId, pn, price, qty, thumbImage, dscr, productLink, discountAmt)
{
  this.rcpId = rcpId;
  this.prodId = prodId;
  this.subcatId = subcatId;
  this.pn = pn;
  this.price = price;
  this.qty = qty;
  this.thumbImage = thumbImage;
  this.dscr = dscr;
  this.productLink = productLink;
  this.discountAmt = discountAmt;
}
