if (!("console" in window) || !("firebug" in console))
{
    var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
    "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];

    window.console = {};
    for (var i = 0; i < names.length; ++i)
        window.console[names[i]] = function() {}
}

var AppUtilsClass = Class.create();

AppUtilsClass.prototype = {

	initialize: function () {
		this.ajaxEventCSSClass = "ajax";
		this.ajaxEventURLExt = "ajax=true";
		this.failureContainer = "mainLayoutContentDiv";
		this.loadingContainer = "loadingLayer";
		this.messageDiv = "messageLayer";
		Event.observe(window, 'load', function () {
			AppUtils.attachAJAXEvents();
			AppUtils.attachAjaxResponders();
		});
		
		this.overlayDuration = 0.2;
		this.overlayOpacity = 0.5;
		
		this.showMessageCounter = 0;
		
		//setTimeout(this.initializeOverlay.bind(this), 1000);
	},
	
	initializeOverlay: function() {
		var objBody = document.getElementsByTagName("body").item(0);
		var objOverlay = document.createElement("div");
		objOverlay.setAttribute('id','overlay');
		objOverlay.style.display = 'none';
		objBody.appendChild(objOverlay);
	},
	
	toString: function() {
		return "Utility Javascript";
	},
	
	attachAJAXEvents: function() {
		var anchorElements = document.getElementsByTagName('a');
		var cssClass = this.ajaxEventCSSClass;
		$A(anchorElements).each((function(element) {
			if(element.className.match(new RegExp("(^|\\s)" + this.ajaxEventCSSClass + "(\\s|$)"))) {
				Event.observe(element, "click", (function(event){
					var element = Event.element(event);
					var target = element.className.replace(/.*target-([\w\d\-]+)(\b.*|$)/i, "$1");
					this._attachAjaxEvent(element, target);
					Event.stop(event);
				}).bind(this));
			}
		}).bind(this));
	},
	
	_attachAjaxEvent: function(anchorElem, target, options) {
		var href = anchorElem.getAttribute("href");
		var url = href + (href.indexOf('?') < 0 ? "?" : "&") + this.ajaxEventURLExt;
		new Ajax.Updater({success: target, failure: this.failureContainer}, url, {method: "GET", evalScripts: true, 
			onSuccess: function(originalReq) {
				if (options && options.onSuccess) options.onSuccess(originalReq);
			}
		});
	},
	
	attachAjaxResponders: function () {
		// TODO: Attach the onError handler to show the generic error messages
		Ajax.Responders.register({ 
			onCreate: (function () {
				new Effect.Appear(this.loadingContainer, {duration: 0.3, queue: {position: 'end', scope: 'loadingContainer'}});
			}).bind(this),
			onComplete: (function() { 
				new Effect.Fade(this.loadingContainer, {duration: 0.3, queue: {position: 'end', scope: 'loadingContainer'}});
				AppUtils.attachAJAXEvents();
			}).bind(this),
			onException: (function() { 
				console.log("--- Error START ---")
				$A(arguments).each(function(arg, index) {
					console.log(index + ': ' + arg);
					console.dir(arg);
				});
				console.log("--- Error END ---")
			}).bind(this)
		});
	}, 
	
	loadScripts: function(module) {
		var reqModules = depends.findDependencies(module);
		reqModules.each( function(script) {
			var url= "../js/" + script;
			var element = document.createElement("script");
			element.setAttribute("type", "text/javascript");
			element.setAttribute("src", url);
			document.getElementsByTagName("head")[0].appendChild(element);
		});
	},

	isEmpty: function(text) {
		if (text) return !/\S/.test(text);
		return true;
	},
	
	isNotEmpty: function(text) {
		return !AppUtils.isEmpty(text);
	},
	
	emptyFunction: function() {
	},
	
	ajaxDisplayTable: function(target, options){
		setTimeout((function() {
			this._ajaxDisplayTable(target, options);
		}).bind(this), 50);
	},
	
	_ajaxDisplayTable: function(target, options) {
		var options = Object.extend({tableOrder: 1, tableClass: 'DisplayTable', tableHeaderClass: 'DisplayTableHeader', pageLinksClass: 'pagelinks', onSuccess: this.emptyFunction}, options);
		document.getElementsByClassName(options.tableClass, target).each((function(tableElem, index) {
			if ((index + 1) == options.tableOrder) {
				document.getElementsByClassName(options.tableHeaderClass, tableElem).each((function(headerElem) {
					$A(headerElem.getElementsByTagName('a')).each((function(anchorElem) {
						Event.observe(anchorElem, 'click', (function(event) {
							var elem = Event.element(event);
							this._attachAjaxEvent(elem, target, options);
							Event.stop(event);
						}).bind(this));
					}).bind(this));
				}).bind(this));
			}
		}).bind(this));
		
		document.getElementsByClassName(options.pageLinksClass).each((function(pageLinksElem, index) {
			if ((index + 1) == options.tableOrder) {
				$A(pageLinksElem.getElementsByTagName('a')).each((function(anchorElem) {
					Event.observe(anchorElem, 'click', (function(event) {
						var elem = Event.element(event);
						/* gets the anchor element img tag is wrapped within */
						if (elem.nodeName.toLowerCase() == 'img') elem = elem.parentNode;
						this._attachAjaxEvent(elem, target, options);
						Event.stop(event);
					}).bind(this));
				}).bind(this));
			}
		}).bind(this));
	},
	
	showMessage: function(message, isError) {
		var messageLayer = $(this.messageDiv);
		var isErrorMsg = isError ? isError : false;
		var msg = '';
		if (message.responseXML) {
		    if (message.responseXML.getElementsByTagName("error")[0]){
				isErrorMsg = true;
				msg = message.responseXML.getElementsByTagName("error")[0].firstChild.data;
			} else if (message.responseXML.getElementsByTagName("success")[0]){
				isErrorMsg = false;
				msg = message.responseXML.getElementsByTagName("success")[0].firstChild.data;
			} else {
				msg = message.responseXML;
			}
		} else if (message.responseText){
			msg = message.responseText;
		} else {
			msg = message;
		}
		
		if (isErrorMsg) 
			alert(msg);
		else {
			messageLayer.style.color = 'green';
			messageLayer.innerHTML = msg;
			new Effect.ScrollTo(messageLayer, {offset: -200, duration: 0.5 });
			new Effect.Appear(messageLayer);
			this.showMessageCounter++;
			var counter = this.showMessageCounter;
			setTimeout((function() {
				if (counter == this.showMessageCounter) {
					new Effect.Fade(messageLayer);
				}
			}).bind(this), 5000);
		}
	},
	
	/**
	 * Serializes an associative array e.g. converts "{foor: bar, month: jan}" to "foo=bar&month=jan"
	 */
	serialize: function(object) {
		var result = new Array();
		for (key in object) {
			var value = object[key];
			if (key != 'extend') result.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
		}
		return result.join('&');
	},

	/* used to encode the xml so that it can be safely passed to servers */
	encodeXML: function(xmlText) {	
		return encodeURIComponent(xmlText.replace(/</g, '[').replace(/>/g, ']'));
	},
	
	isEmptyObject: function (theObject) {
		if(typeof theObject != 'undefined' && theObject != '' && theObject != 'null' && theObject != null) return false;
		return true;
	},
	
	toggleNavBox: function(handler, elem) {
		this.toggleNavBoxClassName(handler, elem, {maxClass: 'nav_box_maximize', minClass: 'nav_box_minimize'});
	},

	toggleNavBox: function(handler, elem, params) {
		if (handler.className.indexOf(params.minClass) > -1) {
			new Effect.BlindUp(elem, {duration: 0.3});
			handler.className=params.maxClass;
			handler.title="Expand";
		} else {
			new Effect.BlindDown(elem, {duration: 0.3});
			handler.className=params.minClass;
			handler.title="Collapse";
		}
		handler.blur();
	},

	helpWindow:function (wDoc){
		hWin = window.open(wDoc, "HelpWin", "resizable,menubar,scrollbars,top=300,left=300,width=600,height=400");
	},

	replaceAll:function (str, searchFor, replacement){ 
		if (searchFor.length == 0)
			return str;
		var index = str.indexOf(searchFor);
		while (index >= 0) {  
			str = str.substring(0,index) + replacement + str.substr(index+searchFor.length);
			index = str.indexOf(searchFor);
		}
		return str;
	},

	decodeURIComponent: function(decodedTxt) {
		// first we replace any + chars with single space as javascript built in functions do not replace + wih space character
		var tempTxt = decodedTxt.replace(/\+/g, ' ');
		return decodeURIComponent(tempTxt);
	},
	
	// getPageSize()
	// Returns array with page width, height and window width, height
	// Core code from - quirksmode.org
	// Edit for Firefox by pHaez
	getPageSize: function(){
		
		var xScroll, yScroll;
		
		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}
		
		var windowWidth, windowHeight;
		if (self.innerHeight) {	// all except Explorer
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { // other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	
		
		// for small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}
	
		// for small pages with total width less then width of the viewport
		if(xScroll < windowWidth){	
			pageWidth = windowWidth;
		} else {
			pageWidth = xScroll;
		}
	
		arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight) 
		return arrayPageSize;
	},
	
	getScrollXY: function() {
		return new Array(window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0,
			    window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0);
	},

	showSelectBoxes: function() {
		var selects = document.getElementsByTagName("select");
		for (i = 0; i != selects.length; i++) {
			selects[i].style.visibility = "visible";
		}
	},

	hideSelectBoxes: function(){
		var selects = document.getElementsByTagName("select");
		for (i = 0; i != selects.length; i++) {
			selects[i].style.visibility = "hidden";
		}
	},
	
	showFlash: function(){
		var flashObjects = document.getElementsByTagName("object");
		for (i = 0; i < flashObjects.length; i++) {
			flashObjects[i].style.visibility = "visible";
		}
	
		var flashEmbeds = document.getElementsByTagName("embed");
		for (i = 0; i < flashEmbeds.length; i++) {
			flashEmbeds[i].style.visibility = "visible";
		}
	},
	
	hideFlash: function(){
		var flashObjects = document.getElementsByTagName("object");
		for (i = 0; i < flashObjects.length; i++) {
			flashObjects[i].style.visibility = "hidden";
		}
	
		var flashEmbeds = document.getElementsByTagName("embed");
		for (i = 0; i < flashEmbeds.length; i++) {
			flashEmbeds[i].style.visibility = "hidden";
		}
	},
	
	/*
	 * options = {onClick: function (){}, zIndex: 1000}
	 */
	showOverlay: function (options) {
		this.hideSelectBoxes();
		this.hideFlash();

		// stretch overlay to fill page and fade in
		var arrayPageSize = this.getPageSize();
		var element = $('overlay');
    	element.style.height = arrayPageSize[1] +"px";
    	
    	// following is to fix the opacity problem on IE 6
    	element.style.width = arrayPageSize[0] +"px";
    	
    	if (options && options.zIndex) {
	    	element.style.zIndex = options.zIndex;
    	}
    	
    	if (options && options.onClick) {
			Event.observe(element, 'click', (function () {
				options.onClick();
				this.hideOverlay();
			}).bind(this));
    	} else {
    		Event.observe(element, 'click', this.hideOverlay.bind(this));
    	}
		
		new Effect.Appear('overlay', { duration: this.overlayDuration, from: 0.0, to: this.overlayOpacity });
	},
	
	hideOverlay: function() {
		new Effect.Fade('overlay', { duration: this.overlayDuration});
		this.showSelectBoxes();
		this.showFlash();
	},
	
	isNumber : function(value) {
		value=value.strip();
		var regExp=/^\d+$/;
		return regExp.test(value);
	},
	
	padChars: function(value, padChar, len) {
		// to make sure value is string object
		var value = value + "";
		if (value.length >= len) return value;
		var padString = "";
		for (i = 0; i < len - value.length; i++) {
			padString = padChar + padString;
		}
		
		return padString + value;
	},
	
	trim: function(s){
		// Trim whitespace from left and right sides of s.
		return s.replace(/^\s*/,'').replace(/\s*$/,'');
	},
	
	showModelDialog: function(dialog, options) {
		var dialogElem = $(dialog);
		var dialogWidth = Element.getWidth(dialogElem);
		var dialogHeight = Element.getHeight(dialogElem);
		var arrayPageSize = this.getPageSize();
		var scrollXY = this.getScrollXY();
		var elemLeft = (arrayPageSize[2] - dialogWidth) / 2;
		var elemTop = (arrayPageSize[3] - dialogHeight) / 2;
		
    	dialogElem.style.left = (elemLeft + scrollXY[0]) +"px";
    	dialogElem.style.top = (elemTop + scrollXY[1]) +"px";
    	dialogElem.style.zIndex = options.dialog_zIndex;
    	new Effect.Appear(dialogElem, { duration: 0.3});
		this.showOverlay({zIndex: options.overlay_zIndex, onClick: function() {
			new Effect.Fade(dialogElem, { duration: 0.3});
		}});
	},
	
	hideModelDialog: function(dialog) {
		this.hideOverlay();
		new Effect.Fade(dialog, {duration: 0.3});
	},
	
	createCookie: function(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=/";
	},
	
	getCookie:  function(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;
	},
	
	deleteCookie: function(name) {
		createCookie(name,"",-1);
	}
	
};


