/**
 * Calculate Shipping Widget
 * This widget provides the main Rich Cart-like sliding drop down functionality.
 */
dojo.provide("atg.b2cblueprint.widget.CalculateShipping");
dojo.require("dojo.lfx.*");
dojo.require("dojo.html.*");
dojo.require("dojo.html.iframe");
dojo.require("dojo.event.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.io.*");

dojo.widget.defineWidget(
  "atg.b2cblueprint.widget.CalculateShipping", 
  dojo.widget.HtmlWidget,
  {
    // Define all global variables for the widget.
    // templatePath: dojo.uri.dojoUri(contextPath+"/javascript/widget/template/calculateShipping.html"),
    templateString: '<div id="mff_calculateShippingPopup"><div class="close"><a href="javascript:void(0);" dojoAttachEvent="onClick:toggleCalculateShipping" title="${this.i18n.closeText}">${this.i18n.closeText}</a></div><h3>${this.i18n.title}</h3><dl><dt><span dojoAttachPoint="saturdayDelivery"><input type="checkbox" id="saturdayDeliveryFlag" dojoAttachPoint="saturdayDeliveryFlag"/>${this.i18n.deliveryOnSaturday}</span></dt><dt>${this.i18n.type}</dt><dd><select id="calculateShippingSelect" dojoAttachPoint="calculateShippingSelect" onchange="atg.b2cblueprint.shipping.checkSaturday(this,\'calculateShipping\')"></select></dd><dt class="submit"><input type="button" value="${this.i18n.calculateButtonText}" class="mff_inputButton" dojoAttachPoint="calculate" onclick="atg.b2cblueprint.shipping.getShippingCost()"></dt><dt class="note"><p>${this.i18n.calculateShippingNote}<a href="javascript:atg.b2cblueprint.util.notifyMePopup(\'${this.contextroot}/company/shippingRatesPopup.jsp\')" title="${this.i18n.calculateShippingLarnLink}">${this.i18n.calculateShippingLarnLink}</a></p></dt></dl><dl class="total"><dt>${this.i18n.calculateShippingTotal}</dt><dd><span dojoAttachPoint="selectedMethod"></span><span dojoAttachPoint="saturdayDeliveryShow"></span><span dojoAttachPoint="calculateShippingTotal"></span></dl></div>',
    // Widget properties
    triggerWidget: null,  // Reference to trigger widget

//    data: null,           // Cart data - should be set with initial widget initialisation properties

    quantityNodeId: null, // DOM ID of the node to contain the cart quantity - i.e. "Show Cart (3)"

    isContainer: true,    // core var, shows Dojo that this widget will contain other widgets

    hijackClassName: null,  // CSS class used to signify forms/anchors to hijack
    highlightColor: null, // Color used to highlight newly added items
    firstPlacementDone: false,
    cartAnimationInProgress: false,

    duration:{
      // Durations in ms of animation elements
      highlight: 3000,
      scroll:500,
      wipe: 280,
      autoHide:5000
    },

    /**
     * Initialize the widget
     */
    initialize: function(){
      dojo.debug("Initializing RichCartSummary widget");
      // Load any initial data into the widget
      if (this.data!==null){
        this.setAllCartData(this.data);
      }
//
//      // Hook up event handling
      var _this=this;
      dojo.event.connect(window, "onresize", this, "placeCart");
      dojo.event.connect(window, "onscroll", this, "placeCart");
      dojo.event.connect(document.body, "onclick", function(evt){
      // If body is clicked and cart is showing, hide it. Ignore clicks on links or submit buttons
      // as they'll be perfoming an action themselves.
        var type=evt.target.nodeName;
        if (_this.isShowing && type!="A" && type!="INPUT" && type!="BUTTON"){
          _this.hide();
        }
      });
      dojo.event.connect(this.domNode, "onclick", function(evt){
      // Prevent body from handling click within the cart
        evt.stopPropagation();
      });

      this.triggerWidget=dojo.widget.byId("richCalculateShippingTrigger");
    },
    
    postCreate: function(){
      var _this=this;
      dojo.addOnLoad(function(){
        // Prepare for first show animation - hide the element's domNode and call the
        // hide animation. Set a callback to change the visibility when hide is complete.
        _this.domNode.style.visibility="hidden";
        _this.attachToContainer();
        _this.hide(function(){
          _this.domNode.style.visibility="visible";
        });
      });
    },
    
    /**
     * Set the rich cart to display all of the passed in data. This function will be
     * called whenever the rich cart widget is initialised (i.e. on page load) and
     * also whenever an item has been added to the cart and a JSON XHR response
     * is received containing the new cart contents.
     */
    setAllCartData: function(pData){
      dojo.debug("Setting all cart data");
      dojo.debug(pData);
//      this.data=pData;
      
      
      //this.clearCartItems();
      //this.setCartSummaryData();
      
//      if (pData.items){
        // Create CartSummaryItem widget for each line item and add to this parent widget       
//        for (var i=0; i<pData.items.length; i++){        
//          this.addCartItem(pData.items[i]);
//        }
//      }
    },
    
    /**
     * Set the summary data for the cart - this includes the subtotal and item quantity
     */
    setCartSummaryData: function(){      
      // Set the cart quantity total - this is the qty in the 'View Cart (3)' link
      var el;
      if (this.quantityNodeId!==null){
        el=dojo.byId(this.quantityNodeId);
        if (el){
          el.innerHTML = "" + this.data.itemCount + "";
        }       
      }
      
      if (this.data.itemCount===0){
        this.showEmptyCart(true);
      }
      else {
        this.showEmptyCart(false);
        // Set the subtotal amount in the cart
        this.csSubtotal.innerHTML = this.data.subtotal;
      }          
    },
    
    /**
     * Turn on/off certain elements of the cart if it is empty. Display a
     * 'cart is empty' message if it is
     */
    showEmptyCart: function(pEmpty){
      if (pEmpty===true){
        // Cart is empty
        dojo.html.hide(this.csSubtotalContainer);
        dojo.html.hide(this.csCheckout);
        dojo.html.show(this.csEmptyMessage);
      }
      else {
        // Cart is not empty
        dojo.html.show(this.csSubtotalContainer);
        dojo.html.show(this.csCheckout);
        dojo.html.hide(this.csEmptyMessage);
      }
    },
    
    /**
     * Add a line item to the rich cart
     */
    addCartItem: function(data){
      dojo.debug("Adding a Line Item");
      dojo.debug(data);
      var lineItem = dojo.widget.createWidget("atg.b2cblueprint:RichCartSummaryItem", {
        data: data,
        highlightColor: this.highlightColor,
        highlightDuration: this.duration.highlight,
        scrollDuration: this.duration.scroll
      });
      
      this.addChild(lineItem);
      this.csContent.appendChild(lineItem.domNode);
    },   
    
    /*
     * Clear all items from the cart
     */
    clearCartItems: function(){
      this.destroyChildren();
    },
        
    /**
     * Toggle display of the calculate shipping drill-down
     */
    toggleCalculateShipping: function(pEventCodeTracking){
      
      if (this.isShowing===true){
        this.hide();
      }
      else {
        //Added for google analytics  
        if(typeof(pageTracker) != 'undefined'){
          pageTracker._trackEvent('shipping',pEventCodeTracking);
        }
      
        dojo.io.bind({
        load: function(type, data, evt){
          var divColorPicker = dojo.byId("atg_b2cblueprint_calculateShippingResults");
          divColorPicker.innerHTML = data;

          var selectedSku = dojo.byId("hSelectedSku");
          
          if ( '' == selectedSku.value || selectedSku.value == 'unselectedSku') {
            return;
          }
          
          var calculateShippingWidjet = dojo.widget.byId("calculateShipping");
          
          calculateShippingWidjet.selectedMethod.innerHTML = "";
          calculateShippingWidjet.saturdayDeliveryShow.innerHTML = "";
          calculateShippingWidjet.calculateShippingTotal.innerHTML = "";
          
          var calculateShippingSelect = calculateShippingWidjet.calculateShippingSelect;
          var i;
          for (i = calculateShippingSelect.length - 1; i >=0 ; i--) {
            calculateShippingSelect.remove(i);
          }
          
          var methods = document.getElementsByName("hShippingMethods");
          
          for (var i=0; i < methods.length; i++){
            var elOptNew = document.createElement('option');
            if (methods[i].value == 'LTL') {
              elOptNew.text = calculateShippingWidjet.i18n.LTL;
            } else if (methods[i].value == 'Standard 4 to 7 Business Day Delivery') {
              elOptNew.text = calculateShippingWidjet.i18n.standardDelivery;
            } else if (methods[i].value == 'Expedite 2 to 3 Business Day Delivery') {
              elOptNew.text = calculateShippingWidjet.i18n.expediteDelivery;
            } else if (methods[i].value == 'Express 1 Day Delivery') {
              elOptNew.text = calculateShippingWidjet.i18n.expressDelivery;
            } else if (methods[i].value == 'Standard 4 to 7 Business Day Delivery LL') {
              elOptNew.text = calculateShippingWidjet.i18n.standardDeliveryLL;
            } else if (methods[i].value == 'Expedite 2 to 3 Business Day Delivery LL') {
              elOptNew.text = calculateShippingWidjet.i18n.expediteDeliveryLL;
            } else if (methods[i].value == 'Express 1 Day Delivery LL') {
              elOptNew.text = calculateShippingWidjet.i18n.expressDeliveryLL;
            }
             
            elOptNew.value = methods[i].value;
            try {
              calculateShippingSelect.add(elOptNew, null); // standards compliant; doesn't work in IE
            }
            catch(ex) {
              calculateShippingSelect.add(elOptNew); // IE only
            }
            
          }
          
          atg.b2cblueprint.shipping.initSaturdayDeliveryOnProductPage(calculateShippingWidjet, calculateShippingSelect);
          
          calculateShippingWidjet.show();
        },
          
        formNode: dojo.byId("calculateShippingResultsForm")
        });

      }
    },
    
    
    
    /**
     * Position the cart at the correct location on screen
     */
    placeCart: function(){
      if (!this.isShowing && this.firstPlacementDone && !this.cartAnimationInProgress){
        return;
      }
      
      this.firstPlacementDone=true;
      var node = this.triggerWidget.calculateShippingTriggerLink;
      var pos = dojo.html.getAbsolutePosition(node);
      var cartLeft,cartTop,cartHeight,triggerHeight,scrollOffsetHeight;
      
      // Left position is 228 pixels left of the trigger link
      cartLeft = pos.left - 15;
      cartLeft = (cartLeft > 0) ? cartLeft : 0;
      
      // Top position is directly under the trigger link
      triggerHeight = dojo.html.getMarginBox(node).height;
      scrollOffsetHeight=dojo.html.getScroll().offset.y;
      cartTop = 208;
      cartTop = (cartTop-scrollOffsetHeight > 0) ? cartTop : scrollOffsetHeight; 
      
      //dojo.debug("pos.top:"+pos.top+" pos.left:"+pos.left+" triggerHeight:"+triggerHeight+ "scrollOffsetHeight:"+scrollOffsetHeight);
      dojo.debug("Placing cart @ "+cartLeft+", "+cartTop);
                
      this.domNode.style.left=cartLeft+"px";
      this.domNode.style.top=cartTop+"px";
    },

    /**
     * Show the Rich Cart
     */
    show: function(callback) {
      if (this.isShowing){
        // If we've been passed a callback function, then call it even if we're showing. It's
        // most likely that a new item has been added, and the callback is the highlight
        if (callback){
          callback();
        }
        return;
      }
      
      if (this.cartAnimationInProgress===true){
        return;
      }
                
      this.cartAnimationInProgress=true;
      this.placeCart();
      var _this=this;
      var wipeAnimation=dojo.lfx.html.wipeIn(this.domNode, this.duration.wipe, dojo.lfx.easeOut, function(){
        _this.isShowing = true;
        _this.cartAnimationInProgress=false;
        
        // IE6 - prevent form elements from shining through cart with hidden bg iframe
        if(dojo.render.html.ie){
          if(!_this.bgIframe){
            _this.bgIframe = new dojo.html.BackgroundIframe();
            _this.bgIframe.setZIndex(_this.domNode);
          }
          _this.bgIframe.size(_this.domNode);
          _this.bgIframe.show();
        }

        if (callback && dojo.lang.isFunction(callback)){
          callback();
        }
        
      });
      var fadeAnimation=dojo.lfx.html.fade(this.domNode, { start:0.3, end: 1 }, this.duration.wipe, dojo.lfx.easeOut);    
      dojo.lfx.combine([wipeAnimation,fadeAnimation]).play();
    },

    /**
     * Hide the Rich Cart
     */
    hide: function(callback){
      if (this.cartAnimationInProgress===true){
        return;
      }
      
      this.cartAnimationInProgress=true;
      var _this=this;
      var wipeAnimation=dojo.lfx.html.wipeOut(this.domNode, this.duration.wipe, dojo.lfx.easeIn, function(){
        _this.isShowing = false;
        _this.cartAnimationInProgress=false;
        
        // IE6 - Prevent form element shine through - hide hidden iframe
        if(_this.bgIframe){
          _this.bgIframe.hide();
          _this.bgIframe.size({left:0, top:0, width:0, height:0});
        }
		
        if (callback && dojo.lang.isFunction(callback)){
          callback();
        }
      });
      var fadeAnimation=dojo.lfx.html.fade(this.domNode, { start:1, end: 0.8 }, this.duration.wipe); 
      dojo.lfx.combine([wipeAnimation,fadeAnimation]).play();      
      this.triggerWidget.updateTriggerDisplay();
      this.clearAutoHide();
    },
    
    /*
     * Get an array of all items that have been flagged as 'modified. This will
     * usually be just a single item - the item that has just been added to the cart.
     */
    getChangedItemWidgets: function(){
      var changedItems=[];
      var item;
      for (var i=0; i<this.data.items.length; i++){
        item=this.data.items[i];
        if (item.modified===true){
          // Get referene to child widget
          changedItems[changedItems.length] = this.children[i];     
        }
      }
      return changedItems;
    },

    /**
     * Start the auto-hide timer. This will close the rich cart after a short period of
     * time, unless the use mouses over the cart display, in which case the timer
     * will be cancelled so the user can continue to view the contents
     */
    startAutoHide: function(){      
      // Clear any existing auto-hide timer
      if (this.autoHideTimer!==null){
        this.clearAutoHide();
      }
      
      dojo.debug("Starting auto-hide (in "+this.duration.autoHide+" ms)");
      
      // Auto-hide the rich cart after n ms...
      this.autoHideTimer = dojo.lang.setTimeout(this, this.hide, (this.duration.autoHide));
      
      // ... unless the user mouses over the cart
      dojo.event.connect(this.domNode, "onmouseover", this, "clearAutoHide");
    },
      
    /**
     * Clear the auto-hide timer. This will stop the widget from auto-hiding. The user
     * must now click the 'hide rich cart' link/icon to hide the widget 
     */
    clearAutoHide: function(){
      dojo.debug("Clearing auto-hide");
      clearTimeout(this.autoHideTimer);
      dojo.event.disconnect(this.domNode, "onmouseover", this, "clearAutoHide");
      this.autoHideTimer=null;        
    },
    
    /**
     * Handle a JSON response following an 'add to cart' form submission
     */
    handleResponse: function(data,evt,node){
      dojo.debug("RichCart:handleResponse");
      dojo.debug(data);
      dojo.debug(node);
      
      // If we got no data whatsoever, then treat this as a serious error
      if (!data){
        this.handleError();
        return;
      }
      
      // If we got an error back in the data then we need to update the UI to display the errors
      if (data.error){
        dojo.debug("Received error from server - resubmitting form");        
        this.resubmitForm(node);
        return;
      }
      
      // All good, update the UI with new cart data
      this.setAllCartData(data);       
      var alreadyShowing=this.isShowing;    
      var changedItems=this.getChangedItemWidgets();

      // Show the cart and scroll the first newly added item into view
      var _this=this;
      this.show(function(){
        // Scroll the first newly added item into view
        if (changedItems.length>0){
          changedItems[0].scrollIntoView();
        }
        for (var i=0; i<changedItems.length; i++){
          changedItems[i].highlight();
        }
        _this.enableNode(node);
      });
           
      // Start the auto-hide timer if the cart wasn't already showing. This will also reset the timer
      // if it's already running
      if (!alreadyShowing || this.autoHideTimer!==null){
        this.startAutoHide();
      }
    },
    
    /*
     * Connect the cart to all forms and links that have the specified className.
     * The class will be set on any <input type="submit"> and <a> tags that are submitted or clicked
     * to add items to the cart. All of these nodes must be 'hijacked' so that the
     * http request uses XHR so that the rich cart can operate.
     */
    hijackAllAddToCartNodes: function(){
      dojo.debug("Connecting RichCart to all elements with class ["+this.hijackClassName+"]");
      var elements=dojo.html.getElementsByClass(this.hijackClassName);
      for (var i=0; i<elements.length; i++){
        this.hijackNode(elements[i]);
      }     
    },
    
    /*
     * Hijack a node. The node should be either a <form> or an <a> node.
     * Hookup the submit to use XHR instead of standard browser request, and 
     * process the returned JSON data with the handleRespones() function
     * 
     */
    hijackNode: function(node){
      dojo.debug("Hijacking node");
      dojo.debug(node);
           
      if (node.isHijacked){
        dojo.debug("Node is already hijacked - ignoring");
        return;
      }
      node.isHijacked=true;
           
      // Create object with common params for io.bind call
      var _this = this;
      var bindParams={
        headers: { "Accept" : "application/json" },
        mimetype: "application/json",
        load: function(type, data, evt) {
          _this.handleResponse(data,evt,node);
        },
        error: function(type, evt) {
          _this.handleError(type, evt);
        },
        timeout: function(type, evt) {
          _this.handleError(type, evt);
        }
      };
      
      if (node.nodeName=="INPUT"){
        dojo.event.connect(node, "onclick", function(evt){
          evt.preventDefault();
          
          // Get parent form node for this input node
          var formNode=dojo.html.getParentByType(node,"FORM");
          
          // Create content object with the name/value pair of the submit button that's been clicked
          // dojo.io.bind doesn't send the value of submit buttons when serializing the form as it 
          // doesn't know which one has been clicked. Server side FormHandlers need this data to
          // invoke the correct formHandler method.
          var content={};
          content[node.name]=node.value;
          
          dojo.debug("Add to Cart form clicked - submitting form");
          dojo.debug(formNode);
          
          // Add the form node and the submit button name/value to the io.bind params
          dojo.lang.mixin(bindParams,{
            formNode: formNode,
            content: content
          });
          
          _this.disableNode(node);
          dojo.io.bind(bindParams);
        });
      }
      else if (node.nodeName=="A"){        
        dojo.event.connect(node, "onclick", function(evt){
          dojo.debug("Add to Cart link clicked");
          evt.preventDefault();
          
          // Ensure it's not a double click
          if (node.currentlyAdding && node.currentlyAdding===true){
            dojo.debug("This link has already been clicked - ignoring");
            return;
          }
          
          // Add the URL of the clicked link to the io.bind params
          dojo.lang.mixin(bindParams,{
            url: node.href
          });
         
          _this.disableNode(node);
          dojo.io.bind(bindParams);
        });
      }
      else{
        dojo.debug("Node is not a form submit or an anchor - ignoring");
      }     
    },
    
    /**
     * Attach this widget's domNode to its containing node
     */
    attachToContainer: function(){
      dojo.debug("Appending cart domNode to body");
      document.body.appendChild(this.domNode);
    },
    
    /**
     * Function that will be called whenever an error or timeout occurs with an io.bind call
     * Changes the page location to 'url.error'. This is usually set to the standard cart
     * page, so if anything goes wrong with the Rich Cart, we get to fall back to the standard cart.
     */
    handleError: function(type, evt){
      document.location=this.url.error;
    },
    
    /**
     * Disable a node whilst it is being added to the cart. Used to prevent double clicks resulting
     * in duplicate additions to the cart.
     */
    disableNode: function(node){
      // Store original properties we're about to mess with
      node.originalProps={};
      node.originalProps.width=node.style.width;
      node.originalProps.height=node.style.height;
      
      // Set values for width and height so element doesn't change size
      node.style.width=dojo.html.getBorderBox(node).width+"px";
      //node.style.height=dojo.html.getBorderBox(node).height+"px";
        
      if (node.nodeName=="INPUT"){               
        node.originalProps.value=node.value;
        node.disabled=true;
        node.value=this.i18n.addingToCart;
      }
      else if (node.nodeName=="A"){
        node.originalProps.innerHTML=node.innerHTML;
        node.currentlyAdding=true;
        node.innerHTML=this.i18n.addingToCart;
      }
    },
    
    /**
     * Re-enable a node that has been disabled by disableNode();
     */
    enableNode: function(node){      
      if (node.nodeName=="INPUT"){
        node.disabled=false;
        node.value=node.originalProps.value;
      }
      else if (node.nodeName=="A"){
        node.currentlyAdding=false;
        node.innerHTML=node.originalProps.innerHTML;      
      }
      
      // Reset size attributes
      node.style.width=node.originalProps.width;
      node.style.height=node.originalProps.height;
      node.originalProps=null;
    },
    
    /**
     * Resubmit the AddToCart form using a normal HTTP request (non XHR).
     * The Submit button's node should be passed in to signify which button was clicked.
     */
    resubmitForm: function(node){
      // Create hidden form element to copy submit button's value into. Need to do this as disabled elements
      // are not submitted from a form by the browser.
      var replacementNode=document.createElement("INPUT");
      replacementNode.type="hidden";
      replacementNode.name=node.name;
      replacementNode.value=node.value;
      
      // Append this to the parent form
      var formNode=dojo.html.getParentByType(node,"FORM");
      formNode.appendChild(replacementNode);
      
      formNode.submit();
    }
  }
);


