// Our custom shopping cart.
// All prices are in pennies (ie. they're integers.  100 is $1)

UIB.cart.Item = function(id, type, name, isbn, price, quantity, shippingLocation)
{
    this.id = id + '_id';
    this.type = type;
    this.name = name;
    this.isbn = isbn;
    this.price = price;
    this.quantity = quantity;
    this.shippingLocation = shippingLocation;
};

UIB.cart.ShippingRate = function(type, domesticStandard, domesticExpedited, internationalStandard, internationalExpedited)
{
    this.type = type;
    this.domesticStandard = domesticStandard;
    this.domesticExpedited = domesticExpedited;
    this.internationalStandard = internationalStandard;
    this.internationalExpedited = internationalExpedited;
};

UIB.cart.Coupon = function(code, discount, discountAsString, isPercent)
{
    this.code = code;
    this.discount = discount;
    this.discountAsString = discountAsString;
    this.isPercent = isPercent;
};

/*
 * @param tableToRender the table to render (the actual element, not the name)
 */
UIB.cart.Cart = function(tableToRender, isReadOnly)
{
    this.idToItemMap = {};
    this.itemArray = [];
    this.idToQuantityMap = {};
    this.isExpeditedShipping = false;
    this.isInternationalShipping = false;
    this.isReadOnly = isReadOnly;
    this.typeToShippingRate = {};
    this.coupon = null;
    this.tableToRender = tableToRender;
    this.isTwoLineFormat = false;
};