var AppUtils = new AppUtilsClass();



AppProperties = {}

AppProperties.Entry = new Class.create();

AppProperties.Entry.prototype = {
	
	initialize: function(key, value) {
		this.key = key;
		this.value = value;
	},
	
	getKey: function() {
		return this.key;
	},
	
	getValue: function() {
		return this.value;
	}
}

AppProperties.Handler = new Class.create();

AppProperties.Handler.prototype = {
	
	initialize: function() {
		this.properties = new Array();
		this.initProperties();
	},
	
	initProperties: function() {
		this.add("simpleCart.impl", "real");
		this.add("imCartURI", "");
		this.add("govEdSSEUPricing.impl", "real");
		this.add("govEdSSEUPricing.url", "");
		this.add("endUsers.impl", "real");
		this.add("endUsers.url", "");
		this.add("it.key", "itna");
		this.add("aidc.key", "aidcna");
		this.add("offline_pnaURI", "/IMD_WASWeb/jsp/order/pa2xml.jsp");
		this.add("offline_pna.impl","real");
	},
	
	add: function(key, value){
		if (!AppUtils.isEmptyObject(key) && !AppUtils.isEmptyObject(value)) 
			this.properties.push(new AppProperties.Entry(key, value));
	},
	
	getProperty: function(key, defaultValue) {
		var value = null;
		this.properties.each(function(entry) {
			if (entry.getKey() == key) {
				value = entry.getValue();
				throw $break;
			}
		});
		
		if (value == null && AppUtils.isEmptyObject(defaultValue)) {
			console.debug("AppProperties ==> Value not found against key " + key);
			return null;
		} else if (value == null) {
			return defaultValue;
		} else {
			return value;
		}
	}
}

var AppProperties = new AppProperties.Handler();


/*
 * Copyright (c) 2006 Jonathan Weiss <jw@innerewut.de> v0.2 - http://blog.innerewut.de/pages/tooltip - Modified to our needs
 */
var Tooltip = Class.create();
Tooltip.prototype = {
	initialize: function(element, tool_tip, options) {
    	this.options = Object.extend({
    	  	default_css: "tooltip",
	    	min_distance_x: 10,
		    min_distance_y: 10,
    		delta_x: 0,
      		delta_y: 0,
	      	zindex: 1000
    	}, options || {});
    	
    	setTimeout((function () {
    		this._init(element, tool_tip);
    	}).bind(this), 1000);
	},
	
	_init: function(element, tool_tip) {

	    this.element = $(element);
	    this.tool_tip = $(tool_tip);
	    
		if (this.element && this.tool_tip) {
	    // hide the tool-tip by default
		    this.tool_tip.hide();
		
		    this.eventMouseOver = this.showTooltip.bindAsEventListener(this);
		    this.eventMouseOut   = this.hideTooltip.bindAsEventListener(this);
		    this.eventMouseMove  = this.moveTooltip.bindAsEventListener(this);
		
		    this.registerEvents();
		}
	},

  	destroy: function() {
    	Event.stopObserving(this.element, "mouseover", this.eventMouseOver);
    	Event.stopObserving(this.element, "mouseout", this.eventMouseOut);
    	Event.stopObserving(this.element, "mousemove", this.eventMouseMove);
  	},

  	registerEvents: function() {
    	Event.observe(this.element, "mouseover", this.eventMouseOver);
    	Event.observe(this.element, "mouseout", this.eventMouseOut);
    	Event.observe(this.element, "mousemove", this.eventMouseMove);
  	},

  	moveTooltip: function(event){
		Event.stop(event);
	  	// get Mouse position
    	var mouse_x = Event.pointerX(event);
	  	var mouse_y = Event.pointerY(event);
	
	  	// decide if wee need to switch sides for the tooltip
	  	var dimensions = Element.getDimensions( this.tool_tip );
	  	var element_width = dimensions.width;
	  	var element_height = dimensions.height;
	
		var pageSize = AppUtils.getPageSize();
		
	  	if ( (element_width + mouse_x) >= ( pageSize[2] - this.options.min_distance_x) ){ // too big for X
			mouse_x = mouse_x - element_width;
		  	// apply min_distance to make sure that the mouse is not on the tool-tip
		  	mouse_x = mouse_x - this.options.min_distance_x;
	  	} else {
		 	mouse_x = mouse_x + this.options.min_distance_x;
	  	}
	
		
		var remPageSize = Position.page(Event.element(event));
		
		// windowHeight - remainingSizeTop - 10
		var remainingSizeBottom = pageSize[3] - remPageSize[1] - 20;
				
	  	// if ( (element_height + mouse_y) >= ( pageSize[3] - this.options.min_distance_y) ){ // too big for Y
	  	if ( (element_height) >= ( (remainingSizeBottom) - this.options.min_distance_y) ){ // too big for Y
		 	 mouse_y = mouse_y - element_height;
	    	// apply min_distance to make sure that the mouse is not on the tool-tip
		  	mouse_y = mouse_y - this.options.min_distance_y;
	  	} else {
		  	mouse_y = mouse_y + this.options.min_distance_y;
	  	} 
	
	  	// now set the right styles
	  	this.setStyles(mouse_x, mouse_y);
  	},
	
 	showTooltip: function(event) {
    	Event.stop(event);
    	this.moveTooltip(event);
	  	Element.show(this.tool_tip);
  	},
  
  	setStyles: function(x, y){
    	// set the right styles to position the tool tip
	  	Element.setStyle(this.tool_tip, { position:'absolute', top: y + this.options.delta_y + "px", left: x + this.options.delta_x + "px", zindex: this.options.zindex });
  	},

  	hideTooltip: function(event){
	  	Element.hide(this.tool_tip);
  	},

  	getWindowHeight: function(){
    	var innerHeight;
	  	if (navigator.appVersion.indexOf('MSIE')>0) {
		  	innerHeight = document.body.clientHeight;
    	} else {
		  	innerHeight = window.innerHeight;
   	 	}
    	return innerHeight;	
  	},
 
  	getWindowWidth: function(){
    	var innerWidth;
	  	if (navigator.appVersion.indexOf('MSIE')>0) {
		  	innerWidth = document.body.clientWidth;
    	} else {
		  	innerWidth = window.innerWidth;
    	}
    	return innerWidth;	
  	}
}



