// Peter's Cart (c) Peter Mott, 2007
// Requires prototype.js v. 1.5.1

/**************************************************************
**  Requires viewcart.html and is sensitive to DOM of that file
**  Requires buttons on the purchase page(s) which carry information
**  about 
***************************************************************/ 


/*************************************************************
    **  Globals -
    **  BASKET - name of cookie that holds order
    **  SEP - the string used to separate orderlines in the cookie
    **  DISPLAYBASKET - the id of the table element to which we add
    **  rows showing the current order
    **  INSERTHERE - the id of the hidden element in the PayPal
    **  CHECKOUT - id of the form sent to PayPal 
    **  form after which the order items are inserted
    **  CONTINUESHOPPING - name of the cookie to hold return address
    **  CARTLOCATION - url of the shopping cart
    *************************************************************/ 
 
   
    var BASKET = "TheBasket";
    var SEP = "[[[";
    var DISPLAYBASKET = "displayBasket";
    var CHECKOUT = "checkout";
    var INSERTHERE = "insertHere";
    var CONTINUESHOPPING = "continueShopping";
    
 
    /**************************************************************
    **    Utilities to handle cookies
    **    from: http://www.quirksmode.org/js/cookies.html
    ***************************************************************/ 
    function createCookie(name,value,days) {
        if (days) {
            var date = new Date();
            date.setTime(date.getTime()+(days*24*60*60*1000));
            var expires = "; expires="+date.toGMTString();
        }
        else var expires = "";
        document.cookie = name+"="+value+expires+"; path=/";
    }
    
    function readCookie(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for(var i=0; i < ca.length; i++) {
             var c = ca[i];
             while (c.charAt(0)==' ') c = c.substring(1,c.length);
             if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
        }
        return null;
    }
    
    function eraseCookie(name) {
        createCookie(name,"",-1);
    }
   
    function cookiesOK() {
        createCookie("Test","OK");
        var tmp = readCookie("Test");
        return (tmp == "OK");
    }   

    /**************************************************************
    **  Convert order between cookie and list (items) of orderlines
    **  An orderline is a dictionary with keys: itemName
    **  itemNumber, itemPrice, and itemShipping.
    **  getItems => returns list of orderlines 
    **  putItems => converts list of orderlines to cookie
    **  addItem => adds a list of orderlines to cookie. Creates
    **             if necessary
    ***************************************************************/
    function itemsOrdered() {
        return (getItems()!=[]); 
    }

    function putItems(items) {
        /*
        Save items list as cookie
        items [in] List of dicts one for each orderline.
        */
        var currentBasket = "";
        var codedItems = [];
        for (var i=0; i < items.length; i++) {
            codedItems.push(codeItem(items[i]));
        }
        currentBasket = codedItems.join(SEP);
        currentBasket = encodeURIComponent(currentBasket);
        createCookie(BASKET, currentBasket);
    }
    
    function getItems() {
        //Extract a list of orderlines from cookie. Each orderline is a dictionary
        //with fields itemName, itemNumber, itemPrice, itemShipping, itemQuantity
        //itemSEPitemSEP ... => [itemdict, itemdict ...] or [] if no items
        var items = [];
        var currentBasket = readCookie(BASKET);
        if (currentBasket) {
            currentBasket = decodeURIComponent(currentBasket);
            currentBasket =  currentBasket.split(SEP);
            for (var i=0; i < currentBasket.length; i++) {
                var dict = decodeItem(currentBasket[i]);
                items.push(dict);
            }
        }
        return items;
    }
    function addItem(newItem) {
        //If an item of this name has already been added then increase the item
        //quantity, otherwise add a new item
        var items = getItems();
        for (var i=0; i < items.length; i++) {
            if (items[i]["itemName"] == newItem["itemName"]) {
                var q = parseInt(items[i]["itemQuantity"]) + 1;
                items[i]["itemQuantity"] = q;
                putItems(items);
                return;
            }
        }
        items = items.concat(newItem);
        putItems(items);
    }
        
    function codeItem(item) {
        var coded = "itemName=" + item["itemName"] +
        "&itemNumber=" + item["itemNumber"] +
        "&itemPrice=" + item["itemPrice"] +
        "&itemShipping=" + item["itemShipping"]+
        "&itemQuantity=" + item["itemQuantity"];
        return coded;
    }
    
    function decodeItem(item) {
        //itemName=NAME& .... => {itemName:NAME ... }
        //Fields are itemName, itemNumber, itemPrice, itemShipping, itemQuantity
        var dict = {};
        var L = item.split("&");
        for (var i=0; i<L.length; i++) {
            var M = L[i].split("=");
            dict[M[0]] = M[1];
        }
        return dict;
    }

    /******************************************************
    **  Display the current order 
    *******************************************************/ 
    function displayCart() {
        //First remove any existing display
        var rows = $(DISPLAYBASKET).childElements();
        for (var i=1; i < rows.length; i++) {
            rows[i].remove();
        }
        //Display the current shopping basket from cookie    
        var totalPrice = 0;
        var totalShipping = 0;     
        var items = getItems();
        //The order of the <td> elements is assumed in updateCart
        if (items != []) {
            var table = $(DISPLAYBASKET);
            for (i=0; i<items.length; i++) {
                totalPrice += parseFloat(items[i]["itemPrice"]) *
                              parseFloat(items[i]["itemQuantity"]);
                totalShipping += parseFloat(items[i]["itemShipping"]) *
                              parseFloat(items[i]["itemQuantity"]);
                var tmpls = '<tr><td>#{itemName}</td>\
                             <td><span style="color:black">#{itemPrice}</span></td>\
                             <td><input style="background-color:#E0DBBB" type="text" size="2" value="#{itemQuantity}"/></td>\
                             <td><input type=\"checkbox\"></td></tr>';
                var tmpl = new Template(tmpls);
                var orderLine = tmpl.evaluate(items[i]);
                new Insertion.Bottom(table, orderLine);
            }
        }
        
        var totals = '<tr><td colspan="3" style="text-align:right">SubTotal</td>';
        totals += '<td style="text-align:right"><span style="color:black">#{subTotal}</td></tr>';             
        totals += '<tr><td colspan="3" style="text-align:right">Postage &amp; Packaging</td>';
        totals += '<td style="text-align:right"><span style="color:black">#{totalShipping}</span></td></tr>';
        totals += '<tr><td colspan="3" style="text-align:right">Total &pound;&nbsp;<span style="font-size:smaller">(GBP)</span></td>';
        totals += '<td style="text-align:right"><span style="color:black">#{totalCost}</span></td></tr>';
        var dict = {subTotal:totalPrice.toFixed(2), totalShipping:totalShipping.toFixed(2), totalCost:(totalShipping+totalPrice).toFixed(2)};
        var tmpl = new Template(totals);
        totals = tmpl.evaluate(dict);
        new Insertion.Bottom(table, totals);

    }
    /******************************************************
    **  Update the order. Read the Display and update the cookie
    *******************************************************/

    function updateCart() {
        var HEADS = 1;
        var TRAILS = 3;
        var rows = $(DISPLAYBASKET).childElements();
        // Recover the quantities. Iterate only the orderlines
        var quants = {};
        for (var i=HEADS; i < rows.length-TRAILS; i++) {
            quants[getName(rows[i])] = getQuant(rows[i]);
        }
        // Find the orderlines to remove
        var itemsToRemove = [];
        for (var i=HEADS; i < rows.length-TRAILS; i++) {
            if (needToRemove(rows[i])) {
                itemsToRemove.push(getName(rows[i]));
            }
        }
        var items = getItems();  //current cookie items
        var newItems = [];      
        // Assign new quantities
        for (var i=0; i < items.length; i++) {
            items[i]["itemQuantity"] = quants[items[i]["itemName"]];
        }
        //remove the orderlines previously marked and those with <=0 quantity
        for (i=0; i < items.length; i++) {
            if (notIn(itemsToRemove, items[i]["itemName"]) && items[i]["itemQuantity"]>0) {
                newItems.push(items[i]);
            }
        }
        putItems(newItems);  // writes the new cookie
    }
    
    function notIn(L, o) {
        return L.indexOf(o)==-1;
    }
    
    function getName(row) {
        var td = row.childElements()[0];  
        return td.innerHTML;
    }
    
    function getQuant(row) {
        var quant = row.childElements()[2].firstDescendant().value;
        try {
            quant = parseFloat(quant);
        }
        catch (e) {
            quant = 1;
        }
        return quant;
    }
    
    // total order without postage
    function getTotalOrder() {
        var items = getItems();
        var total = 0;
        for (var i=0; i < items.length; i++) {
            total += parseFloat(items[i]["itemPrice"]) * parseInt(items[i]["itemQuantity"]);
        }
        return total;
    }
        
        
    function needToRemove(row) {
        //True if remove checkbox has been set on row
        var cb = row.childElements()[3].firstDescendant();  //the checkbox for removing an element
        if (cb.checked) {
            return true;
        } else {
            return false;
        }
    }
    
    /******************************************************
    ** Redisplay the order (on update button) 
    *******************************************************/
    function reDisplayCart() {
        updateCart();
        displayCart();
    }
    
    /******************************************************
    **  Continue shopping. The page to return to is held in
    **  a cookie CONTINUESHOPPING
    *******************************************************/
    function continueShopping() {
        updateCart();
        var loc = decodeURIComponent(readCookie(CONTINUESHOPPING));
        self.location = loc;
    }
    
    /******************************************************
    **  Checkout. Update the cookie from display, use cookie
    **  to populate order form (hidden). Submit form to PayPal
    *******************************************************/
    function checkout() {
        if (!itemsOrdered()) {
            if (confirm("You have not ordered anything - do you wish to visit PayPal anyway?")) {
                self.location = "http://www.paypal.com";
                return;
            } else return;
        }
        updateCart();
        var items = getItems();
        for (var i=0; i < items.length; i++) {
            orderInsertItem(items[i], i);
        }
        eraseCookie(BASKET);
        $(CHECKOUT).submit();
        /* if (confirm("Submit?") ) {
            $(CHECKOUT).submit();
        }*/ 
    }
    
    function orderInsertItem(item, at) {
        var lines ='<input type="hidden" name="item_name_#{index}" value="#{itemName}">\
                    <input type="hidden" name="item_number_#{index}" value="#{itemNumber}">\
                    <input type="hidden" name="amount_#{index}" value="#{itemPrice}">\
                    <input type="hidden" name="shipping_#{index}" value="#{itemShipping}">\
                    <input type="hidden" name="shipping2_#{index}" value="#{itemShipping}">\
                    <input type="hidden" name="quantity_#{index}" value="#{itemQuantity}">';
        item["index"] = at+1;  //PayPal items start at 1 not 0
        var tmpl = new Template(lines);
        var lines = tmpl.evaluate(item)
        new Insertion.After(INSERTHERE, lines);
    }

    
    /**************************************************************
    **  Clear Basket
    ***************************************************************/
    function clearCart() {
        eraseCookie(BASKET);
        displayCart();
    }
        
        
    /**************************************************************
    **  addToCart. Add an item to the cookie cart, display the cart page
    **  The function is called from a button. 
    **  The button carries attributes describing the purchased item.
    **  The attributes are:
    **  itemName   - This is the name used on the PayPal form the user sees
    **  itemNumber - A code (string) not seen by user, for merchant to
    **               help identify the item
    **  itemPrice  - the Price of the item (like 4.50)
    **  itemShipping - Post and Package
    **  This can be overridden
    ***************************************************************/
    function onLoadPage() {
        
        //Display dog by ordered items
        //alert("OK" );
        var items = getItems();
        //alert("OK" + items.length);
        var thisPageItems = [];
        try {
            thisPageItems = $$("*[itemName]"); //all buttons carrying an item
            // Above will work in IE
        } catch(e) {
            //For IE7 at least
            //alert(e.name + " " + e.description);
            var tmp = document.getElementsByTagName("img");
            for (var i=0; i < tmp.length; i++) {
                try {
                    var item = $(tmp[i]);
                    var a = item.readAttribute("itemName");
                    if (a != null) {
                        thisPageItems.push(item);
                    }
                } catch(e) {
                        alert(e.name + ": " + e.description);
                }
            }
        }
        for (var i=0; i < items.length; i++) {
            //If the purchased item (itemName) is on this page (thisPageItems) then display its dog
            //itemName my have been changed by appending stuff eg for option 
            //So OK id itemName startswith the item on this page 
            var itemName = items[i]["itemName"];
            //Comparison allows appending data to itemName on adding to cart
            for (var j=0; j<thisPageItems.length; j++) {
                var el = thisPageItems[j];
                if (itemName.startsWith(el.readAttribute("itemName"))) {
                    var dog = el.next(0);
                    dog.setStyle({display:"inline"});
                }
            }
        }
            //var el = thisPageItems.find( function (el) { return el.readAttribute("itemName") == itemName;});
            //if (typeof(el) != "undefined") {
            //    var dog = el.next(0); //next sibling
            //    dog.setStyle({display:"inline"});
            //}
        }
    
    function addToCart(obj) {
        if (!cookiesOK()) {
            alert("Cookies must be enabled to use the shopping Cart");
            return;
        }
        obj = $(obj); // prototype extend to use methods below
        var item = {itemName:obj.readAttribute("itemName"),
                itemNumber:obj.readAttribute("itemNumber"),
                itemPrice:obj.readAttribute("itemPrice"),
                itemShipping:obj.readAttribute("itemShipping"),
                itemQuantity:1}; 
        addItem(item);
        afterAddAction(obj,item)
    }
    //Display current total and view button to user
    function afterAddAction(obj,item) {
        var el = obj.next(1);
        el.innerHTML = "Order total &pound;" + getTotalOrder();
        new Effect.Appear(el,{duration:0.5, to:1.0});
        new Effect.Fade(el, {delay:2.0, duration:2.0, to:0.0});
        el = obj.next(0);
        new Effect.Appear(el, {duration:1.0, to:1.0});
        el.setAttribute("dogShown",item["itemName"]);
    } 
    
    function viewCart(returnUrl,location) {
        var continueShopping = encodeURIComponent(returnUrl);
        createCookie(CONTINUESHOPPING, continueShopping);
        if (location==undefined) {
            location = 'viewcart.html';
        } 
        self.location = location;
    }
    