UIB.cart.Cart.prototype = 
{
    setShippingForType: function(type, domesticStandard, domesticExpedited, internationalStandard, internationalExpedited)
    {
        this.typeToShippingRate[type] = new UIB.cart.ShippingRate(type, domesticStandard, domesticExpedited, internationalStandard, internationalExpedited);
    },

    setIsExpeditedShipping: function(isExpeditedShipping)
    {
        this.isExpeditedShipping = isExpeditedShipping;
    },

    setIsInternationalShipping: function(isInternationalShipping)
    {
        this.isInternationalShipping = isInternationalShipping;
    },

    setTableToRender: function(tableToRender)
    {
        this.tableToRender = tableToRender;
    },

    /**
     * Set to true if the name should be the first line, and everything else should go on the second line.
     */
    setIsTwoLineFormat: function(isTwoLineFormat)
    {
        this.isTwoLineFormat = isTwoLineFormat;
    },

    getSize: function()
    {
        return this.itemArray.length;
    },

    addItem: function(item, shouldTellServer)
    {
        var id = item.id;
        var noMoreAvailable = true;
        if(!this.idToItemMap[id])
        {
            this.idToItemMap[id] = item;
            this.itemArray.push(item);
            this.itemArray.sort(this.sortByName);
            this.idToQuantityMap[id] = 1;
            noMoreAvailable = false;
        } else {
            var qty = this.idToQuantityMap[id];
            if(qty < item.quantity)
            {
                this.idToQuantityMap[id] = qty + 1;
                noMoreAvailable = false;
            }
        }
        YAHOO.log("Cart now has " + this.getSize() + " items.", "info", "cart");

        if(noMoreAvailable)
        {
            $('serverMsg').innerHTML = "<font class='warning'>That item is already in your cart.</font>";
        } else if(shouldTellServer)
        {
            // Send the info to the server
            $('serverMsg').innerHTML = "<font class='updating'>Updating...</font>";
            new Ajax.Request(
                    "/cart/add/" + id,
            {
                method: "get",
                onSuccess: this.addItemComplete,
                onFailure: this.noServer,
                onException: function(theThis, e) { throw e; }
            });
            if((typeof(window['pageTracker']) != "undefined")) {
                pageTracker._trackPageview("/cart/add/" + id);
            }
        }
        
        if(shouldTellServer)
        {
            cartPanel.show();
        }
    },

    sortByName: function(item1, item2)
    {
        var name1 = item1.name;
        var name2 = item2.name;
        return ((name1 > name2) ? 1 : (name1 < name2) ? -1 : 0);
    },

    clearErrorMessage: function()
    {
        $('serverMsg').innerHTML = "";
    },

    addItemComplete: function(responseObject)
    {
        var response = responseObject.responseText.evalJSON();
        YAHOO.log("AddItemComplete: Received" + response, "info", "cart");
        if(response.success)
        {
            cart.clearErrorMessage();
        } else {
            var error = response.errors.join("|xyx|").escapeHTML().gsub(/\|xyx\|/, "<br>");
            $('serverMsg').innerHTML = "<font class='updating'>Error adding item to cart: " + error + "</font>";
        }
    },

    remove: function(id)
    {
        itemToDelete = this.idToItemMap[id];
        quantityInCart = this.idToQuantityMap[id];
        if(quantityInCart > 1) {
            this.idToQuantityMap[id] = quantityInCart-1;
        } else {
            this.idToItemMap[id] = null;
            this.itemArray = this.itemArray.without(itemToDelete);
            this.idToQuantityMap[id] = null;
        }
        $('serverMsg').innerHTML = "<font class='updating'>Updating...</font>";
        new Ajax.Request(
                "/cart/remove/" + id,
        {
            method: "get",
            onSuccess: this.removeComplete,
            onFailure: this.noServer,
            onException: function(theThis, e) { throw e; }
        });

        YAHOO.log("Cart now has " + this.getSize() + " items.", "info", "cart");
        
        this.render()
    },

    removeComplete: function(responseObject)
    {
        var response = responseObject.responseText.evalJSON();
        YAHOO.log("RemoveComplete: Received" + response, "info", "cart");
        if(response.success)
        {
            $('serverMsg').innerHTML = "";
        } else {
            var error = response.errors.join("|xyx|").escapeHTML().gsub(/\|xyx\|/, "<br>");
            $('serverMsg').innerHTML = "<font class='updating'>Error removing item from cart: " + error + "</font>";
        }
    },

    noServer: function()
    {
        $('serverMsg').innerHTML = "<font class='updating'>Could not reach server.  Please reload this page and try again.</font>";
    },

    getName: function(lineNum)
    {
        return this.itemArray[lineNum].name;
    },

    getItemPrice: function(lineNum)
    {
        var item = this.itemArray[lineNum];
        return item.price;
    },

    getLineTotal: function(lineNum)
    {
        var item = this.itemArray[lineNum];
        return (this.getItemPrice(lineNum) + this.getShippingCostForItem(item)) * this.idToQuantityMap[item.id];
    },

    getShippingCostForItem: function(item)
    {
        var rate = this.typeToShippingRate[item.type];
        if(this.isInternationalShipping)
        {
            if(this.isExpeditedShipping)
            {
                return rate.internationalExpedited;
            } else {
                return rate.internationalStandard;
            }
        } else {
            if(this.isExpeditedShipping)
            {
                return rate.domesticExpedited;
            } else {
                return rate.domesticStandard;
            }
        }
    },

    getShippingDiscount: function()
    {
        var total = 0;
        var warehousesSeenSoFar = [];
        for(var i = 0; i < this.getSize(); i++)
        {
            var item = this.itemArray[i];
            var shippingLocation = item.shippingLocation;
            var quantity = this.idToQuantityMap[item.id];
            if(warehousesSeenSoFar[shippingLocation])
            {
                total += quantity*this.getPerItemShippingDiscount(item);
            } else {
                warehousesSeenSoFar[shippingLocation] = true;
                total += (quantity-1)*this.getPerItemShippingDiscount(item);
            }
        }

        return total;
    },

    getPerItemShippingDiscount: function(item)
    {
        return Math.round((this.getShippingCostForItem(item) + 1)/2);
    },

    getLastGrandTotal: function()
    {
        return this.lastGrandTotal;
    },

    getPrettyLastGrandTotal: function()
    {
        return this.formatAsMoney(this.getLastGrandTotal());
    },
    

    getShippingMethod: function()
    {
        return this.isExpeditedShipping ? 'expedited' : 'standard';

    },

    render: function()
    {
        YAHOO.log("Render was called", "info", "cart");
        var cartSubTotal = 0;
        var salesPriceTotal = 0;
        while(this.tableToRender.tBodies[0].rows.length > 0)
        {
            this.tableToRender.tBodies[0].deleteRow(0);
        }

        var rowNumber = 0;
        for(var i = 0; i < this.getSize(); i++)
        {
            var item = this.itemArray[i];
            var lineTotal = this.getLineTotal(i);
            cartSubTotal += lineTotal;
            salesPriceTotal += this.getItemPrice(i);
            var row = this.tableToRender.tBodies[0].insertRow(rowNumber++);
            var nameCell = this.insertCellWithHTML(row,
                    this.isReadOnly ? '<a href="/catalog_item/show/' + item.isbn + '">' + item.name + '</a>' :
                    '<a href="javascript:cart.remove(\'' + item.id + '\')">' +
                    '<div class="remove" id="' + item.id + '"></div></a><a href="/catalog_item/show/' + item.isbn + '">' + item.name + '</a>',
                    'name');
            if(this.isTwoLineFormat)
            {
                nameCell.colSpan = "4";
                row = this.tableToRender.tBodies[0].insertRow(rowNumber++);
            }
            this.insertCellWithText(row, this.formatAsMoney(this.getItemPrice(i)), "amount");
            this.insertCellWithText(row, this.formatAsMoney(this.getShippingCostForItem(item)), "amount blinkOnShipping");
            this.insertCellWithText(row, this.idToQuantityMap[item.id], "amount");
            this.insertCellWithText(row, this.formatAsMoney(lineTotal), "amount");
        }

        var footerTableToRender = $(this.tableToRender.id + "Footer");
        while(footerTableToRender.rows.length > 0)
        {
            footerTableToRender.deleteRow(0);
        }
        rowNumber = 0;

        var subtotalRow = footerTableToRender.insertRow(rowNumber++);
        var subtotalTitle = this.insertCellWithText(subtotalRow, "Subtotal", "footer");
        this.insertCellWithText(subtotalRow, this.formatAsMoney(cartSubTotal), "footer amount footerAmount blinkOnShipping");

        var shippingDiscountRow = footerTableToRender.insertRow(rowNumber++);
        var shippingDiscountTitle = this.insertCellWithText(shippingDiscountRow, "Shipping discount for items from same location", "footer");
        var shippingDiscount = this.getShippingDiscount();
        this.insertCellWithText(shippingDiscountRow, this.formatAsMoney(shippingDiscount, true), "footer amount footerAmount blinkOnShipping");

        if(this.coupon)
        {
            var couponRow = footerTableToRender.insertRow(rowNumber++);
            this.insertCellWithText(couponRow, "Coupon " + this.coupon.code + " - " + this.coupon.discountAsString + " off cost of items", "footer");
            var couponDiscount;
            if(this.coupon.isPercent)
            {
                couponDiscount = salesPriceTotal * (this.coupon.discount/100);
            } else {
                couponDiscount = salesPriceTotal > this.coupon.discount ? this.coupon.discount : salesPriceTotal;
            }
            this.insertCellWithText(couponRow, "-" + this.formatAsMoney(couponDiscount), "footer amount footerAmount blinkOnShipping");

            this.lastGrandTotal = cartSubTotal - (shippingDiscount + couponDiscount);
        } else {
            this.lastGrandTotal = cartSubTotal - shippingDiscount;
        }

        var grandTotalRow = footerTableToRender.insertRow(rowNumber++);
        this.insertCellWithText(grandTotalRow, "Grand Total", "footer grandTotal");
        this.insertCellWithText(grandTotalRow, this.formatAsMoney(this.lastGrandTotal), "footer amount footerAmount blinkOnShipping grandTotal");

        if($('checkout'))
        {
            $('checkout').enabled =  this.getSize() == 0;
        }
    },

    insertCellWithText: function(row, text, className)
    {
        var cell = row.insertCell(row.cells.length);
        cell.appendChild(document.createTextNode(text));
        if(className)
        {
            cell.className = className;
        }

        return cell;
    },

    insertCellWithHTML: function(row, innerHTML, className)
    {
        var cell = row.insertCell(row.cells.length);
        cell.innerHTML = innerHTML;
        if(className)
        {
            cell.className = className;
        }

        return cell;
    },

    formatAsMoney: function(mnt, showAsNegative) 
    {
        var originalAmount = mnt;
        mnt -= 0;
        mnt = Math.abs(Math.round(mnt)/100);
        var returnVal = mnt == Math.floor(mnt) ? mnt + '.00' : (mnt*10 == Math.floor(mnt*10) ?  mnt + '0' : mnt); 
        
        returnVal = "$" + returnVal;
        if((showAsNegative && originalAmount > 0) || (!showAsNegative && originalAmount < 0))
        {
            returnVal = "-" + returnVal;
        }

        return returnVal;
    },

    enterCoupon: function()
    {

        if(!this.enterCouponPanel)
        {
            this.enterCouponPanel = new YAHOO.widget.Panel("enterCouponPanelDiv",   {
              width:"290px",
              height:"110px",
              fixedcenter:true,
              close:true,
              draggable:true,
              modal:true,
              visible:false,
              zIndex: 40
            });
            this.enterCouponPanel.render();
        }

        this.enterCouponPanel.cfg.setProperty("height", "110px");
        $('couponErrorText').innerHTML = "";
        $('couponServerMsg').innerHTML = "";

        YAHOO.util.Event.addListener($('couponInput'), 'keypress', function(e) {
            // check for return key press
            if (YAHOO.util.Event.getCharCode(e) == 13)
            {
               cart.lookupCoupon(e);
            }
        });

        this.enterCouponPanel.showEvent.subscribe(function() {
            UIB.util.focusOnFirstEmptyTextField($("enterCouponPanelDiv"));           
        });

        this.enterCouponPanel.show();
    },

    lookupCoupon: function()
    {
        $('couponServerMsg').innerHTML = "<font class='updating'>Looking up...</font>";
        new Ajax.Request(
                "/coupons/verify_coupon?code=" + $F("couponInput"),
        {
            method: "get",
            onSuccess: this.lookupCouponComplete,
            onFailure: this.couponNoServer,
            onException: function(theThis, e) { throw e; }
        });
       
    },

    lookupCouponComplete: function(responseObject)
    {
        var response = responseObject.responseText.evalJSON();
        YAHOO.log("LookupCouponComplete: Received" + responseObject.responseText, "info", "cart");
        $('couponServerMsg').innerHTML = "";
        if(response.errorMsg)
        {
            cart.enterCouponPanel.cfg.setProperty("height", "130px");
            $('couponErrorText').innerHTML = response.errorMsg;
        } else {
            cart.coupon = new UIB.cart.Coupon(response.code, response.discount, response.discountAsString, response.isPercent);
            cart.render();
            cart.enterCouponPanel.hide();
        }
    },
    
    couponNoServer: function()
    {
        cart.enterCouponPanel.cfg.setProperty("height", "95px");
        $('couponServerMsg').innerHTML = "";
        $('couponErrorText').innerHTML = "Could not reach server.  Please try again.";
    }
};