var SimpleCart = Class.create();

SimpleCart.isFakeBackend = AppProperties.getProperty("simpleCart.impl", "real") == "fake";

SimpleCart.CART_TYPE_RESELLER = "reseller";
SimpleCart.CART_TYPE_INTEGRATION = "integration";

SimpleCart.imCartURI = AppProperties.getProperty("imCartURI", "/IMD_WASWeb/jsp/order/cartmgr.jsp");

SimpleCart.VIEW_CART_URI = (SimpleCart.isFakeBackend ? "/ims/fakeSimpleCartBackend.ajax" : SimpleCart.imCartURI) + "?action=view&type={type}";
SimpleCart.DELETE_CART_LINE = (SimpleCart.isFakeBackend ? "/ims/fakeSimpleCartBackend.ajax" : SimpleCart.imCartURI) + "?action=delete&row={row}&type={type}";
SimpleCart.UPDATE_CART_LINE_QTY = (SimpleCart.isFakeBackend ? "/ims/fakeSimpleCartBackend.ajax" : SimpleCart.imCartURI) + "?action=update&qty={qty}&row={row}&type={type}";
SimpleCart.ADD_CART_LINE = (SimpleCart.isFakeBackend ? "/ims/fakeSimpleCartBackend.ajax" : SimpleCart.imCartURI) + "?action=add&sku={sku}&qty={qty}&type={type}";
SimpleCart.ADD_CART_LINE_EU = (SimpleCart.isFakeBackend ? "/ims/fakeSimpleCartBackend.ajax" : SimpleCart.imCartURI) + "?action=add&sku={sku}&qty={qty}&type={type}&euId={euId}&euAddrId={euAddressId}&euContactId={euContactId}&euName={euName}";

SimpleCart.GET_HTML = '/ims/search/simpleCart.ajax';

