var basket, IE = /MSIE/.test(navigator.userAgent);

Event.observe(window, 'load', function(event) {
  Responder.onDOMContentLoaded();
  
  var container = $('shopping_basket') || $('whole_checkout');
  if (container) {
    basket = new Basket(container, Basket.Selectors);
    basket.showHideScrollers();
  }
  
  if(!$('order__checkout') && !$('order__payment') && !$('order__complete')) {
    /// FIXME: Slack
    try {
      Event.observe(window, 'resize', basket.showHideScrollers.bind(basket));
    } catch (e) {}
  }
  //scrollerInit();
});

var Basket = Responder.create();
Basket.Selectors = {
  toggleButton: '#toggle_basket_button',
  content: '#basket_items',
  items:   '#items',
  next: '#next_link',
  previous: '#previous_link',
  itemCount:   '#itemCount',
  grandTotal:   '#basket_grand_total',
  subtotal:   '#basket_subtotal',
  hideBasketHelp: '#hideBasketHelp',
  vat: '#basket_vat',
	deliveryCharge: '#delivery_charge',
	deliveryTotal: '#delivery_total'
};

Object.extend(Basket.prototype, {
  itemScrollOffset: 0,
  
  onClickToggleButton: function(event) {
	  if (this.getState()) {
		  this.close(true);
		} else {
			this.open(true);
		}
	},
	
	onChangeDeliveryCharge: function(event) {
		Event.stop(event);
		new Ajax.Request('/basket/set_delivery_charge?update_all=true', {
			onSuccess:this.update.bind(this),
			parameters: {delivery_id: this.deliveryCharge.value}
		});
	},
	
	onClickNext: function(event) {
	  Event.stop(event);
  	this.items.down('.basket_item', this.itemScrollOffset).hide();
	  this.itemScrollOffset++;
	  this.showHideScrollers();
	},
	
	onClickPrevious: function(event) {
    Event.stop(event);
    if (this.itemScrollOffset > 0) {
      this.itemScrollOffset--;
  	  this.items.down('.basket_item', this.itemScrollOffset).show();
    }
    this.showHideScrollers();
	},
	
	showHideScrollers: function() {
	  if (this.itemScrollOffset > 0) {
	    this.previous.show();
	  } else {
	    if(this.previous) this.previous.hide();
	  }
	  if (this.isOverflowed()) {
  	  this.next.show();
	  } else {
	    if(this.next) this.next.hide();
	  }
	},
	
	isOverflowed: function() {
   if(!this.items) return false;
	  var elements   = this.items.getElementsByClassName('basket_item');
    if(elements.length>0) {
      var element = elements[elements.length-1];
	    var container = this.items.up();
	    return (element.offsetLeft + element.offsetWidth) > (container.offsetLeft + container.offsetWidth);
    }else{
      return false;
    }
	},
	
	onClickHideBasketHelp: function(event) {
	  document.cookie = 'hideBasketHelp=true; path=/';
	  new Effect.Fade($('basket_tip'), { duration: 0.3 });
	},
	
	onAddItemSuccess: function(response) {
	  var fragment = document.createDocumentFragmentFromHTML(response.responseText);
	  var elements = $A(fragment.childNodes).select(function(element) {
	    return element.className == 'basket_item';
	  });
	  
	  if (elements.length > 0) {
  	  if (!this.container.visible()) {
  	    if (!this.getState()) {
  	      this.open();
  	    }
  	    Effect.SlideDown(this.container, { duration: 0.4});
  	  } else if (!this.getState()) {
  	    this.open(true);
  	  }	    
	  }
	  
	  var existing;
	  elements.each(function(element) {
	    element = $(element), existing = $(element.id);
      if (existing) {
        existing.parentNode.replaceChild(element, existing);
      } else {
        this.items.appendChild(element);
      }
      if (IE) Event.dispatch({ type: 'DOMNodeInserted', target: element });
	  }.bind(this));
	  
    this.update(response);
		this.showHideScrollers();
	},
	
	update: function(response) {
	  if (response.getResponseHeader('basketIsEmpty') == 'true') {
	    if (document.body.id == 'order__checkout') {
	      //location.reload(true);
      } else {
        new Effect.BlindUp(this.container, { duration: 0.3});
      }
    } else {
  	  ['itemCount', 'subtotal', 'grandTotal', 'deliveryTotal'].each(function(name) {
  	    if (this[name]) {
  	      this[name].update(response.getResponseHeader(name));  	      
  	    }
  	  }.bind(this));      
    }
	},
  
  open: function(slide) {
		this.container.removeClassName('closed');
		this.setState(true);
		this.content.show();
	},
	
	close: function(slide) {
	  this.container.addClassName('closed');
		this.setState(false);
		this.content.hide();
	},
	
	getState: function() {
		return document.cookie.indexOf('basketOpen=true') > -1;
	},
	
  setState: function(isOpen) {
    if (isOpen) {
      document.cookie = 'basketOpen=true; path=/';
    } else {
      document.cookie = 'basketOpen=false; path=/';
    }
  }
});

