/* jslint verified 2008.10.22 */
/*jslint browser: true, onevar: false, undef: true, white: false, eqeqeq: true */
/*global $, $$, Constants, noop, statusBar, Ajax, MbitLinks, WindowUtilities, findPosX, findPosY, isset, mmmChangeBold */
var debug = false,
	Cart = function () {
	var self = {}, _total, _showMenu, _moveMenu, _cartSel, _cartMove, _CMDiv, _timeOut = -1, _gS,
		_data = [], // array of [ cart IDs => [line item ID, line item name, [contrib IDs, contrib names], tip, price] ]
		_names = {length: 0}, // keyed array of [ cart IDs => [ name ] ]
		_curCart = null, // current cart ID
		_tipFlds = [],
		_URL = Constants.ajax()+'cart', _mode = 'get', _ajax = null,
		_checkP = Constants.images()+"mmmail/msg_close_p.jpg", _checkU = Constants.images()+"mmmail/msg_close_u.jpg",
		_itmPfx = "cart_itm_", _delPfx = "cart_del_", _chkPfx = "cart_chk_",
		_tipPfx = "cart_tip_", _prcPfx = "cart_amt_", _subPfx = "cart_sub_",
		_pdadded = {},
		_loadMsg1 = 'Loading...<br /><img src="'+Constants.ajaxImages()+'progress2.gif" alt="Loading..." />',
		_loadMsg2 = 'Loading... <img src="'+Constants.ajaxImages()+'progress2.gif" alt="Loading..." />',
		_itemsTable;

	function noneTR(table, msg) {
		var tr = document.create("tr", "cartNone"),
			itm = tr.create("td", null, "item", "&nbsp;"),
			msgT = msg ? msg : "No items in cart.",
			msgtd = tr.create("td");
		msgtd.setAttribute("colspan", 5);
		if (!!msg) { msgtd = msgtd.create("span", null, "error"); }
		msgtd.createText(msgT);
		table.empty().appendChild(tr);
	}
	function tblHdrs(table) {
		var tr = table.insertRow(-1),
			frag = $$(document.createDocumentFragment());
		frag.create("th").classify("del").create("div");
		frag.create("th").classify("item").create("div");
		frag.create("th").classify("name").create("div").createText("audio name");
		frag.create("th").classify("contrib").create("div").update("audio contributor(s)");
		frag.create("th").classify("tip").create("div").update("tip contributor(s)");
		frag.create("th").classify("price").create("div").update("audio price");
		frag.create("th").classify("sub").create("div").update("subtotal");
		tr.id = "hdrs";
		tr = $('hdrs');
		tr.appendChild(frag);
	}
	
	self.initialize = function () {
		_total = $("cartTotalAmt");
		_showMenu = $("cartMenuBox");
		_moveMenu = $("cartMoveMenu");
		_cartSel = $("cartSel");
		_cartMove = $("cartMove");
		_itemsTable = $('cartItemsTbl');
		if (_cartSel && _cartMove) {
			_cartSel.setEvent('change', function () { self.showCart(_cartSel.scan(), true, false, _cartSel); });
			_cartMove.setEvent('change', function () { self.moveSel(_cartSel.scan(), false, false, _cartMove); });
			$("cartRemSel").setClick(self.removeSel.bind(self));
			$("cartSelAllTop").setClick(self.selAll.bind(self));
			$("cartSelAllBtm").setClick(self.selAll.bind(self));
			$("cartSelNoneTop").setClick(self.selNone.bind(self));
			$("cartSelNoneBtm").setClick(self.selNone.bind(self));
			$("cartEmpty").setClick(function (e) { cancelBubble(e); self.doConfirm('ec'); });
			$("cart_btn_save").setClick(function () { history.go(-1); });
			$("cart_btn_buyP").show();
			$("cart_btn_buyD").hide();
		}
		// add child of "content"
		_CMDiv = $('content').create("div", 'cartModal');

		self.addCSS(Constants.css() + 'cartPopup.20081023.css');
	};

	self.storeData = function (data, names) {
		_data = data; _names = names; _names.length = 0;
		for (var key in _names) { if (_names.hasOwnProperty(key)) { ++_names.length; } }
	};

	self.calcLine = function (tipID) {
		var bitID = tipID.substr(_tipPfx.length),
			tipFld = $(tipID), tip = tipFld.value;
		if (isNaN(parseFloat(tip)) || parseFloat(tip) < 0) { tip = 0; }
		tip = tip > 1e4 - 1 ? 1e4 - 1 : tip;
		var sum = parseFloat(tip) + parseFloat($(_prcPfx+bitID).scan());
		$(_subPfx+bitID).update(parseFloat(sum).toFixed(2));
		tipFld.value = parseFloat(tip).toFixed(2);
		_data[_curCart][$(_itmPfx+bitID).rowIndex-1][3] = tip; // store in JS array
		var func = function (request) {
			var resp = JSON.parse(request.responseText);
			if (resp.errors) { noneTR(_itemsTable, resp.errors); }
		};
	 	self.doAjax(null,'t',bitID,'&t='+tip, func); // store in DB with AJAX
		self.calcTotal();
	};

	self.calcTotal = function () {
		var i, c = _data[_curCart], sum = 0;
		for (i=0; c&&i<c.length; ++i) { sum += parseFloat($(_subPfx+c[i][0]).scan()); }
		_total.update('$' + parseFloat(sum).toFixed(2));
	};

	self.getSel = function () {
		var bids = [], bid, i,
			c = _data[_curCart];
		for (i=0; c && i<c.length; ++i) {
			bid = c[i][0];
			if ($(_chkPfx+bid).isChecked()) { bids.push(bid); }
		}
		return bids.join(',');
	};

	self.setMenus = function (cur) {
		var oA = '', selected = ' selected="selected"', sel, key;
		for (key in _names) {
			if (_names.hasOwnProperty(key) && key !== 'length' && typeof(_names[key])!=="function") {
				sel = key === cur ? selected : '';
				oA += '<option value="'+key+'"'+sel+'>'+_names[key]+'</option>';
			}
		} 
		sel = cur === null ? selected : '';
		_cartMove.update(oA);
		_cartSel.update(oA+'<option value="" id="viewSep"'+sel+'>-</option><option value="0">new cart...</option>');
		mmmChangeBold(_cartMove);
		mmmChangeBold(_cartSel);
	};

	self.showCart = function ( cartID, dohtml, eventsonly, menu ) {
		if (cartID !== "") {
			if (cartID !== null && +cartID === 0) {
				self.newCartFromMenu(menu);
			} else {
				var setMenu = _curCart !== cartID;
				_curCart = cartID !== null ? cartID : _curCart;
				if (dohtml) {
					if (_data[_curCart].length > 0) {
						tblHdrs(_itemsTable.empty());
						self.getItemsHTML(eventsonly, _itemsTable);
						self.attachTipEvents();
					} else { noneTR(_itemsTable); }
					$("cartName").update(_names[_curCart]);
					self.calcTotal();
					if (setMenu) { self.setMenus(cartID); }
					$("btn_chkmm_cart").update(cartID);
					$("btn_chkpp_cart").update(cartID);
				} else if (eventsonly) {
					self.getItemsHTML(eventsonly);
					self.attachTipEvents();
				}
// error in IE? seems to happen on the $() maybe?
			}
		}
	};

	self.getItemsHTML = function (eventsonly, table) {
		var c = _data[_curCart];
		_tipFlds = [];
		for (var i=0; c && i<c.length; ++i) {
			var bid = c[i][0];
			if (!eventsonly) {
				var name = c[i][1], ancs = c[i][2], tip = parseFloat(c[i][3]).toFixed(2), price = parseFloat(c[i][4]).toFixed(2), ancstr = [];
				for (var j=0; j<ancs.length; ++j) { ancstr.push('<a href="'+Constants.profileLink(ancs[j][0])+'">'+ancs[j][1]+'</a>'); }
				ancstr = ancstr.join(', ');
				var ext = (ancstr.replace(/(<([^>]+)>)/ig,"").length > 12) ? ' etc' : '',
					extN = (name.length > 23) ? ' etc' : '';
				var tr = table.insertRow(-1),
					frag = $$(document.createDocumentFragment());
				tr.id = _itmPfx + bid;
				tr = $(tr.id);
				if (i+1 === c.length) { tr.setClassName("last"); }
				tr.setAttribute("name", i);
				var del = frag.create("td", null, "del").create("div"),
					img = del.create("a", "cart_del_"+bid, "hand").create("img");
				frag.create("td", null, "item").create("div").create("input:checkbox", _chkPfx+bid);
				frag.create("td", null, "name"+extN).create("div").create("a").update(name).href = Constants.profileLink(bid);
				frag.create("td", null, "contrib"+ext).create("div").update(ancstr);
				var tipTD = frag.create("td", null, "tip"),
					priceTD = frag.create("td", null, "price"),
					subTD = frag.create("td", null, "sub");
				tipTD.create("div").create("input:text", _tipPfx+bid, "cart_us", tip);
				priceTD.create("div", _prcPfx + bid, "cart_us", price);
				subTD.create("div", _subPfx + bid, "cart_us", (parseFloat(price) + parseFloat(tip)).toFixed(2));
				tipTD.create("div", null, "clear");
				priceTD.create("div", null, "clear");
				subTD.create("div", null, "clear");
				img.setAttribute("src", Constants.images()+"cart/cart_del.jpg");
				tr.appendChild(frag);
			}
			_tipFlds.push(bid);
		}
	};

	self.selAll = function (e) {
		cancelBubble(e);
		var c = _data[_curCart];
		for (var i=0; c && i<c.length; ++i) { $(_chkPfx+c[i][0]).check(); }
	};

	self.selNone = function (e) {
		cancelBubble(e);
		_gS = self.getSel().split(',');
		for (var i=0; i<_gS.length; ++i) { if (_gS[i] !== "") { $(_chkPfx+_gS[i]).uncheck(); } }
	};

	self.removeOne = function (pID, popup, e) {
		cancelBubble(e);
		var bitID = popup ? pID : pID.substr(_itmPfx.length), c = _data[_curCart], oldI, trID = _itmPfx+bitID;
		if (!popup) { oldI = $(trID).rowIndex - 1; }
		else { oldI = 0; if (debug) { console.log("fix this!"); } }
		var bitN = c[oldI][1];
		self.doConfirm('ro', bitID, bitN, oldI, popup);
	};

	self.doRmvOne = function (bitID, offCart) {
		var trID = _itmPfx+bitID, tr = $(trID), c = _data[_curCart], oldI = tr.rowIndex-1, name = c[oldI][1];
		if (tr.hasClassName('last') && c.length>1) { $(_itmPfx+c[oldI-1][0]).addClassName('last'); }
		c.splice(oldI, 1);
		if (!offCart) {
			if (c&&c.length > 0) { tr.remove(); }
			else { self.showCart(null, true); }
			statusBar.talk('<a href="'+Constants.profileLink(bitID)+'">'+name+'</a> has been removed from cart "'+_names[_curCart]+'".');
			var view = document.create("a").textify("view cart").attrib('href', "/cart?cart="+_curCart);
			statusBar.map([view]);
		}
		self.hideConfirm();
		self.calcTotal();
	};

	self.removeSel = function (e) {
		cancelBubble(e);
		_gS = self.getSel();
		var tg = _gS==="" ? [] : _gS.split(',');
		if (tg.length > 0) { self.doConfirm('rx', tg); }
	};

	self.doRmvSel = function (tg) {
		var trID, view = document.create("a").textify("view cart").attrib('href', Constants.relRoot()+"cart?cart="+_curCart);
		for (var i=0; i<tg.length; ++i) {
			trID = _itmPfx + tg[i];
			_data[_curCart].splice($(trID).rowIndex-1, 1);
			if (_data[_curCart].length > 0) { $(trID).parentNode.removeChild($(trID)); }
			else { self.showCart(null, true); }
		}
		statusBar.talk('The selected audio has been removed from cart "'+_names[_curCart]+'".');
		statusBar.map([view]);
		self.hideConfirm();
		self.calcTotal();
	};

	self.doEmpty = function () {
		var key, optsArr = [], oldC = _curCart, nN = [], msg = 'Cart "'+_names[_curCart]+'" has been emptied and deleted.';
		_data[_curCart] = [];
		_names[_curCart] = null;
		_curCart = null;
		nN.length = 0;
		for (key in _names) {
			if (oldC !== key && key !== 'length') {
				if (!_curCart) { _curCart = key; }
				var selected = key === _curCart ? ' selected="selected"' : '';
				optsArr.push('<option value="'+key+'"'+selected+'>'+_names[key]+'</option>');
				nN[key] = _names[key];
				++nN.length;
			}
		}
		var oa = optsArr.join("\n");
		_names = nN;
		_cartSel.update(oa+'<option value="" id="viewSep">-</option><option value="0">new cart...</option>');
		_cartMove.update(oa);
		mmmChangeBold(_cartMove);
		mmmChangeBold(_cartSel);
		if (_curCart) { self.showCart(null, true); }
		else {
			$("cartName").empty();
			self.setMenus();
			noneTR(_itemsTable);
		}
		self.hideConfirm();
		statusBar.talk(msg);
	};

	self.moveSel = function (destCart, popup, id) {
		if (destCart !== "") {
			_gS = popup ? [id] : self.getSel();
			if (popup) {
				var m = $("cartModal_moveMenu");
				destCart = m.options[m.selectedIndex].value;
			}
			var tg = _gS==="" ? [] : _gS.split(',');
			if (tg.length > 0) {
				var func = function (request) {
					var resp = JSON.parse(request.responseText);
					if (resp.errors) { noneTR(_itemsTable, resp.errors); }
				};
				self.doAjax(null,'m', _gS, "&d="+destCart,func,true);
				var cA, dA, oldI, i;
				for (i=0; i<tg.length; ++i) {
					cA = _data[_curCart];
					dA = _data[destCart];
					var tr;
					if (popup) { oldI = 0; if (debug) {console.log("fix this!");} }
					else {
						tr = $(_itmPfx+tg[i]);
						oldI = tr.rowIndex-1;
					}
if (debug) { console.log("cA.length: "+cA.length+"   dA.length:"+dA.length+"     oldI:"+oldI);  console.log(dA); }
					dA.splice(dA.length, 0, cA[oldI]);
					cA.splice(oldI, 1);
					if (!popup) { tr.remove(); }
				}
if (debug) { console.log("cA.length: "+cA.length+"   dA.length:"+dA.length+"     oldI:"+oldI); }
				self.showCart(destCart, true);
				var view = document.create("a").textify("view cart").attrib('href', Constants.relRoot() + "cart?cart="+_curCart);
				statusBar.talk('<a href="'+Constants.profileLink(id)+'">'+dA[oldI][1]+'</a> has been moved to cart "'+_names[_curCart]+'".');
				statusBar.map([view]);
			}
		}
	};

	self.doAjax = function (cart, func, items, extra, success, synch) {
		if (!cart) { cart = _curCart; }
		var params = "c="+cart+"&f="+func+"&i="+items+extra;
		_ajax = new Ajax( _URL, { method: _mode, parameters: params, onFailure: self.reportError, onSuccess: function (request) { success(request); } });
		if (!!synch) { _ajax.updateOptions({asynchronous: false}); }
		_ajax.send();
	};

	self.reportError = function (request) {
		statusBar.error("Error: "+request);
	};

	function attachTipEvent(bid) {
		$(_tipPfx+bid).setEvent("change", self.calcLine.bind(self, _tipPfx+bid));
		$(_delPfx+bid).setClick(self.removeOne.bind(self, _delPfx+bid));
	}
	self.attachTipEvents = function () {
		for (var i=0; i<_tipFlds.length; ++i) { attachTipEvent(_tipFlds[i]); }
	};

	self.doConfirm = function (type, bits, bitN, oldI, offCart) {
		// ro, rx, ec
		var bid, imgsrc, msg, popup, yL, func, af, cn = _names[_curCart], ext='';
		if (type === 'ro') {
			bid = bits; af = 'r'; msg = 'Are you sure you want to remove '+bitN+' from your cart "'+cn+'"?';
			yL = document.create("a").classify("hand").textify("remove audio");
			func = function () { self.doRmvOne(bid, offCart); };
			popup = true;
		} else if (type === 'rx') {
			bid = bits; af = 'r'; msg = 'Are you sure you want to remove '+bits.length+' items from your cart "'+cn+'"?';
			yL = document.create("a").classify("hand").textify("remove audio");
			func = function () { self.doRmvSel(bits); };
			popup = true;
		} else if (type === 'ec') {
			af = 'e'; ext = '&e=yesyesyes';
			yL = document.create("a").classify("hand").textify("delete cart");
			msg = 'Are you sure you want to empty and erase your shopping cart "'+cn+'"?';
			func = function () { self.doEmpty(); };
			popup = true;
		} else { popup = false; }
		if (popup) {
			self.makePopup(bid, imgsrc, msg);
			var cmLt = $('cartModal_left'), cmRt = $('cartModal_right');
			cmLt.empty().create("a").classify("hand").textify("cancel");
			cmRt.empty().appendChild(yL);
			cmLt.setClick(self.hideConfirm.bind(self));
			cmRt.setClick(function (e) { $("cartModal_msg").update(_loadMsg1); self.doAjax(null, af, bid,ext,func); });
			_CMDiv.popup(self.hideConfirm.bind(self));
		}
		return false;
	};

	self.addToCart = function (el, isnew, e) {
		cancelBubble(e);
		var name, id, ids, cid;
		ids = el.nextSibling.scan().split("|");
		id = ids[0];
		name = ids[1];
		cid = ids[2];
		self.makePopup(id);
		self.doAjax(cid,'a',id,'',function (request) { self.addedToCart(id, name, JSON.parse(request.responseText), isnew); });
		//_CMDiv.popup(self.hideConfirm.bind(self));	
		// show loading indicator
	};

	self.addedToCart = function ( id, name, response, isnew ) {
		if (debug) { console.log(response); }
		//if (response[0] && $('cm_close')) {
		if (response[0]) {
/*
			var cartid = response[1], cartname = _names[cartid], msg = $('cartModal_msg'), newstr = isnew ? "new " : '';
			msg.update('<span id="cartModal_un">'+name+'</span> has been added to the '+newstr+'cart "'+cartname+'".');
			_data[cartid] = response[2];
			var h = "hand", c = "click", pID = "cartModal",
				viewL = $('cartModal_left').create("a", pID+"_leftLink", h, "view cart"),
				hideL = $('cartModal_right').create("a", pID+"_rightLink", h, "continue MixMatching");
			viewL.href = "/cart?cart="+cartid;
			viewL.setAttribute("href", "/cart?cart="+cartid);
			var cmRt = $(hideL.id), cmLt = $(viewL.id);
			cmRt.setEvent(c, function (e) { self.hideConfirm(e); });
			//cmLt.setEvent(c, (function (e) { self.removeOne(id, true, e); }).bind(self));
			//cmLt.setEvent(c, (function (e) { self.moveSel(dest, true, id); }).bind(self));
*/
			var cartid = response[1],
				cartname = _names[cartid], newstr = isnew ? "new " : '',
				view = document.create("a").
						classify('sBvL').
						textify("view cart").
						attrib('href', Constants.relRoot() + "cart?cart="+cartid),
				undo = document.create("a").
						classify('sBuL').
						textify("view cart");
			_data[cartid] = response[2];
			statusBar.talk('<a id="cartModal_un" href="'+Constants.profileLink(id)+'">'+name+'</a> has been added to the '+newstr+'cart "'+cartname+'".');
			statusBar.show();
			statusBar.map([view]);
		} else if (!response[0]) { statusBar.error("AJAX PHP error! In Cart.AddedToCart"); }
	};

	self.makePopup = function (bid, imgsrc, msg) {
		if (!imgsrc) { imgsrc = Constants.profilePic(bid,'small'); }
		if (!msg) { msg = _loadMsg1; }
		var frag = $$(document.createDocumentFragment()),
			cmt = frag.create("div", "cartModal_top"),
			cmm = frag.create("div", "cartModal_mid"),
				cmpid = cmm.create("div", "cartModal_img"),
					cmpi = cmpid.create("img"),
			cmb = frag.create("div", "cartModal_btm"),
			cmid = frag.create("div", "cartModal_id", "hide", bid),
			cmidiv = frag.create("div").classify("hide"),
				cmimg = cmidiv.create("img");
		frag.create("div").classify("clear");
		cmt.create("div", "cm_close", null, "&nbsp;");
		cmm.create("div", "cartModal_msg", null, msg);
		cmm.create("div").classify("clear");
		cmm.create("div", "cartModal_left");
		cmm.create("div", "cartModal_right");
		cmm.create("div").classify("clear");
		cmimg.src = _checkP;
		cmimg.setAttribute("src", _checkP);
		cmpi.src = imgsrc;
		cmpi.setAttribute("src", imgsrc);
		_CMDiv.empty().appendChild(frag);

		var cmC = $('cm_close');
		cmC.setClick(self.hideConfirm.bind(self));
		cmC.setEvent('mouseover',  function () { cmC.style.cursor = "pointer"; cmC.style.backgroundImage = "url("+_checkP+")"; });
		cmC.setEvent('mouseout',  function () { cmC.style.backgroundImage = "url("+_checkU+")"; });
	};

	self.hideConfirm = function (e) {
		cancelBubble(e);
		_CMDiv.hide().empty();
		WindowUtilities.enableScreen();
	};

	self.addCSS = function (ss) {
		var css = ss ? ss : Constants.css() + 'cartPopdown.20081023.css';
		if (!_pdadded[ss]) {
			if (document.createStyleSheet) { document.createStyleSheet(css); }
			else {
				var styles = css, /* "@import url(css);"; */
					newSS = document.create('link');
				newSS.rel = 'stylesheet';
				newSS.type = 'text/css';
				newSS.href = (styles);
				document.getElementsByTagName("head")[0].appendChild(newSS);
			}
			_pdadded[ss] = true;
		}
	};

	self.clrTimeout = function () {
		if (_timeOut >= 0) { clearTimeout(_timeOut); }
		_timeOut = -1;
	};

	function setAddToCart(el) {
		el.setClick(
			function (e) {
				cancelBubble(e);
				self.addToCart(this, false, e);
				self.removePD(e, true);
			}
		);
	}

	self.showPopdown = function (el, elNS, e) {
		var pdE = $("cart_popDown");
		if (!pdE) {
			self.addCSS();
			var h = "hand", l = "link", ids = elNS.split("|"), id = ids[0], un = ids[1],
				pd = document.create("div", 'cart_popDown'),
					pdI = pd.create("div", pd.id+'_i'),
						img = pdI.create("img", pd.id+'_pic', h),
						pdIcap = pdI.create("span",pd.id+'_iC', h, "add to..."),
					pdM = pd.create("div", pd.id+'_menu'),
						sep1 = pdM.create("div", pdM.id+'_sep1', 'sep'),
						sep2 = document.create("div", pdM.id+'_sep2', 'sep'),
					pdMn = document.create("div", pdM.id+'_new', l),
						pdMnL = pdMn.create("a", pdMn.id+'_'+l, h, "new cart..."),
				key, lnkD;
			pd.style.top = +findPosY(el.childNodes[0])-5 + "px";
			pd.style.left = +findPosX(el.childNodes[0])-5 + "px";
			img.src = el.childNodes[0].src;
			if (+_names.length > 0) {
				for (key in _names) { if (_names.hasOwnProperty(key) && key !== 'length') {
					lnkD = pdM.create("div", pdM.id+'_'+key, l);
					lnkD.create("a", pd.id+'_'+l+'_'+key, h, _names[key]);
					lnkD.create("span", pd.id+'_sssh_'+key, null, id+'|'+un+'|'+key).hide();
					lnkD = null;
				}	}
			} else { pdM.create("div", pdM.id+'_none', "arrow", "No carts."); }
			pdM.appendChildren([sep2,pdMn]);
			document.body.appendChild(pd);
			$(pd.id).addEvent("mouseout", function (e) { self.removePD(e); } );
			$(img.id).setClick( function (e) { self.removePD(e, true); } );
			if (_names.length > 0) {
				for (key in _names) {
					if (_names.hasOwnProperty(key) && key !== 'length') {
						setAddToCart($(pd.id+"_link_"+key));
					}
				}
			}
			$(pdMnL.id).setClick(function (e) { self.extendPopdown(id, un, e); });
			pdE = $("cart_popDown");
		}
		if (isset(typeof(MbitLinks))) {
			// play nicely with search results - keep selected result popup shown while cart is shown
			var mbitLinks = new MbitLinks();	// this returns a static instance of the MbitLinks that will already be created
			mbitLinks.prolongFromCart();
			pdE.addEvent("mouseover", mbitLinks.prolongFromCart);
			pdE.addEvent("mousemove", mbitLinks.prolongFromCart);
			this.selectedResult = mbitLinks.selected();
		}

		//pdE.addEvent("mouseover", self.clrTimeout());
	};

	self.extendPopdown = function (bid, bn, e) {
		cancelBubble(e);
		var pd = $("cart_popDown"), pdE = $(pd.id+"_ext");
		if (pd && !pdE) {
			pdE = pd.create("div", pd.id+'_ext');
			var pdEl = pdE.create("div", pdE.id+'_lbl', null, "new cart name:"),
				pdEb = pdE.create("div", pdE.id+'_btm'),
					pdEi = pdEb.create("input", pdEb.id+'_inp'),
					pdEa = pdEb.create("a", pdEb.id+'_btn', 'hand', "add cart"),
					sssh = pdEb.create("span", pdEb.id+'_sssh_n', null, bid+"|"+bn).hide(),
					clr = pdEb.create("div").classify('clear');
			pdEi.type = "text";
			pdEa.setClick(function (e) {
				var val = pdEi.value;
				if (val !== "") {
					cancelBubble(e);
					self.newCart(val, this, e);
					self.removePD(e,true);
				}
			});
		}
	};

	self.newCartFromMenu = function (menu, e) {
		cancelBubble(e);
		var value = window.prompt("Please enter the name of the new cart:"); // get name
		if (value!==null && value!=="") { self.newCart(value, false, e); }
		else { menu.options.selectedIndex = _names.length; }
		//else { menu.options.selectedIndex = _curCart!==null ? _curCart : _names.length };
	};

	self.newCart = function (value, link, e) {
		cancelBubble(e);
		var params = "new=y&name="+encodeURIComponent(value);
		_ajax = new Ajax( _URL, { method: _mode, parameters: params, onFailure: self.reportError, onSuccess: function (request) { self.newResp(request, link, value );  } });
		_ajax.send();
	};

	self.newResp = function (request, link, value ) {
		var resp = JSON.parse(request.responseText), cid;
		if (resp.length === 2 && resp[0]) {
			cid = resp[1];
			_names[cid] = value;
			++_names.length;
			if (!_curCart) { _curCart = cid; }
			_data[cid] = []; // {length:0};
			if (link) {
				link.nextSibling.append('|'+cid);
				self.addToCart(link, true);
			} else {
				//	add cart to cartSel(before viewSep) and cartMove
				var opt1 = document.create("option"), opt2 = _cartMove.create("option");
				opt1.value = cid;
				opt1.innerHTML = value;
				opt2.value = cid;
				opt2.innerHTML = value;
				_cartSel.insertBefore(opt1, $("viewSep"));
				mmmChangeBold(_cartMove);
				mmmChangeBold(_cartSel);
				statusBar.talk('Cart "'+value+'" has been created.');
				var view = document.create('a', 'sBvL', null, "view cart"),
					undo = document.create('a', 'sBuL', null, "undo");
				view.href = "/cart?cart="+cid;
				statusBar.show();
				statusBar.map([view]);
				self.showCart(cid, true);
			}
		} else { statusBar.error("AJAX PHP error in making new cart."); }
	};

	self.removePD = function (e, click) {
		cancelBubble(e);
		var pd = "cart_popDown", relT = {};
		if (!click) {
			if (!e) { e = window.event; }
			relT = e.relatedTarget || e.toElement;
			if (!isset(typeof(relT)) || relT.id) { relT = false; }
		}
		if (!!click || (relT && ![relT.id, relT.parentNode.id, relT.parentNode.parentNode.id, relT.parentNode.parentNode.parentNode.id].in_array(pd))) {
			pd = $(pd);
			//if (pd) { _timeOut = setTimeout('$("'+pd.id+'").remove();', 200); }
			if (pd) { _timeOut = setTimeout(self.removePDFinally.bind(self), 200); }
		}
	};

	self.removePDFinally = function () {
		var pd = $('cart_popDown');
		if (pd) { pd.remove(); }
		if (isset(typeof(MbitLinks))) {
			// close the selected result popup on the search results if it exists and hasn't changed
			var mbitLinks = new MbitLinks();	// this returns a static instance of the MbitLinks that will already be created
			if (this.selectedResult === mbitLinks.selected() && !mbitLinks.stillHovered()) {
				mbitLinks.closeResult();
			}
		}
	};

	window.addLoad(self.initialize);
	return self;
}();
/*
function DL_GetElementLeft(eElement) {
   if (!eElement && this)                    // if argument is invalid
   {                                         // (not specified, is null or is 0)
      eElement = this;                       // and function is a method
   }                                         // identify the element as the method owner

   var DL_bIE = document.all ? true : false; // initialize var to identify IE

   var nLeftPos = eElement.offsetLeft;       // initialize var to store calculations
   var eParElement = eElement.offsetParent;  // identify first offset parent element

   while (eParElement !== null)
   {                                         // move up through element hierarchy

      if(DL_bIE)                             // if browser is IE, then...
      {
         if( (eParElement.tagName != "TABLE") && (eParElement.tagName != "BODY") )
         {                                   // if parent is not a table or the body, then...
            nLeftPos += eParElement.clientLeft; // append cell border width to calcs
         }
      }
      else                                   // if browser is Gecko, then...
      {
         if(eParElement.tagName == "TABLE")  // if parent is a table, then...
         {                                   // get its border as a number
            var nParBorder = parseInt(eParElement.border,10);
            if(isNaN(nParBorder))            // if no valid border attribute, then...
            {                                // check the table's frame attribute
               var nParFrame = eParElement.getAttribute('frame');
               if(nParFrame !== null)         // if frame has ANY value, then...
               {
                  nLeftPos += 1;             // append one pixel to counter
               }
            }
            else if(nParBorder > 0)          // if a border width is specified, then...
            {
               nLeftPos += nParBorder;       // append the border width to counter
            }
         }
      }
      nLeftPos += eParElement.offsetLeft;    // append left offset of parent
      eParElement = eParElement.offsetParent; // and move up the element hierarchy
   }                                         // until no more offset parents exist
   return nLeftPos;                          // return the number calculated
}

function DL_GetElementTop(eElement) {
	if (!eElement && this) {                   // if argument is invalid (not specified, is null or is 0) and function is a method, identify the element as the method owner
		eElement = this;
	}

	var DL_bIE = document.all ? true : false; // initialize var to identify IE

	var nTopPos = eElement.offsetTop;         // initialize var to store calculations
	var eParElement = eElement.offsetParent;  // identify first offset parent element

   while (eParElement !== null) {	     // move up through element hierarchy
      if(DL_bIE)                             // if browser is IE, then...
      {
         if( (eParElement.tagName != "TABLE") && (eParElement.tagName != "BODY") )
         {                                   // if parent a table cell, then...
            nTopPos += eParElement.clientTop; // append cell border width to calcs
         }
      }
      else                                   // if browser is Gecko, then...
      {
         if(eParElement.tagName == "TABLE")  // if parent is a table, then...
         {                                   // get its border as a number
            var nParBorder = parseInt(eParElement.border,10);
            if(isNaN(nParBorder))            // if no valid border attribute, then...
            {                                // check the table's frame attribute
               var nParFrame = eParElement.getAttribute('frame');
               if(nParFrame !== null)         // if frame has ANY value, then...
               {
                  nTopPos += 1;              // append one pixel to counter
               }
            }
            else if(nParBorder > 0)          // if a border width is specified, then...
            {
               nTopPos += nParBorder;        // append the border width to counter
            }
         }
      }

      nTopPos += eParElement.offsetTop;      // append top offset of parent
      eParElement = eParElement.offsetParent; // and move up the element hierarchy
   }                                         // until no more offset parents exist
   return nTopPos;                           // return the number calculated
}
*/