SimpleCart.prototype = {

	initialize: function(divID, cartType) {
		this.productsDiv = divID + "_products";
		this.cartLineSizeSpanId= "cartLineSize";
		this.msgDiv = divID + "_msg";
		this.effectsQueue = "cartEffectsQueue";
		this.cartType = cartType;
		this.isCartEmpty = true;
		this.effectsCounter = 0;
		this.rowQuantities = new Array();
		this.recentlyAddedSkuQty=0;
		this.addToCartSnapshotID='addToCartSnapshot';
		this.seperator='@divSeparator@';
		this.addedSkus = new Array();
		this.addedSkusQty = new Array();
		this.addedSkusRowID = new Array();
		this.eu = null;
		// sku and end user price {sku: '12312', price: '$123'}
		this.euSkus = null;
		this.viewCart();
	},
	
	viewCart: function() {
		var url = SimpleCart.VIEW_CART_URI.replace(/{type}/, this.cartType);
		setTimeout((function() {
			this.doActualStuff(url, "view");
		}).bind(this), 100);
	},

	addToCart: function(sku,catalog, qty, avail) {
		if (typeof qty == 'undefined') qty = '1';
		if (qty <= 0) {
			AppUtils.showMessage("Unable to add product to cart with zero or negative quantity . Please provide non-zero positive quantity.", true);
			return;
		}
		
		qty = qty.strip();
		var regExp = /^\d+$/;
		if(regExp.test(qty) == false){
			AppUtils.showMessage("Unable to add product to cart with non-numeric value. Please provide non-zero positive quantity.", true);
			return;
		}
		
		if (!(typeof avail == 'undefined') && qty > avail) {
			AppUtils.showMessage("Order Quantity can not be more than Stock Quantity for discontinued items", "error");
			return;
		}

		// lets check the sku being added is already added
		var alreadyAddedIndex = this.addedSkus.indexOf(sku);
		if (alreadyAddedIndex > -1) {
			var skuQty = this.addedSkusQty[alreadyAddedIndex];
			var rowID = this.addedSkusRowID[alreadyAddedIndex];
			console.log("SKU: " + sku + " Qty: " + skuQty + " RowID: " + rowID);
			if (skuQty != qty) {
				var ans = confirm("This item is already in your cart with a quantity of " + skuQty + ". Do you want to change the quantity to " + qty + "?")
				if (ans) {
					this.updateQty(rowID, qty, sku, catalog.strip());
					return;
				}
			} else {
				var newQty = parseInt(qty) + parseInt(skuQty);
				if (!(typeof avail == 'undefined') && newQty > avail) {
					AppUtils.showMessage("Can not change quantity to " + newQty + ". Order Quantity can not be more than Stock Quantity for discontinued items.", "error");
					return;
				}
				var ans = confirm("This item is already in your cart with a quantity of " + skuQty + ". Do you want to change the quantity to " + newQty + "?")
				if (ans) {
					this.updateQty(rowID, newQty, sku, catalog.strip());
					return;
				}
			}
			
			return;
		}
		
		var url = null;
		
		// makes sure we pass any end user selected for this sku
		var endUserNamePrice = null;
		var euIndex = this.eu != null ? this.euSkus.pluck('sku').indexOf(sku) : -1;
		if (euIndex > -1) {
			endUserNamePrice = {euName: this.eu.euName, euPrice: this.euSkus.pluck('price')[euIndex]};

			// due to some bug in IM.com code - we need to make sure every EU id we pass is exactly 9 chars long by padding it with zeros in front
			var euId = AppUtils.padChars(this.eu.euId, "0", 9);
			var euContactId = AppUtils.padChars(this.eu.euContactId, "0", 9);
			var euAddressId = AppUtils.padChars(this.eu.euAddressId, "0", 9);
			url = SimpleCart.ADD_CART_LINE_EU.replace(/{type}/, this.cartType).replace(/{sku}/, sku).replace(/{qty}/, qty).replace(/{euId}/, euId).replace(/{euAddressId}/, euAddressId).replace(/{euContactId}/, euContactId).replace(/{euName}/, encodeURIComponent(this.eu.euName));
			console.log("Add to Cart URL with EU ==> " + url);
		} else {
			url = SimpleCart.ADD_CART_LINE.replace(/{type}/, this.cartType).replace(/{sku}/, sku).replace(/{qty}/, qty);
		}
		
		new Effect.ScrollTo('myCart',{offset:-100});	//scroll to the cart Icon in the mainNavBar to show the snapshot
		if (endUserNamePrice != null) {
			this.doActualStuff(url, "addToCart", {recentlyAddedSku: sku, catalog: catalog.strip(), recentlyAddedSkuQty: qty, euNamePrice: endUserNamePrice});
		} else {
			this.doActualStuff(url, "addToCart", {recentlyAddedSku: sku, catalog: catalog.strip(), recentlyAddedSkuQty: qty});
		}
	},

	updateQty: function(rowID, qty, sku, catalog) {
		if (qty <= 0) {
			AppUtils.showMessage("Can not update quantity to zero or negative value. Please provide non-zero positive quantity.", true);
			return;
		}
		
		new Effect.ScrollTo('myCart',{offset:-100});	//scroll to the cart Icon in the mainNavBar to show the snapshot
		
		var url = SimpleCart.UPDATE_CART_LINE_QTY.replace(/{type}/, this.cartType).replace(/{row}/, rowID).replace(/{qty}/, qty);

		this.doActualStuff(url, "updateQty", {recentlyAddedSku: sku, catalog: catalog.strip(), recentlyAddedSkuQty: qty});
	},

	deleteLine: function(rowID) {
		var url = SimpleCart.DELETE_CART_LINE.replace(/{type}/, this.cartType).replace(/{row}/, rowID);
		this.doActualStuff(url, "deleteLine");
	},

	doActualStuff: function(url, action, options) {
		new Ajax.Request(url, {method: 'get', onSuccess: (function (xmlHttpReq) {
				if (xmlHttpReq.responseXML && xmlHttpReq.responseXML.getElementsByTagName('cart')[0]) {
					if (xmlHttpReq.responseXML && xmlHttpReq.responseXML.getElementsByTagName('status')[0] 
							&& (xmlHttpReq.responseXML.getElementsByTagName('status')[0]).getAttribute("type") == 'error') {
						if (action == 'addToCart')	
							AppUtils.showMessage("Failed to add to cart" + (options ? " for sku " + options.recentlyAddedSku : "" ), true);
						else if (action == 'updateQty')
							AppUtils.showMessage("Failed to update quantity for cart item" + (options ? " sku " + options.recentlyAddedSku + " to " + options.recentlyAddedSkuQty : "" ), true);
					} else if (xmlHttpReq.responseXML && xmlHttpReq.responseXML.getElementsByTagName('row')[0]){
						this.updateUI(xmlHttpReq, action, options);
						Element.update(this.cartLineSizeSpanId,'('+xmlHttpReq.responseXML.getElementsByTagName('row').length+')');
					}
					else
						this.emptyCart();
				} else {
					// we should not reach here
					this.emptyCart();
				}
			}).bind(this)
		});
	},

	updateUI: function(xmlHttpReq, action, options) {
		// we can not pass xmlHttpReq.responseXML to encodeXML as it will pass the XML Document not a string
		var encodedXML = AppUtils.encodeXML(xmlHttpReq.responseText);
		var url = SimpleCart.GET_HTML;
		var params = "encXML=" + encodedXML;
		
		if(options) {
			params = params + "&sku=" + options.recentlyAddedSku + "&qty=" + options.recentlyAddedSkuQty + "&catalog=" + options.catalog;
			if (options.euNamePrice) params = params + "&euName=" + encodeURIComponent(options.euNamePrice.euName) + "&euPrice=" + encodeURIComponent(options.euNamePrice.euPrice);
		}
		
		new Ajax.Request(url, { parameters: params, method: 'get', onSuccess: (function(originalRequest) {
				if (originalRequest.responseXML && originalRequest.responseXML.getElementsByTagName('error')[0])
					this.emptyCart(xmlHttpReq.responseXML.getElementsByTagName('error')[0].firstChild.data, "error");
				
				var respText=originalRequest.responseText;
				Element.update(this.productsDiv, respText.substring(0,respText.indexOf(this.seperator)));
				var snapshotText=respText.substring(respText.indexOf(this.seperator)+this.seperator.length,respText.length);
				snapshotText=snapshotText.replace(/^\s+/,"");	//Left trim
				if(snapshotText.length>1 && $(this.addToCartSnapshotID)){
					Element.update($(this.addToCartSnapshotID),snapshotText);
					this.viewAddToCartSnapshot();
				}
				
				if (this.isCartEmpty) {
					 Element.show(this.productsDiv, { duration: 0.5 });
					this.isCartEmpty = false;
				} else {
					Element.setOpacity(this.productsDiv, 0.1);
					Element.show(this.productsDiv, { duration: 0.5, from: 0.1, to: 1.0 });	
				}
				
				//updating UI for add-to-cart stuff..
				if (options) {
					if($('qtyInCart' + options.recentlyAddedSku + options.catalog))
						$('qtyInCart' + options.recentlyAddedSku + options.catalog).innerHTML = '(' + options.recentlyAddedSkuQty + ')';
					if($('img' + options.recentlyAddedSku + options.catalog)){
						$('img' + options.recentlyAddedSku + options.catalog).src = '<app:imgURL value="elmo/cartarrow.gif"/>';
						$('img' + options.recentlyAddedSku + options.catalog).title = 'Add More to Cart';
					}
					
					// for d_e_class
					if($('d_e_qtyInCart' + options.recentlyAddedSku + options.catalog).innerHTML)
						$('d_e_qtyInCart' + options.recentlyAddedSku + options.catalog).innerHTML = '(' + options.recentlyAddedSkuQty + ')';
					if($('d_e_img' + options.recentlyAddedSku + options.catalog)){
						$('d_e_img' + options.recentlyAddedSku + options.catalog).src = '<app:imgURL value="elmo/cartarrow.gif"/>';
						$('d_e_img' + options.recentlyAddedSku + options.catalog).title = 'Add More to Cart';
					}
				}
				
				this.hideMessage();
				
				/*setTimeout((function() {
					this.attachEvents();
				}).bind(this), 100);*/
			}).bind(this)
		});
		
		this.updateAddedSkus(xmlHttpReq);
		
	},
	
	updateAddedSkus: function(xmlHttpReq) {
		this.addedSkus.clear();
		this.addedSkusQty.clear();
		this.addedSkusRowID.clear();
		var nodes = xmlHttpReq.responseXML.getElementsByTagName('row');
		for (i = 0; i < nodes.length; i++) {
			var sku = nodes[i].getAttribute('sku');
			var qty = nodes[i].getAttribute('qty');
			var rowID = nodes[i].getAttribute('id');
			this.addedSkus.push(sku);
			this.addedSkusQty.push(qty);
			this.addedSkusRowID.push(rowID);
		}
	},
	
	attachEvents: function() {
		var deleteLinks = document.getElementsByClassName('simple-cart-delete-link', this.productsDiv);
		deleteLinks.each((function(link) {
			Event.observe(link, "click", (function(event) {
				var elem = Event.element(event);
				this.deleteLine(elem.getAttribute("rowID"));
				Event.stop(event);
			}).bind(this));
		}).bind(this));
		
		var updateLinks = document.getElementsByClassName('simple-cart-update-link', this.productsDiv);
		updateLinks.each((function(link) {
			var linkElem = $(link);
			Event.observe(linkElem, "click", (function(event) {
				var elem = Event.element(event);
				var qty = $F(elem.getAttribute("qtyInputID"));
				var rowID = elem.getAttribute("rowID");
				this.updateQty(rowID, qty);
				Event.stop(event);
			}).bind(this));
			
			// attach enter key event on qty input box
			Event.observe(linkElem.getAttribute("qtyInputID"), "keypress", (function(event) {
				var elem = Event.element(event);
				switch(event.keyCode) {
					case Event.KEY_RETURN:
		    			this.updateQty(linkElem.getAttribute("rowID"), elem.value);
		    			Event.stop(event);
				}
			}).bind(this));
			
			// attach foucs event on qty input box
			Event.observe(linkElem.getAttribute("qtyInputID"), "focus", (function(event) {
				var elem = Event.element(event);
				this.saveRowQuantity(linkElem.getAttribute("rowID"), elem.value);
				Event.stop(event);
			}).bind(this));

			// attach blur event on qty input box
			/* Event.observe(linkElem.getAttribute("qtyInputID"), "blur", (function(event) {
				var elem = Event.element(event);
				var qty = this.getRowQuantity(linkElem.getAttribute("rowID"));
				if (qty != null) elem.value = qty;
				Event.stop(event);
			}).bind(this)); */
			
		}).bind(this));
	},
	
	saveRowQuantity: function(rowID, qty) {
		var added = false;
		this.rowQuantities.each(function(item) {
			if (item.rowID == rowID) {
				item.qty = qty;
				added = true;
				throw $break;
			}
		});
	
		if (!added)
			this.rowQuantities.push({rowID: rowID, qty: qty});		
	},
	
	getRowQuantity: function(rowID) {
		var value = null;
		this.rowQuantities.each(function(item) {
			if (item.rowID == rowID) {
				value = item.qty;
				throw $break;
			}
		});
		
		if (value == null)
			console.debug("SimpleCart ==> getRowQuantity returning null qty for rowID " + rowID);
		return value;
	},

	emptyCart: function(msg, messageType) {
		this.isCartEmpty = true;
		$(this.productsDiv).innerHTML = "";
		Element.hide(this.productsDiv);
		if (msg) {
			this.showMessage(msg, messageType);
		} else {
			/* TODO use WebMessages */
			this.effectsCounter++;
			this.hideMessage();
			$(this.msgDiv).style.color = 'black';
			$(this.msgDiv).innerHTML= "There are no products added to this cart. Please use <i>Add to Cart</i> button to add products to it.";
			new Effect.Appear(this.msgDiv, { duration: 0.5 });
		}
	},

	showMessage: function(msg, type) {
		this.hideMessage();
		if (type)
			$(this.msgDiv).style.color = type == 'error' ? 'red' : (type == 'success' ? 'green' : 'black');
		$(this.msgDiv).innerHTML = msg;
		
		new Effect.Appear(this.msgDiv, { duration: 0.5 });
		this.effectsCounter++;
		var counterValue = this.effectsCounter;
		setTimeout((function() {
			if (counterValue == this.effectsCounter) 
				if (this.isCartEmpty) {
					this.hideMessage();
					this.emptyCart();
				} else {
					this.hideMessage(true);
				}
			}
		).bind(this), 5000);
	},
	
	hideMessage: function(withEffects) {
		if (withEffects)
			new Effect.Fade(this.msgDiv);
		else {
			Element.hide(this.msgDiv);
		}
	},
	
	showLoading: function() {
		this.effectsCounter++;
		this.hideMessage();
		$(this.msgDiv).style.color = 'black';
		$(this.msgDiv).innerHTML = "Loading ...";
		new Effect.Appear(this.msgDiv, { duration: 0.5 });
	},
	
	viewAddToCartSnapshot:function(){
		new Effect.Appear($(this.addToCartSnapshotID), { duration: 0.2 });
		
			setTimeout((function() {
				this.hideAddToCartSnapshot();
			}
		).bind(this), 5000);
	},
	
	hideAddToCartSnapshot:function(sku){
		new Effect.Fade($(this.addToCartSnapshotID), { duration: 0.2 });
	},
	
	setEU: function(eu, euSkus) {
		this.eu = eu;
		this.euSkus = euSkus;
	},
	
	clearEU: function() {
		this.eu = null;
		this.euSkus = null;
		console.log("Cleared SSEU");
	}
}