var Item = Responder.create('.basket_item');

Object.extend(Item.prototype, {
  initialize: function(container) {
    this.container = container;
    this.assignElementsByClassName(container);
		this.qty = container.getElementsByClassName('quantity')[0];
    ['remove', 'upQuantity', 'downQuantity'].each(function(name) {
      if (this[name]) {
        Event.observe(this[name], 'click', this.onClickChange.bind(this));
      }
    }.bind(this));
    this.observe('quantityField');
  },
  
  onKeyUpQuantityField: function(event) {
    if (parseInt(this.quantityField.value) >= 0) {
      var params = {};
      params[this.quantityField.name] = this.quantityField.value;
      new Ajax.Request(this.quantityField.form.action, { parameters: $H(params).toQueryString(), onSuccess: this.update.bind(this) });
    }
  },
  
  onClickChange: function(event) {
    Event.stop(event);
    new Ajax.Request(Event.element(event).href, { onSuccess: this.update.bind(this) });
  },
  
  update: function(response) {
    var element = Element.first(document.createDocumentFragmentFromHTML(response.responseText));
		if(element && window.location.href.match(/\/checkout\s*$/)){ //dont update item on big basket
			this.qty.innerHTML = response.getResponseHeader('qty');
		}else{
	    if (element) {
	      this.container.parentNode.replaceChild(element, this.container);
	      if (IE) Event.dispatch({ type: 'DOMNodeInserted', target: element });
	    } else {
	      new Effect.Fade(this.container, { duration: 0.3, afterFinish: function() {
	        this.container.remove();
	        basket.showHideScrollers();
	        if (document.body.id == 'order__checkout' && response.getResponseHeader('basketIsEmpty') == 'true') {
	  	      location.reload(true);
	        }
	      }.bind(this) });
	    }
		}

	  basket.update(response);
  }
});


/*--------------------------------------------------------------------------*/