function changeCatalog(catalogID, elem){

	var url = '/ims/search/changeCatalog.ajax';
	var pars = 'catalog=' + catalogID;
	var myAjax = new Ajax.Request( url, {method: 'get', parameters: pars});
	
	// we update the catalog bar right away
	updateCatalogBar(catalogID, elem);
}

function updateCatalogBar(catalog, elem){
	var catalogID = null;
		
	if (AppUtils.isNotEmpty(catalog))
		catalogID = catalog;
	else { 
		catalogID = AppUtils.getCookie('catalogID');
		if (AppUtils.isEmpty(catalogID)) 
			catalogID = AppProperties.getProperty('it.key', 'itna');
	}
	
	if (catalogID == AppProperties.getProperty('it.key', 'itna')){
		$('first_catalog_bar').style.display = 'block';
		$('aidc_catalog_bar').style.display = 'none';
		$('itTab').className = 'OnIT_Tab';
		$('aidcTab').className = 'OffAIDC_Tab';
		console.log("catalogID: " +  catalogID);
		console.log($('searchBarForm').elements['catalog'].value);
		$('searchBarForm').elements['catalog'].value = catalogID;
		AppUtils.createCookie("catalogID", catalogID, 1000);
	} else if (catalogID == AppProperties.getProperty('aidc.key', 'aidcna')) {
		$('first_catalog_bar').style.display = 'none';
		$('aidc_catalog_bar').style.display = 'block';
		$('itTab').className = 'OffIT_Tab';
		$('aidcTab').className = 'OnAIDC_Tab';
		console.log("catalogID: " +  catalogID);
		console.log($('searchBarForm').elements['catalog'].value);
		$('searchBarForm').elements['catalog'].value = catalogID;
		AppUtils.createCookie("catalogID", catalogID, 1000);
	} else {
		console.error("Invalid catalog id " + catalogID);
	}
	
	if (elem) elem.blur();
}

function searchBarFormSubmit(){
	var keyword=$('searchKeyword').value;
	if(AppUtils.isEmpty(keyword) || keyword == 'Keywords or Sku/Mfg#' || AppUtils.trim(keyword).length == 0){
		alert('Please provide non empty keyword(s) to search the catalog.');
	}else{
		document.searchBarForm.submit();
	}
}
/**
*  Added by Infosys on <05/08/2007> for Order status Enhancements
*  function goToOrder(in_searchNumber,in_searchNumberType) used for searching orders
*  through the Go To order search available in the page header.
*/
function goToOrder(in_searchNumber,in_searchNumberType){
	if(validateOrderNbr(in_searchNumber,in_searchNumberType)){
		var line1="/IMD_WASWeb/jsp/orderstatus/postorder.jsp?action=order_status_sum.jsp&searchNumber="
		var line2="&searchNumberType="
		var url=line1+in_searchNumber.value+line2+in_searchNumberType.value;
		window.location.href = url;	
	}
}

/**
* Added by Infosys on <05/08/2007> for Order status Enhancements
* checking the length of order number
* finds out whether the user entered order number length is less than three
* or not
*/

function validateOrderNbr(in_searchNumber,in_searchNumberType){
	var orderLabel=in_searchNumberType.value;
	if(orderLabel=='order') {
		orderNbr=in_searchNumber.value;
		lengthOrdrNbr = orderNbr.length;
		if(lengthOrdrNbr < 2) {
			alert("You must enter 2 or more characters");
			in_searchNumber.focus;
			return false;
		}
		else if(lengthOrdrNbr>11) {
			alert("You cannot enter more than 11 characters");
			in_searchNumber.focus;
			return false;
		}
		else {
			return true;
		}
	}
	else {
		return true;
	}
}

function logout() {
    document.cookie = "SMSESSION=; expires=Mon, 01-Jan-90 00:00:01 GMT; path=/; domain=.ingrammicro.com";
    document.cookie = "SMTRYNO=; expires=Mon, 01-Jan-90 00:00:01 GMT; path=/; domain=.ingrammicro.com";
    document.cookie = "SMCHALLENGE=; expires=Mon, 01-Jan-90 00:00:01 GMT; path=/; domain=.ingrammicro.com";
    document.cookie = "SMCREDS=; expires=Mon, 01-Jan-90 00:00:01 GMT; path=/; domain=.ingrammicro.com";
    document.cookie = "SMONDENIEDREDIR=; expires=Mon, 01-Jan-90 00:00:01 GMT; path=/; domain=.ingrammicro.com";
    document.cookie = "smUserType=; expires=Mon, 01-Jan-90 00:00:01 GMT; path=/; domain=.ingrammicro.com";
    document.cookie = "IM_SITE=; expires=Mon, 01-Jan-90 00:00:01 GMT; path=/; domain=.ingrammicro.com";
}

var PnAManager = Class.create();
/*
This is a singleton pnaManager...
all PnA objects become a part of this class. Soooo this can cache all responses
so that ajax based pagination can have improved performance
*/

PnAManager.prototype = {
	initialize: function(params){
		this.url = '/ims/search/pna.ajax';
		this.isFakePnA = AppProperties.getProperty("offline_pna.impl") == "fake";
		this.offLinePnAURL = this.isFakePnA ? "/ims/search/fakePnA.ajax" : AppProperties.getProperty("offline_pnaURI");
		this.pnaRequests = new Array();
		// a queue is associative array {name: queueName, value: new Array()} ... new Array() will contain {pnaReq: pna.js object, skuNumber: 'sku', catalog: 'catalog', qty: 12}
		this.pnaQueues = new Array();
		
		// for syncronization
		this.skuNumbersProcessing = new Array();
	},
	
	loadPnA: function(params) {
		if (AppUtils.isEmpty(params.skuNumber) || AppUtils.isEmpty(params.catalog)) {
			console.error("PnA req missing skuNumber and/or catalog", params);
			return;
		}

		if (AppUtils.isEmpty(params.quantity)) params.quantity = 1;
		
		var pnaReq = this.pnaRequests.length == 0 ? null : this.pnaRequests.find(function (item) { 
			return item.params.skuNumber == params.skuNumber && 
						item.params.catalog == params.catalog && 
							item.params.quantity == params.quantity;
		});
		if (AppUtils.isEmpty(pnaReq)) {
			//console.debug("PnA ==> creating new pnaReq object " + params.skuNumber + " " + params.catalog + " " +  params.quantity + " " + params.targetDiv);
			var pnaRequest = new PnA(params);
			this.pnaRequests.push({ request: pnaRequest, params: params});
			pnaRequest.loadPnA();
		} else if (pnaReq.request.hasResponse) {
			//console.debug("PnA ==> pnaReq object exists and response recieved " + params.skuNumber + " " + params.targetDiv);
			pnaReq.request.addTargetDiv(params.targetDiv);
			pnaReq.request.showPnAResponse();
		} else {
			//console.debug("PnA ==> pnaReq object exists and response pending " + params.skuNumber + " " + params.targetDiv);
			pnaReq.request.addTargetDiv(params.targetDiv);
		}
	},
	
	hasProduct:function(param) {
		return (this.pnaRequests.length > 0) && this.pnaRequests.any( function (e) { 
			return e.skuNumber == param;
		});
	},
	
	addRequestToQueue:function(params, queueName) {
		if (AppUtils.isEmpty(params.skuNumber) || AppUtils.isEmpty(params.catalog)) {
			console.error("PnA queue req missing skuNumber and/or catalog", params);
			return;
		}
		
		if (AppUtils.isEmpty(params.quantity)) params.quantity = 1;
		
		var queue = this.pnaQueues.find(function (item) { return item.name == queueName});
		var isQueueEmpty = AppUtils.isEmpty(queue);
		var pnaReq = null;
		if (isQueueEmpty) {
			//console.debug("PnA Queued ==> Creating new pna queue " + queueName);
			queue = {name: queueName, value: new Array()};
			this.pnaQueues.push(queue);
		} else {
			pnaReq = queue.value.find(function (item) { 
				return item.params.skuNumber == params.skuNumber && 
							item.params.catalog == params.catalog && 
								item.params.quantity == params.quantity;
			});
		}
		
		var isPnAReqEmpty = AppUtils.isEmpty(pnaReq);
		
		if (isPnAReqEmpty) {
			//console.debug("PnA Queued ==> creating new queued pnaReq object " + params.skuNumber + " " + params.catalog + " " +  params.quantity + " " + params.targetDiv);
			var pnaRequest = new PnA(params);
			queue.value.push({ request: pnaRequest, params: params });
			this.skuNumbersProcessing.splice(this.skuNumbersProcessing.indexOf(params.skuNumber), 1);
		} else if (pnaReq.request.hasResponse) {
			//console.debug("PnA Queued ==> queued pnaReq object exists and response recieved " + params.skuNumber);
			pnaReq.request.addTargetDiv(params.targetDiv);
			pnaReq.request.showPnAResponse();
		} else {
			// more verbose
			// console.debug("PnA Queued ==> queued pnaReq object exists and response pending " + params.skuNumber);
			pnaReq.request.addTargetDiv(params.targetDiv);
		}
	},
	
	executePnARequests:function(queueName){
		var queue = this.pnaQueues.find(function (item) { return item.name == queueName});
		
		if(AppUtils.isEmpty(queue)) {
			console.error("PnA Queued ==> cannot call executePnARequests, no pna queue found with name " + queueName)
			return;
		}
		
		var pars = 'sku=' + queue.value.pluck('params').pluck('skuNumber').join(',') + 
					"&catalog=" + queue.value.pluck('params').pluck('catalog').join(',') + 
					"&quantity=" + queue.value.pluck('params').pluck('quantity').join(',');
		
		var removed = this.pnaQueues.splice(this.pnaQueues.pluck('name').indexOf(queue.name), 1);
		console.debug("PnA Queued ==> Removed queue " + removed[0].name);		
		
		var queue = removed[0];
		
		new Ajax.Request(this.url, { method: 'get', parameters: pars, onSuccess: (function(originalReq) {

			var offlinePnAReqResp = new Array();
			var onlinePnAResps = originalReq.responseXML.getElementsByTagName('pna-info');
			
			var pnaReqs = queue.value;
			for (var index = 0; index < pnaReqs.length ; index++){
				var onLineTag = onlinePnAResps[index].getElementsByTagName('isOnlineData')[0];
				if (onLineTag && onLineTag.firstChild.data != 'true') {
					offlinePnAReqResp.push({pnaReq: pnaReqs[index], pnaResp: onlinePnAResps[index]});
				} else {
					pnaReqs[index].request.updateState(onlinePnAResps[index]);
					// we add it to this.pnaRequests for re-usability on same page
					this.pnaRequests.push(pnaReqs[index]);
				}
			}

			if (offlinePnAReqResp.length > 0)
				this.executeOffLinePnARequests(offlinePnAReqResp);
		}).bind(this) });
		
	},

	executeOffLinePnARequests: function(offlinePnAReqResp) {
		var pars = 'skus=' + offlinePnAReqResp.pluck('pnaReq').pluck('params').pluck('skuNumber').join(',') + "&mode=offline"
		
		new Ajax.Request(this.offLinePnAURL, { method: 'get', parameters: pars, onSuccess: (function(originalOfflineReq) { 
			this.updatePnAState(offlinePnAReqResp, originalOfflineReq);
		}).bind(this), onFailure: (function(originalReq) { 
			this.updatePnAState(offlinePnAReqResp);
		}).bind(this) });
	},
	
	updatePnAState:function(offlinePnAReqResp, originalOfflineReq){
		var offline_pnaXMLResps = null;
		if (originalOfflineReq)
			offline_pnaXMLResps= originalOfflineReq.responseXML.getElementsByTagName('offline-pna');
			
		for (var index = 0; index < offlinePnAReqResp.length ; index++){
			if (offline_pnaXMLResps != null) {
				var statusTag = offline_pnaXMLResps[index].getElementsByTagName('status')[0];
				if (!AppUtils.isEmpty(statusTag.getAttribute('type')) && statusTag.getAttribute('type').toLowerCase() == 'success') 
					offlinePnAReqResp[index].pnaReq.request.updateState(offlinePnAReqResp[index].pnaResp, offline_pnaXMLResps[index]);
				else
					offlinePnAReqResp[index].pnaReq.request.updateState(offlinePnAReqResp[index].pnaResp, null, statusTag);
			} else {
				offlinePnAReqResp[index].pnaReq.request.updateState(offlinePnAReqResp[index].pnaResp);
			}
			// we add it to this.pnaRequests for re-usability on same page
			this.pnaRequests.push(offlinePnAReqResp[index].pnaReq);
		}
	}
};

pnaManager = new PnAManager();

var PnA = Class.create();
	
/*
Mandatory

catalog
skuNumber
targetDiv


Optional

quantity
url

*/