ESClasses = {};
ESClasses.InLineEditor = Class.create();
ESClasses.InLineEditor.prototype = {
  initialize: function(options) {
    this.editableElement = $(options['editable']);
    this.enableElement = $(options['whenClicked']);
    this.submitURL =  options['submitTo'];
    this.editing = false;
    this.createEventListeners('onClickSave', 'onClickCancel')
    this.actuateInterface();
  },
  actuateInterface: function() {
    /* Makes the editor work */
    Event.observe(
      this.enableElement,
      'click',
      function(event){
        this.showEditor();
      }.bind(this)
    );    
  },
  extractFromDOM: function(elementOrId) {
    /* Removes an item from the dom and returns a reference that can be used to put it back again */
    var element = $(elementOrId);
    var nextSibling = element.nextSibling;
    var parentNode = element.parentNode;
    parentNode.removeChild(element);
    return([element,parentNode,nextSibling]);
  },
  returnToDOM: function(reference) {
    reference[1].insertBefore(reference[0],reference[2]);
  },
  showEditor: function() {
    /* Shows the editor widget */

    
    /* Remove elements from the DOM and save information used to restore
       them later */

    this.extractedElementTouplets = [];
    this.editableElementParentNode = this.editableElement.parentNode;
    var insertEditorBefore;
    if (this.editableElement.nextSibling == this.enableElement) {      
      this.extractedElementTouplets.push(this.extractFromDOM(this.enableElement));
      this.extractedElementTouplets.push(this.extractFromDOM(this.editableElement));      
      insertEditorAfter = this.enableElement.nextSibling;
    } else {
      this.extractedElementTouplets.push(this.extractFromDOM(this.editableElement));
      this.extractedElementTouplets.push(this.extractFromDOM(this.enableElement));      
      insertEditorBefore = this.editableElement.nextSibling;
    }

/*    this.editableElementNextSibling = this.editableElement.nextSibling;
    this.editableElementParentNode = this.editableElement.parentNode;
    this.enableElementNextSibling = this.enableElement.nextSibling;
    this.enableElementParentNode = this.enableElement.parentNode;
*/       
    /* Create the editor elements */
    /* Editor Field */
    this.editorElement = document.createElement('input');
    this.editorElement.setAttribute('value', this.editableElement.innerHTML)
    
    /* Save Link */
    this.editorSaveElement = document.createElement('a');
    this.editorSaveElement.appendChild(document.createTextNode('Save'));
    this.editorSaveElement.setAttribute('href', '#');
    this.editorSaveElement.onclick = this.eventListeners.onClickSave;
    
    /* Cancel Link */
    this.editorCancelElement = document.createElement('a');
    this.editorCancelElement.appendChild(document.createTextNode('Cancel'));
    this.editorCancelElement.setAttribute('href', '#');
    this.editorCancelElement.onclick = this.eventListeners.onClickCancel;
    
    /* Push the editor elements into the DOM, in reverse order */
    this.editableElementParentNode.insertBefore(this.editorCancelElement, insertEditorBefore);
    this.editableElementParentNode.insertBefore(this.editorSaveElement, this.editorCancelElement);
    this.editableElementParentNode.insertBefore(this.editorElement, this.editorSaveElement);    

    /* Set state */
    this.editing = true;
  },
  hideEditor: function() {
    /* Removes the editor widget */
    
    /* Remove the editor elements from the DOM */
    this.editorCancelElement.parentNode.removeChild(this.editorCancelElement);
    this.editorSaveElement.parentNode.removeChild(this.editorSaveElement);
    this.editorElement.parentNode.removeChild(this.editorElement);    
    this.editorValue = this.editorElement.value;
    delete(this.editorCancelElement);
    delete(this.editorSaveElement);
    delete(this.editorElement);

    /* Restore the original elements */
    while (this.extractedElementTouplets.length > 0) {
      this.returnToDOM(this.extractedElementTouplets.pop());
    }
    delete(this.extractedElementTouplets);
    /* Set state */
    this.editing = false;
  },
  onClickSave: function(event) {
    /* Triggered when the save link is clicked */
    var onSuccess = (function(response) { this.onSaveSuccess(response); }).bind(this);
    var onFailure = (function(response) { this.onSaveFailure(response); }).bind(this);
    var parameters = 'value=' + escape(this.editorElement.value);
    new Ajax.Request(
      this.submitURL, {
        asynchronous: true,
        evalScripts: true,
        parameters: parameters,
        onSuccess: onSuccess,
        onFailure: onFailure
      }
    );
    this.hideEditor();
  },
  onClickCancel: function(event) {
    /* Triggered when the cancel link is clicked */
    this.hideEditor();
  },
  onSaveSuccess: function(response) {
    this.editableElement.innerHTML = this.editorValue;
    this.editableElement.style.display = 'none';
    Effect.Appear(this.editableElement);
    this.onSaveFinish(response);
  },
  onSaveFailure: function(response) {
    Effect.Pulsate(this.editableElement);
    this.onSaveFinish(response);
  },
  onSaveFinish: function(response) {
    
  }
}
Object.extend(ESClasses.InLineEditor.prototype,EditableAttributes.WidgetMethods);




/* little functions for item popup */

showPopupInfo = function(el, e){
	if(!Element.hasClassName(el, 'active') && !ancestorOf(Event.element(e), 'close_popup_btn') ){
		hideAllPopupInfo();
		Element.addClassName(el, 'active');
		new Effect.Appear(el.id+'_popup');
		Event.observe(document,'mousedown',hidePopupIfClickAway);
	}
}
waitThenShowPopup = function(el, e){
	el.onmouseover = function(){return true}
	setTimeout(function(){
		if(el.onmouseover && el.onmouseover.call && el.onmouseover()) showPopupInfo(el, e);
	}, 1500);
	return false
}
hideAllPopupInfo = function(){
	$$('.basket_item').each(function(el){
		Element.removeClassName(el, 'active');
		Element.hide(el.id+'_popup');
	})
	Event.stopObserving(document,'mousedown',hidePopupIfClickAway);
}
hidePopupIfClickAway = function(e){
	if(!ancestorOf( Event.element(e),'popup' )) hideAllPopupInfo();
}


/* JS DOM ancestory */
ancestorOf = function(el, klass){
	gettingSilyCounter=0;
	while (el.tagName!='BODY' && gettingSilyCounter<1000) {
		if(el.className==klass) return true;
		el = el.parentNode;
		gettingSilyCounter++;
	}
	return false;
}


/* advert editor */
var lockAdvert=false;
var advertTimeoutSet=false;
var overEditor=false;
showAdvertEditor = function(){
	overEditor=true;
	// set a timeout and only slidedown after one second of hover
	editor = $('banner_editor');
	if(!advertTimeoutSet && editor && editor.style.display!='block'){
		setTimeout(slideOutAdvertEditor, 500)
		advertTimeoutSet=true
		Event.observe(document,'mousemove',hideAdvertIfMoveOut);
	}
}

slideOutAdvertEditor = function(){
	editor = $('banner_editor');
	if(!lockAdvert && editor && editor.style.display!='block' && overEditor){
		lockAdvert=true; 
		Effect.SlideDown(editor, {
			afterFinish: function(){
				Element.show('banner_controls');
				lockAdvert=false;
			}
		});
	} //endif	
}

hideAdvertIfMoveOut = function(e){	
	if(!ancestorOf( Event.element(e), 'advert') && !lockAdvert){
		overEditor=false;
		advertTimeoutSet=false;
		Event.stopObserving(document,'mousemove',hideAdvertIfMoveOut);
		editor = $('banner_editor');
		if(editor.style.display!='none'){
			Element.hide('banner_controls'); 
			Effect.SlideUp(editor, { 
				afterFinish: function(){
					lockAdvert=false
				} 
			});
		}
	}
}

/*****************************************************************************
 * Called when a product (i.e. shampoo) is added or removed from another's   *
 * (i.e. soap) related_products relationship using an editable_collection in *
 * view.mab. It's task is to ask the user if they wish to add/remove the     *
 * same relationship in the other direction (i.e. add/remove soap from       *
 * shampoo's related_products) relationship and make this happen if they do. *
 *****************************************************************************/

function relatedProductUpdated(effectObject, action) {

	var updatedElement = effectObject.element || effectObject.effects[0].element;
	
	// FIXME: Test in Internet Explorer and Safari
	var updatedProductName = updatedElement.firstChild.lastChild.previousSibling.firstChild.textContent;		
	var pageProductTitleElement = $$('h1.name')[0];
	if (!pageProductTitleElement) return;	
	var pageProductName = pageProductTitleElement.firstChild.textContent;
	
	var matchArray = pageProductTitleElement.firstChild.id.match(/es_product_name_(\d+)_editor/);
	if (!matchArray) return;
	var pageProductId = matchArray[1];
	matchArray = updatedElement.lastChild.getAttribute("onclick").match(/related_id=(\d+)/);
	if (!matchArray) return;
	var updatedProductId = matchArray[1];

	var confirmationMessage = {
		added: 'Would you like to make this a two-way relationship?',
		removed: 'Would like to remove the two-way relationship?'
	}[action];
	
	if (confirm(confirmationMessage)) {		

		var resourceAction = {
			added: 'add',
			removed: 'delete'
		}[action];

	  new Ajax.Request(
	    "/update/product/" + updatedProductId + "/" + resourceAction + "/related_product", {
				method: 'POST',
	      asynchronous: true,
	      evalScripts: true,
	      postBody: "related_product_id=" + pageProductId
	    }
	  );
	}

}

// Cross-browser XPath function

function xPath(oNodes, sXPath) {
  if(oNodes) {
    if(window.XMLHttpRequest) { 
      try {
        var oXpe = new XPathEvaluator();
        var oNsResolver = oXpe.createNSResolver(oNodes.ownerDocument == null ? oNodes.documentElement : oNodes.ownerDocument.documentElement);
        var oResult = oXpe.evaluate(sXPath, oNodes, oNsResolver, 0, null);
        var aFound = [];
        var oRes;
        while (oRes = oResult.iterateNext()) {
          aFound.push(oRes);
        }
        return aFound;
      } catch (e) {
        alert(e.description);
      }
    } else {
      try {
        oNodes.setProperty ("SelectionLanguage", "XPath")
        var oSelectedNode = oNodes.documentElement.selectNodes(sXPath);
        return oSelectedNode;
      } catch (e) {
        alert(e.description);
      }
    }
  }
}