PnA.prototype = {
	// the default values for everything related to pna can be set here.
	defaults: {
		url:'/ims/search/pna.ajax',
		unknownAvailability:'Call',	// IMS-3
		unknownPrice:'Call',		// IMS-3
		unknownListPrice:'Call',	// IMS-3
		listPriceNotAvailable:'Not Available', // IMS-4
		unknownFromIMG:'Unknown'
	},
	
	offlineDefaults: {
		availability: 'Call',
		price: 'Call',
		listPrice: '',
		offlinePnAIndicator: 'offlinePnAIndicator'
	},

	initialize: function(params){
		if (params != null) {

			// optional
			this.url = AppUtils.isEmptyObject(params.url)?this.defaults.url:params.url;
			this.quantity = (AppUtils.isEmptyObject(params.quantity))?1:(isNaN(parseInt(params.quantity)))?1:parseInt(params.quantity);
			
			// offline PnA
			this.isFakePnA = AppProperties.getProperty("offline_pna.impl") == "fake";
			this.offLinePnAURL = this.isFakePnA ? "/ims/search/fakePnA.ajax" : AppProperties.getProperty("offline_pnaURI");

			// Mandatory
			this.catalog = AppUtils.isEmptyObject(params.catalog)?'':params.catalog;
			this.skuNumber = AppUtils.isEmptyObject(params.skuNumber)?'':params.skuNumber;
			this.targetDiv = new Array();
			if (!AppUtils.isEmptyObject(params.targetDiv)) {
				this.targetDiv.push(params.targetDiv);
			}
			
			// check Gov/Ed & SSEU links
			this.checkGovEdLink = 'viewGovEdLink';
			this.checkSSEULink = 'checkSSEULink';
			
			// parameter validation			
			// Catalog cannot be empty
			if (AppUtils.isEmpty(this.catalog))  {
				throw('IllegalArgumentException: A non-empty catalog key is required. skuNumber cannot be empty. [PnA.initialize]');
			}
			// skuNumber cannot be empty
			if (AppUtils.isEmpty(this.skuNumber))  {
				throw('IllegalArgumentException: No valid product identification criteria. skuNumber cannot be empty. [PnA.initialize]');
			}
			
			this.isBasePrice = false;
			this.isOnlineData = true;
			
			// initializing other stuff
			this.hasResponse = false;
			this.error=false;
			this.errorMessage='';
		} 
		else 
			throw({name:'NullPointerException', message:'params is null [PnA.initialize]'});
	},
	
	loadPnA: function() {
		var pars= 'quantity=' + this.quantity + '&catalog=' + this.catalog;
		pars = pars + '&sku=' + this.skuNumber;
		new Ajax.Request(this.url, { method: 'get', parameters: pars, onSuccess: (function(originalReq) {
			// if it is offline pna, go call IM.com offline pna servlet
			var onLineTag = originalReq.responseXML.getElementsByTagName('isOnlineData')[0];
			if (onLineTag && onLineTag.firstChild.data != 'true')
				this.loadOffLinePnA(originalReq.responseXML);
			else
				this.updateState(originalReq.responseXML);
		}).bind(this) });
	},
	
	loadOffLinePnA: function(responseXML) {
		var pars= 'skus=' + this.skuNumber + "&mode=offline";
		new Ajax.Request(this.offLinePnAURL, { method: 'get', parameters: pars, onSuccess: (function(originalReq) {
			var statusTag = originalReq.responseXML.getElementsByTagName('status')[0];
			if (!AppUtils.isEmpty(statusTag.getAttribute('type')) && statusTag.getAttribute('type').toLowerCase() == 'success') 
				this.updateState(responseXML, originalReq.responseXML);
			else 
				this.updateState(responseXML, null, statusTag);
		}).bind(this), onFailure: (function(originalReq) { 
			this.updateState(responseXML);
		}).bind(this) });
	},
	
	// assumptions are evil... I am assuming that if <error> element doesnt exist, 
	// then a valid set of <price> <availability> <id> <catalog> will exist for sure ...
	// <warehouseAvailaibilities> <isAuthorizedPurchase> and <listPrice> may or may not exist!
	updateState: function(responseXML, offlinePnAxml, offlinePnAStatusTag) {
		this.response=responseXML;
		if (responseXML.getElementsByTagName('error')[0]){
			this.error=true;
			this.errorMessage=responseXML.getElementsByTagName('error')[0];
			this.showPnAError();
		} else {
			var onLineTag = responseXML.getElementsByTagName('isOnlineData')[0];
			if (onLineTag && onLineTag.firstChild.data != 'true') this.isOnlineData = false;
			
			if (!this.isOnlineData) {
				this.showOfflinePnAIndicator();
				this.hideGovEdSSEULinks();
			}
			
			if (offlinePnAxml) {
				this.price = offlinePnAxml.getElementsByTagName('base-price')[0].firstChild.data;
				this.isBasePrice = true;
			} else {
				this.price = responseXML.getElementsByTagName('price')[0].firstChild.data;
				if (!this.isOnlineData) {
					if (responseXML.getElementsByTagName('offlinePrice')[0]) 
						this.price = responseXML.getElementsByTagName('offlinePrice')[0].firstChild.data;
					else 
						this.price = this.offlineDefaults.price;
					this.isBasePrice = true;
				} else if (this.price == this.defaults.unknownFromIMG)
					this.price = this.defaults.unknownPrice;
			}
			
			if (offlinePnAxml) {
				if (offlinePnAxml.getElementsByTagName("warehousesAvailabilities")[0])
					this.warehousesAvailabilities = offlinePnAxml.getElementsByTagName("warehousesAvailabilities")[0];
			} else {
				if (responseXML.getElementsByTagName("warehousesAvailabilities")[0])
					this.warehousesAvailabilities = responseXML.getElementsByTagName("warehousesAvailabilities")[0];
			}
			
			if (offlinePnAxml) {
				this.availability = offlinePnAxml.getElementsByTagName('stock')[0].firstChild.data;
			} else {
				this.availability = responseXML.getElementsByTagName('availability')[0].firstChild.data;
				if (!this.isOnlineData) {
					if (responseXML.getElementsByTagName('offlineAvail')[0])
						this.availability = responseXML.getElementsByTagName('offlineAvail')[0].firstChild.data;
					else 
						this.availability = this.offlineDefaults.availability;
				} else if (this.availability == this.defaults.unknownFromIMG || !this.hasWHAvail()) 
					this.availability = this.defaults.unknownAvailability;
			}
			
			if (this.availability == this.defaults.unknownAvailability || this.availability == this.offlineDefaults.availability || !this.hasWHAvail()) 
				this.availability = '<span style="color:#000">'+ this.availability + '</span>';
			
			this.sku = responseXML.getElementsByTagName('sku')[0].firstChild.data;

			if (responseXML.getElementsByTagName('listPrice')[0]) {
				this.listPrice = responseXML.getElementsByTagName('listPrice')[0].firstChild.data;
				if (!this.isOnlineData)
					this.listPrice = this.offlineDefaults.listPrice;
				else if (this.listPrice == this.defaults.unknownFromIMG) 
					this.listPrice = this.defaults.unknownListPrice;
			}
			
			if(responseXML.getElementsByTagName('isSourced')[0]) {
				this.sourced = true;
			}
			
			if(responseXML.getElementsByTagName('isDirectShipped')[0]) {
				this.directShipped = true;
			}
			
			if(responseXML.getElementsByTagName('isEndOfLife')[0]) {
				this.endOfLife = true;
			}
			
			if(responseXML.getElementsByTagName('isDiscontinued')[0]) {
				this.discontinued = true;
			}
			
			if(responseXML.getElementsByTagName('addToCartDisplay')[0]){
				this.addToCartDisplay=responseXML.getElementsByTagName('addToCartDisplay')[0].firstChild.data == 'true' ? true : false;
			}

			if (offlinePnAStatusTag && !AppUtils.isEmpty(offlinePnAStatusTag.getAttribute('type')) && offlinePnAStatusTag.getAttribute('type').toLowerCase() == 'error' 
						&& offlinePnAStatusTag.firstChild && AppUtils.trim(offlinePnAStatusTag.firstChild.data) == 'NOT_AUTHORIZED')
				this.isAuthorizedPurchase = false;
			else if (offlinePnAxml)
				this.isAuthorizedPurchase = true;
			else if (responseXML.getElementsByTagName('isAuthorizedPurchase')[0])
				this.isAuthorizedPurchase = (responseXML.getElementsByTagName('isAuthorizedPurchase')[0].firstChild.data=='true') ? true : false;
			else
				this.isAuthorizedPurchase = false;

			if(responseXML.getElementsByTagName('hasPromotions')[0]) {
				this.promotion = true;
			}

			if(responseXML.getElementsByTagName('replacementSku')[0]) {
				this.replacementSku = responseXML.getElementsByTagName('replacementSku')[0];
			}
			
			if(responseXML.getElementsByTagName('quantityInCart')[0]){
				this.quantityInCart = responseXML.getElementsByTagName('quantityInCart')[0].firstChild.data;
			} else this.quantityInCart = -1;
				
			this.showPnAResponse();
		}
	},
	
	showPnAResponse: function() {
		this.hasResponse = true;
		var myTargetDiv = this.targetDiv.splice(0, this.targetDiv.length);
		for (x = 0; x < myTargetDiv.length; x++) {
			var e = $(myTargetDiv[x]);
			if (AppUtils.isEmptyObject(e)) continue;
			if (e.getAttribute('pnaType') == 'price') {
				e.innerHTML = this.price;
				if (!AppUtils.isEmptyObject(e.getAttribute('postfix'))) {
					e.innerHTML = e.innerHTML + ' ' + e.getAttribute('postfix');
				}
				if (!AppUtils.isEmptyObject(e.getAttribute('prefix'))) {
					e.innerHTML = e.getAttribute('prefix')+ ' ' + e.innerHTML;
				}
				if (this.isBasePrice) {
					var labelElem = $('your_price_label_' + this.sku);
					if (labelElem) labelElem.update("Base Price");
					else {
						labelElem = $('your_price_label_common');
						if (labelElem) labelElem.update("Base Price");
					}
				}
			} else if (e.getAttribute('pnaType') == 'avail') {
				if (e.getAttribute("d_e_class") == 'true' && (this.isDiscontinued() || this.isEndOfLife()) && !this.isAddToCartDisplayable()) Element.show(e);
				else if (e.getAttribute('directShip') == 'true' && this.isDirectShipped() && !((this.isDiscontinued() || this.isEndOfLife()))) Element.show(e);
				else if (this.isDirectShipped() || ((this.isDiscontinued() || this.isEndOfLife()) && !this.isAddToCartDisplayable())) Element.hide(e);
				else e.innerHTML = this.availability;
			} else if (e.getAttribute('pnaType') == 'listPrice'){
	           e.innerHTML = (this.hasListPrice())?this.listPrice:this.defaults.listPriceNotAvailable;
			} else if ((e.getAttribute('pnaType') == 'addToCart') && this.isAddToCartDisplayable() && this.isAuthorized()) {
				var d_e_class = e.getAttribute("d_e_class");
				var attachListeners = false;
				if (!AppUtils.isEmptyObject(d_e_class) && d_e_class == 'true' && (this.isDiscontinued() || this.isEndOfLife())) {
					Element.show(e);
					attachListeners = true;
				} else if (AppUtils.isEmptyObject(d_e_class) && !(this.isDirectShipped() || this.isDiscontinued() || this.isEndOfLife())) {
					Element.show(e);
					attachListeners = true;
				}
					
				if (attachListeners) {
					/* read: http://jehiah.cz/archive/javascript-isdefined-function */
					if (window.resellerCart) {
						/* we register the listener to SimpleCart so when it is done loading latest cart info it will update the qty if this sku is added/removed/updated from outside IMSearch
						 * IMS-269
						 */
						 this.addQtyInCartListener(resellerCart);
					} else {
						console.log('resellerCart not defined yet; adding listener with timeout');
						setTimeout((function(){
							if (window.resellerCart) this.addQtyInCartListener(resellerCart);
							else console.error('resellerCart not defined after timeout');
						}).bind(this), 500);
					}
				}
			} else if ((e.getAttribute('pnaType') == 'addToCartUnauthorized') && !this.isAuthorized()) {
				Element.show(e);
			} else if ((e.getAttribute('pnaType') == 'callToOrder') && this.isDirectShipped() && this.isAuthorized()) {
				Element.show(e);
			} else if (e.getAttribute('pnaType') == 'isSourced' && this.isSourced()){
				Element.show(e);
			} else if (e.getAttribute('pnaType') == 'hasPromotions' && this.hasPromotions() ){
				Element.show(e);
			} else if (e.getAttribute('pnaType') == 'replacementSku' && this.hasReplacementSku()){
				var sku = this.replacementSku.getElementsByTagName('sku')[0].firstChild.data;
				var linkReplacementSku = this.replacementSku.getElementsByTagName('link')[0].firstChild.data == 'true';
				
				if (linkReplacementSku)
					e.innerHTML = "<b>Replacement SKU:<b> <a href='displayProduct?sku="+sku+"&catalog="+this.catalog+"'>" + sku + "</a>"
				else
					e.innerHTML = "<b>Replacement SKU:<b> " + sku;
					
				Element.show(e);
			} else if (e.getAttribute('pnaType') == 'isDirectShipped' && this.isDirectShipped()){
				Element.show(e);
			} else if (e.getAttribute('pnaType') == 'isDiscontinued' && this.isDiscontinued()){
				Element.show(e);
			} else if (e.getAttribute('pnaType') == 'isEndOfLife' && this.isEndOfLife()){
				Element.show(e);
			} else if (e.getAttribute('pnaType') == 'whAvail') {
				if (this.hasWHAvail()) {
					if (this.price != this.defaults.unknownPrice && this.price != this.offlineDefaults.price) {
						var whaLength = this.warehousesAvailabilities.getElementsByTagName('warehouse').length;
						var whaHTML = '<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" align=\"center\">' +
		                               '<tr>' +
		                                   '<th width=\"10px;\">' +
		                                       '&nbsp;' +
		                                   '</th><th>' +
		                                       '<fmt:message key="warehouse.header.warehouse"/>' +
		                                   '</th><th style=\"text-align: center; \">' +
		                                       '<fmt:message key="warehouse.header.stock"/>' +
		                                   '</th><th style=\"text-align: center; \">' +
		                                       '<fmt:message key="warehouse.header.on_order"/>' +
		                                   '</th><th style=\"text-align: center; \">' +
		                                       '<fmt:message key="warehouse.header.eta"/>' +
		                                   '</th></tr>';
						var i = 0;               
						var showEtaMessage = false;
						while(i < whaLength){
							//TODO: this should come from resource bundle
							var onOrder = this.warehousesAvailabilities.getElementsByTagName('warehouse').item(i).getElementsByTagName('onOrder')[0].firstChild.data;
							var eta = this.warehousesAvailabilities.getElementsByTagName('warehouse').item(i).getElementsByTagName('eta')[0].firstChild ? 
										this.warehousesAvailabilities.getElementsByTagName('warehouse').item(i).getElementsByTagName('eta')[0].firstChild.data : 'Unknown';
							if (onOrder == '0') {
								onOrder = 'Pending';
								eta = 'No ETA';
							} else {
								var etaDate = new Date()
								etaDate.setTime(Date.parse(eta));
								// if adding two days shifts the date to next month or next year ... the Date object handles it automatically
								etaDate.setDate(etaDate.getDate() + 2);
								// month is from 0-11 so we have to add 1 before displaying
								if (!isNaN(etaDate.getMonth())) {
			                       var month = etaDate.getMonth() + 1;
			                       var date = etaDate.getDate();
			                       if (month < 10 )
			                           month = '0' + month;
			                       if (date < 10)
			                           date = '0' + date;
			                       eta = month + '/' + date + '/' + etaDate.getFullYear();
			                       eta = eta + " <span class='cC00'>*</span>";
			                       showEtaMessage = true;
			                   }
							}
							// if all the 4 values are Unknown, then write "Call" in this row
							if (this.defaults.unknownFromIMG==this.warehousesAvailabilities.getElementsByTagName('warehouse').item(i).getElementsByTagName('name')[0].firstChild.data 
									&& this.defaults.unknownFromIMG==this.warehousesAvailabilities.getElementsByTagName('warehouse').item(i).getElementsByTagName('onHand')[0].firstChild.data 
										&& this.defaults.unknownFromIMG==onOrder && this.defaults.unknownFromIMG==eta) {
								whaHTML = whaHTML +
				                   "<tr><td colspan=\"5\">"+ this.defaults.unknownAvailability +"</td></tr>";
							} else {
								whaHTML = whaHTML +
				                   "<tr><td>&nbsp;</td>" +
				                   "<td>" + this.warehousesAvailabilities.getElementsByTagName('warehouse').item(i).getElementsByTagName('name')[0].firstChild.data + "</td>" +
				                   "<td style=\"text-align: center; \">" + this.warehousesAvailabilities.getElementsByTagName('warehouse').item(i).getElementsByTagName('onHand')[0].firstChild.data + "</td>" +
				                   "<td style=\"text-align: center; \">" + onOrder + "</td>" +
				                   "<td style=\"text-align: center; \">" + eta + "</td></tr>";
							}
			               i = i + 1;
			           }
			           if (showEtaMessage) {
			               // TODO: this should come from resource bundle
			               whaHTML = whaHTML + "<tr><td colspan='5' class='i pLR5'><span class='cC00'>*</span>This date represents the best estimated date provided by the vendor. Ingram Micro will make every effort to provide updates as they become available</td></tr>"
			           }
			           whaHTML = whaHTML + "</table>";
		           	   e.innerHTML = whaHTML;
	           		   if (e.getAttribute('isWarehouseToolTip') == 'true') {
	           		   		new Tooltip('warehouseLabel'+this.skuNumber, 'warehouseLabel'+this.skuNumber+'_tooltip');
			           }
				           
					} else {
						e.innerHTML = "<div class=\"warehouse_value\" style=\"padding: 5px 20px;\">"+ this.defaults.unknownAvailability +"</div>";
					}
					
					// tooltip
					if (e.getAttribute('isTooltip') == 'true' && this.availability != this.defaults.unknownAvailability && this.price != this.offlineDefaults.price && this.hasWHAvail()) {
		           		new Tooltip(e.getAttribute('id').replace("tooltip_","avail"),e.getAttribute('id'));
		            }
		       }
		       else {
					e.innerHTML = '';
		       }
			}
		}
	},
	
	addQtyInCartListener: function(resellerCartArg) {
		resellerCartArg.updateQtyInCart({sku: this.skuNumber, notify: (function(qty){
		 	$('qtyInCart'+this.skuNumber+this.catalog).innerHTML='(' + qty + ')';
		 	$('img'+this.skuNumber+this.catalog).src='<app:imgURL value="elmo/cartarrow.gif"/>';
		 	$('img'+this.skuNumber+this.catalog).title='Add More to Cart';
		 	// for d_e class
		 	$('d_e_qtyInCart'+this.skuNumber+this.catalog).innerHTML='(' + qty + ')';
		 	$('d_e_img'+this.skuNumber+this.catalog).src='<app:imgURL value="elmo/cartarrow.gif"/>';
		 	$('d_e_img'+this.skuNumber+this.catalog).title='Add More to Cart';
		}).bind(this)});
	},
	
	addTargetDiv: function(newTarget) {
		this.targetDiv.push(newTarget);
	},
	
	// FIXME: this function need to be written !
	showPnAError: function () {
		console.error("Error finding pna: " + this.errorMessage)
	},
	
	isAuthorized: function () {
		return this.hasAuthorization() && this.isAuthorizedPurchase;
	},
	hasPrice: function () {
		return this.hasOwnProperty('price');
	},
	hasQuantity: function () {
		return this.hasOwnProperty('quantity');
	},
	hasWHAvail: function () {
		return this.hasOwnProperty('warehousesAvailabilities');
	},
	hasAuthorization: function () {
		return this.hasOwnProperty('isAuthorizedPurchase');
	},
	hasListPrice: function () {
		return this.hasOwnProperty('listPrice');
	},
	isSourced: function () {
		return this.hasOwnProperty('sourced');
	},
	isDirectShipped:function (){
		return this.hasOwnProperty('directShipped');
	},
	isDiscontinued:function (){
		return this.hasOwnProperty('discontinued');
	},
	isEndOfLife:function() {
		return this.hasOwnProperty('endOfLife');
	},
	isAddToCartDisplayable:function () {
		return this.addToCartDisplay;
	},
	hasPromotions: function () {
		return this.hasOwnProperty('promotion');
	},
	hasReplacementSku: function () {
		return this.hasOwnProperty('replacementSku');
	},
	hasKnownAndNonZeroAvail: function () {
		return this.availability != this.defaults.unknownAvailability && this.availability != 0;
	},
	hasKnownAndZeroAvail: function () {
		return this.availability != this.defaults.unknownAvailability && this.availability <= 0;
	},
	
	showOfflinePnAIndicator: function() {
		if ($(this.offlineDefaults.offlinePnAIndicator))
			Element.show(this.offlineDefaults.offlinePnAIndicator);
	},
	
	hideGovEdSSEULinks: function() {
		if ($(this.checkGovEdLink + this.skuNumber))
			Element.hide(this.checkGovEdLink + this.skuNumber);
		if ($(this.checkSSEULink))
			Element.hide(this.checkSSEULink);
	}
}