// Assumes you will never pass it more than two decimal places.

function numberToCurrency(string) {
	string = string.toString();
	integerStrings = string.split('.');
	integer = integerStrings[0];
	decimalPlaces = integerStrings.length > 1 ? '.' + integerStrings[1] : '';
	if ( decimalPlaces.length == 2 ) {
		decimalPlaces += '0';
	}
	var regexp = /(\d+)(\d{3})/;
	while ( regexp.test( integer ) ) {
		integer = integer.replace( regexp, '$1' + ',' + '$2' );
	}
	return "&pound;" + integer + decimalPlaces;
}

// Called by the catalogue value template to make mutually-exclusive checkboxes that may sometimes be turned off and sometimes not.

function esProductOptionValueCheckboxes(defaultDomId, defaultDomClass, containerDomId, makeThisValueDefaultUrl, requiredCheckBoxDomId) {
  Event.observe(
    defaultDomId,
    'click',
    function (event) {
      // Don't stop the event
  	  if ( window.discardCheckBoxClicks ) { return(true); }

      // defaultCheckBox = the clicked box
      var defaultCheckBox = Event.element(event);
      var defaultCheckBoxValue = Form.Element.getValue(defaultCheckBox) || 0;

	    if ( !defaultCheckBox.checked ) {

        var requiredCheckbox = $( requiredCheckBoxDomId );

        if (requiredCheckbox.checked) {
          alert('Required options must have a default value.')
          Event.stop(event);
          return(false);
        }
	
      }

      new Ajax.Request(
        makeThisValueDefaultUrl,
        {
          asynchronous: !IE,
          evalScripts:  true,
          parameters:   'value=' + defaultCheckBoxValue
        }
      );

      if ( defaultCheckBox.checked ) {

  	    window.discardCheckBoxClicks = true;
        $$( defaultDomClass ).each(
          function(checkBox) {
            if( checkBox.id != defaultCheckBox.id ) {
              if ( checkBox.checked ) {
                checkBox.click();
              }
            }
          }
        );
        window.discardCheckBoxClicks = false;

      }
      
      return(true);
    }
  );
}




// methods used on product view page
function addWishlistProductWithOptions(url) {      
  var parameters = 'owner_shown_buyer=' + ($('owner_shown_buyer').checked ? '1' : '0');
  parameters += '&everyone_shown_buyer=' + ($('everyone_shown_buyer').checked ? '1' : '0');
  new Ajax.Request(url, {asynchronous:true, evalScripts:true, parameters:parameters, onSuccess: basket.onAddItemSuccess.bind(basket)});
  return false;
}
function addProductWithOptions(url) {
	var parameters = Form.serialize('select_options_and_add_form');
  new Ajax.Request(url, { evalScripts: true, parameters: parameters, onSuccess: basket.onAddItemSuccess.bind(basket) });
  return false;
}
function addProductWithOptionsToWishlist(url) {
  url += (url.indexOf('?') > 0) ? '&' : '?';
  url += Form.serialize('select_options_and_add_form');
  window.location.href = url;
  return false;
}
function addProductViaSigninWithOptions(url) {
  url += (url.indexOf('?') > 0) ? '&' : '?';
  url = escape(url);
  url += Form.serialize('select_options_and_add_form');
  var redirectTo = '/customer/user?redirect_to=' + url;
  window.location.href = redirectTo;
  return false;
}


// Used to hide and show the PaymentSubmit button.

var PaymentSubmit = Class.create();
PaymentSubmit.prototype = {
  initialize: function( elementOrId ) {
    this.element = $(elementOrId);        
    this.visible = true;
  },
  hide: function() {
    if ( !this.visible ) { return( false ); }
    this.parentNode = this.element.parentNode;
    this.nextSibling = this.element.nextSibling;
    this.element.parentNode.removeChild( this.element );
    this.visible = false;    
    return( true );
  },
  show: function() { 
    if ( this.visible ) { return( false ); }
    this.parentNode.insertBefore( this.element, this.nextSibling );
    this.visible = true;    
    delete this.parentNode;
    delete this.nextSibling;
    return( true );
  }
}

// flash crap

function callExternalInterface() {
    thisMovie("wvzobject").extPlay();
}

function thisMovie(movieName) {
    if (navigator.appName.indexOf("Microsoft") != -1) {
    	return window[movieName];
    }
    else {
    	return document[movieName];
    }
}

