/**
 * @name			Project Detail Script Kit
 * @namespace		TB.Detail
 * @author			Kong Wei (Chappell.Wat) <kongwei@taobao.com>
 * @description		A script kit for taobao's project detail.
 * @requires		YAHOO, Lang, Env, Anim, DOM, Event, Connect, TBra
 * @constructor
 * @param {Object} config (optional)
 *		Editor Configuration.
 * @version			1.1
 * @changelog
 *		Ver 1.0 @ 2008-11-27	Initialize release
 *		Ver 1.1 @ 2009-01-03	Structure rebuilt for TC
 */
(function () {
	TB.namespace('Detail');

	/**
	 * shortcuts
	 * @private
	 */
	var YU = YAHOO.util,
		YL = YAHOO.lang,
		YEU = YAHOO.env.ua,
		YUA = YU.Anim,
		YUC = YU.Connect,
		YUD = YU.Dom,
		YUE = YU.Event;

	/**
	 * clearNodes
	 * @private
	 */
	var clearNodes = function (elmt) {
		for (var i = elmt.childNodes.length - 1; 0 <= i; i --) {
			elmt.removeChild(elmt.childNodes[i]);
		}
	};

	/**
	 * VIP Promotion Module
	 */
	TB.Detail.VipPopup = function () {
		/**
		 * vars
		 * @private
		 */
		var config = {},
			timer = null;

		/**
		 * getElmt
		 * @private
		 */
		var getElmt = function () {
			// create a new ul
			var neoUl = document.createElement('ul'),
				prices = config.valVipPrices;
			for (var vip in prices) {
				var neoLi = document.createElement('li');
				neoLi.appendChild(document.createTextNode(vip + '：'));
				var neoEm = document.createElement('em');
				neoEm.appendChild(document.createTextNode(prices[vip] + ' 元'));
				neoLi.appendChild(neoEm);
				neoUl.appendChild(neoLi);
			}
			var neoDiv = document.createElement('div');
			neoDiv.appendChild(neoUl);
			var neoDiv2 = document.createElement('div');
			neoDiv2.className = 'vip-popup invisible';
			neoDiv2.appendChild(neoDiv);
			var neoSpan = document.createElement('span');
			neoDiv2.appendChild(neoSpan);
			document.body.appendChild(neoDiv2);

			// init position
			YUD.setXY(neoDiv2, [0, 0]);

			// overwrite the function
			getElmt = function () {
				return neoDiv2;
			};
			return getElmt();
		};

		/**
		 * decorate
		 * @private
		 */
		var decorate = function () {
			// get popup
			var vipPopup = getElmt(),
				imgVip = config.imgVip;

			// pointer style for vip img
			YUD.setStyle(imgVip, 'cursor', 'pointer');

			// show it
			YUE.on(imgVip, 'mouseover', function (evt) {
				// related target
				var relTarget = YUE.getRelatedTarget(evt);

				// on mouse enter
				if (relTarget !== imgVip && true !== YUD.isAncestor(imgVip, relTarget)) {
					if (null !== timer) {
						timer.cancel();
					}
					timer = YL.later(200, this, function () {
						// calculate the position
						YUD.setXY(vipPopup, [YUD.getX(config.imgVip), YUD.getY(config.imgVip) + 13]);

						YUD.removeClass(vipPopup, 'invisible');
					});
				}
			});

			// hide it
			YUE.on(imgVip, 'mouseout', function (evt) {
				// related target
				var relTarget = YUE.getRelatedTarget(evt);

				// on mouse leave
				if (relTarget !== imgVip && true !== YUD.isAncestor(imgVip, relTarget)) {
					if (null !== timer) {
						timer.cancel();
					}
					timer = YL.later(200, this, function () {
						YUD.addClass(vipPopup, 'invisible');
					});
				}
			});

			YUE.on(vipPopup, 'mouseover', function (evt) {
				// related target
				var relTarget = YUE.getRelatedTarget(evt);

				// on mouse enter
				if (relTarget !== vipPopup && true !== YUD.isAncestor(vipPopup, relTarget)) {
					if (null !== timer) {
						timer.cancel();
					}
					timer = YL.later(200, this, function () {
						YUD.removeClass(vipPopup, 'invisible');
					});
				}
			});

			YUE.on(vipPopup, 'mouseout', function (evt) {
				// related target
				var relTarget = YUE.getRelatedTarget(evt);

				// on mouse leave
				if (relTarget !== vipPopup && true !== YUD.isAncestor(vipPopup, relTarget)) {
					if (null !== timer) {
						timer.cancel();
					}
					timer = YL.later(200, this, function () {
						YUD.addClass(vipPopup, 'invisible');
					});
				}
			});
		};

		return {
			/**
			 * initialization
			 * @public
			 */
			init: function () {
				// read config
				config = TB.Detail.Setup.getConfig();
				if ('undefined' === typeof config) {
					return false;
				}

				// decoration
				decorate();
			}
		};
	}();

	/**
	 * Safety Service Module
	 */
	TB.Detail.SafetyService = function () {
		/**
		 * vars
		 * @private
		 */
		var config = {},
			timer = null;

		/**
		 * decorate
		 * @private
		 */
		var decorate = function (triggers, tips) {

			// default showing
			var showing = tips[0];
			YUD.removeClass(showing, 'hidden');
			

			// binding
			for (var i = triggers.length - 1; 0 <= i; i --) {
				(function () {
					// vars
					var j = i,
						curTrigger = triggers[j],
						curTip = tips[j];

					// binding
					YUE.on(curTrigger, 'mouseover', function (evt) {
						// currently selected?
						if (false === YUD.hasClass(curTip, 'hidden')) {
							return false;
						}

						// get target and related target
						var relTarget = YUE.getRelatedTarget(evt);

						// on mouse enter
						if (relTarget !== curTrigger && true !== YUD.isAncestor(curTrigger, relTarget)) {
							if (null !== timer) {
								timer.cancel();
							}
							timer = YL.later(200, this, function () {

								// reset showing
								YUD.addClass(showing, 'hidden');

								// show the tip
								YUD.removeClass(curTip, 'hidden');
								showing = curTip;
							});
						}
					});
				})();
			}
		};

		return {
			/**
			 * initialization
			 * @public
			 */
			init: function () {
				// read config
				config = TB.Detail.Setup.getConfig();
				if ('undefined' === typeof config) {
					return false;
				}

				// requirements
				var triggers = config.liSafety.getElementsByTagName('em'),
					tips = config.liSafety.getElementsByTagName('dl');
				if (0 < triggers.length && triggers.length === tips.length) {
					// decoration
					decorate(triggers, tips);
				}
			}
		};
	}();

	/**
	 * Image Viewer Module
	 */
	TB.Detail.ImageViewer = function () {
		/**
		 * vars
		 * @private
		 */
		var config = {};

		/**
		 * getFlashMainVer - modified from YUI
		 * @private
		 */
		var getFlashMainVer = function () {
			var mainVer = 0,
				axo = null;
			if (navigator.plugins && navigator.mimeTypes.length) {
				var plugin = navigator.plugins['Shockwave Flash'];
				if(plugin && plugin.description) {
					mainVer = plugin.description.replace(/([a-zA-Z]|\s)+/, '').replace(/(\s+r|\s+b[0-9]+)/, '.').split('.')[0];
				}
			} else if (navigator.userAgent && 0 <= navigator.userAgent.indexOf('Windows CE')) {
				// if Windows CE
				var counter = 3;
				while (axo) {
					try {
						counter ++;
						axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.' + counter);
						mainVer = counter;
					} catch (e) {
						axo = null;
					}
				}
			} else {
				// Win IE (non mobile)
				// do minor version lookup in IE, but avoid fp6 crashing issues
				// see http://blog.deconcept.com/2006/01/11/getvariable-setvariable-crash-internet-explorer-flash-6/
				try {
					axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.7');
				} catch(e) {
					try {
						axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash.6');
						mainVer = 6;
						axo.AllowScriptAccess = 'always'; // error if player version < 6.0.47 (thanks to Michael Williams @ Adobe for this code)
					} catch(e) {
						if (6 === mainVer) {
							return mainVer;
						}
					}
					try {
						axo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
					} catch (e) {
					}
				}

				if(null !== axo) {
					mainVer = axo.GetVariable('$version').split(' ')[1].split(',')[0];
				}
			}
			return mainVer;
		};

		/**
		 * outputBooth
		 * @private
		 */
		var outputBooth = function () {
			// image info
			var info = config.valImageInfo;

			// decoder
			var decode = function (url) {
				var newUrl = '';
				for (var i = 0; i < url.length; ++ i) { 
					var code = url.charCodeAt(i); 
					newUrl += String.fromCharCode(code ^ (i % 5)); 
				}
				return newUrl;
			};

			// building
			var neoA = document.createElement('a');
			neoA.target = '_blank';
			neoA.href = info.linkUrl + '&d=1'; //d=1 means big image for js version
			var neoImg = document.createElement('img');
			neoImg.src = (info.imgPath || 'http://image.taobao.com/bao/uploaded') + '/' + decode(info.imgUrl) + '_310x310.jpg'; // adding suffix
			neoA.appendChild(neoImg);

			// appending
			clearNodes(config.divBooth);
			config.divBooth.appendChild(neoA);

			// change target				
			config.LinkMagnifier.href = neoA.href;
			config.LinkMagnifier.target = '_blank';

			// binding
			YUE.on(vipPopup, 'error', function () {
				config.divBooth.className = 'booth aborted';
				clearNodes(config.divBooth);
				config.divBooth.appendChild(document.createTextNode('加载图片超时'));
			});
		};

		/**
		 * decorate
		 * @private
		 */
		var decorate = function () {
			// get main version of flash
			var flashVer = getFlashMainVer();

			if (8 < flashVer) {
				// image info
				var info = config.valImageInfo;

				config.divBooth.innerHTML = '<embed src="http://assets.taobaocdn.com/swf/detail080523.swf" quality="high" width="310" height="310" name="ImageViewer" allowScriptAccess="always" type="application/x-shockwave-flash" wmode="transparent" pluginspage="http://www.macromedia.com/go/getflashplayer" FlashVars="' + info.swfVars + ((config.valMode & 4) ? '' : '&fv=' + flashVer) + '" />';

				// change target				
				config.LinkMagnifier.href = info.linkUrl + ((config.valMode & 4) ? '' : '&fv=' + flashVer); // no fv param for simple shop
				config.LinkMagnifier.target = '_blank';

				// if failed to load img, then switch to the js version
				window['commandDelegate'] = function(cmd) {
					if ('jsShowImg' === cmd) {
						// hiding flash
						var swf = config.divBooth.getElementsByTagName('embed')[0];
						swf.style.display = 'none';
						YL.later(1, null, outputBooth);
					}
				};
			} else {
				// js version
				outputBooth();
			}
		};

		return {
			/**
			 * initialization
			 * @public
			 */
			init: function () {
				// read config
				config = TB.Detail.Setup.getConfig();
				if ('undefined' === typeof config) {
					return false;
				}

				// decoration
				decorate();
			}
		};
	}();

	/**
	 * Thumbnail Viewer Module
	 */
	TB.Detail.ThumbViewer = function () {
		/**
		 * vars
		 * @private
		 */
		var config = {},
			timer = null,
			viewing = null;

		/**
		 * getPics
		 * @private
		 */
		var getBoothes = function () {
			var thumbPics = config.ulThumb.getElementsByTagName('img'),
				boothPics = [];
			for (var i = thumbPics.length - 1; 0 <= i; i --) {
				boothPics.unshift(thumbPics[i].getAttribute('src'));
			}

			// overwrite the function
			getBoothes = function () {
				return boothPics;
			};
			return getBoothes();
		};

		/**
		 * decorate
		 * @private
		 */
		var decorate = function (thumbs) {
			// get currently viewing item
			viewing = thumbs[0];

			// binding
			for (var i = thumbs.length - 1; 0 <= i; i --) {
				(function () {
					// vars
					var j = i,
						curThumb = thumbs[j];

					// binding
					YUE.on(curThumb, 'mouseover', function (evt) {
						// currently selected?
						if (true === YUD.hasClass(curThumb, 'selected')) {
							return false;
						}

						// get target and related target
						var relTarget = YUE.getRelatedTarget(evt);

						// on mouse enter
						if (relTarget !== curThumb && true !== YUD.isAncestor(curThumb, relTarget)) {
							if (null !== timer) {
								timer.cancel();
							}
							timer = YL.later(200, this, function () {
								// reset showing
								YUD.removeClass(viewing, 'selected');

								// show the tip
								YUD.addClass(curThumb, 'selected');
								viewing = curThumb;

								// change booth
								config.imgBooth.src = getBoothes()[j];
							});
						}
					});
					YUE.on(curThumb, 'click', function (evt) {
						// stop event
						YUE.stopEvent(evt);
					});
				})();
			}
		};

		return {
			/**
			 * initialization
			 * @public
			 */
			init: function () {
				// read config
				config = TB.Detail.Setup.getConfig();
				if ('undefined' === typeof config) {
					return false;
				}

				// thumbnail viewer
				var thumbs = config.ulThumb.getElementsByTagName('li');
				if (0 < thumbs.length) {
					// decoration
					decorate(thumbs);
				} else {
					config.valMode -= 32;
				}
			},
			/**
			 * show
			 * @public
			 */
			show: function (imgSrc) {
				// prevent from select a duplicated one
				if (config.imgBooth.src === imgSrc) {
					return false;
				}

				// reset showing
				YUD.removeClass(viewing, 'selected');
				viewing = null;

				// change booth
				config.imgBooth.src = imgSrc;
			}
		};
	}();

	/**
	 * Sales Property Handler Module
	 */
	TB.Detail.PropertyHandler = function () {
		/**
		 * vars
		 * @private
		 */
		var config = {},
			propData = [],
			selProp = [],
			propLen = 0,
			fieldData = {
				skuId:		'',
				skuInfo:	'',
				amount:		0
			};

		/**
		 * showImg
		 * @private
		 */
		var showImg = function (imgSrc) {
			// overwrite the function
			if (config.valMode & 32) {
				showImg = function (img) {
					TB.Detail.ThumbViewer.show(img);
				};
			} else {
				showImg = function () {
					return false;
				};
			}
			return showImg(imgSrc);
		};

		/**
		 * updateComboProp
		 * @private
		 */
		var updateComboProp = function (index, value) {
			// overwrite the function
			if (config.valMode & 16) {	// combo mode
				var propList = [],
					fragment = document.createDocumentFragment();
					neoUl = document.createElement('ul');
				neoUl.className = 'props';

				for (var i = propLen - 1; 0 <= i; i --) {
					var thisProp = propData[i],
						neoLi = document.createElement('li');
					neoLi.appendChild(document.createTextNode(thisProp.prop + '：'));
					var neoStr = document.createElement('strong');
					neoStr.appendChild(document.createTextNode('尚未选择'));
					neoLi.appendChild(neoStr);
					neoUl.insertBefore(neoLi, neoUl.firstChild || null);

					// push into index array
					propList.unshift(neoStr);
				}
				fragment.appendChild(neoUl);
				var neoHr = document.createElement('hr');
				fragment.appendChild(neoHr);
				config.ulChoice.parentNode.insertBefore(fragment, config.ulChoice);

				// overwrite the function
				updateComboProp = function (idx, val) {
					propList[idx].replaceChild(document.createTextNode(val), propList[idx].firstChild);
				};
			} else {
				updateComboProp = function () {
					return false;
				};
			}
			return updateComboProp(index, value);
		};

		/**
		 * setErrMsg
		 * @private
		 */
		var setErrMsg = function (errMsg) {
			// create a new div
			var neoDiv = document.createElement('div');
			neoDiv.className = 'msg hidden';
			var neoP = document.createElement('p');
			neoP.appendChild(document.createTextNode('发生错误'));
			neoP.className = 'stop';
			neoDiv.appendChild(neoP);
			config.dlChoice.parentNode.insertBefore(neoDiv, config.dlChoice);

			// overwrite the function
			setErrMsg = function (msg) {
				if ('undefined' !== typeof msg) {
					neoP.replaceChild(document.createTextNode(msg), neoP.firstChild);
				}
				return neoDiv;
			};
			return setErrMsg(errMsg);
		};

		/**
		 * validate
		 * @private
		 */
		var validate = function () {
			// fields data
			var skuInfo = [];

			// validate props
			var errArr = [];
			for (var i = propLen - 1; 0 <= i; i --) {
				var thisProp = selProp[i];
				if ('' === thisProp.pvid) {
					YUD.addClass(propData[i].elmt, 'h');

					// log error
					errArr.push(thisProp.prop);
				} else {
					YUD.removeClass(propData[i].elmt, 'h');

					// field data
					skuInfo.unshift(thisProp.prop + ':' + thisProp.name);
				}
			}
			var errLen = errArr.length;
			if (0 < errLen) {
				clearNodes(config.dlChoice);
				var fragment = document.createDocumentFragment();
				var neoDt = document.createElement('dt');
				neoDt.appendChild(document.createTextNode('请选择：'));
				fragment.appendChild(neoDt);
				var neoDd = document.createElement('dd');
				neoDd.className = 'h';
				for (var i = errLen - 1; 0 <= i; i --) {
					var neoEm = document.createElement('em');
					neoEm.appendChild(document.createTextNode('"' + errArr[i] + '"'));
					neoDd.appendChild(neoEm);
				}
				fragment.appendChild(neoDd);
				config.dlChoice.appendChild(fragment);

				// highlighting
				YUD.addClass(config.dlChoice, 'h');
			} else {
				// cancel highlighting
				YUD.removeClass(config.dlChoice, 'h');

				// field data
				fieldData.skuInfo = skuInfo.join(';');
			}

			// check amount
			var errMsg = '',
				stock = parseInt(config.spanStock.firstChild.nodeValue, 10),
				amount = parseInt(config.iptAmount.value, 10);
			switch (true) {
			case isNaN(amount) || 0 >= amount:
				errMsg = '请填写正确的商品数量！';
				break;
			case stock < amount:
				errMsg = '您所填写的商品数量超过库存！';
				break;
			}
			if ('' !== errMsg) {
				// show error message
				YUD.removeClass(setErrMsg(errMsg), 'hidden');
			} else {
				// hide error message
				YUD.addClass(setErrMsg(), 'hidden');

				// field data
				fieldData.amount = amount;
			}

			// return
			if (0 < errLen || '' !== errMsg) {
				return false;
			}
			return true;
		};

		// unique
		var unique = function (arr) {
			if (arr.length < 2) {
				return arr;
			}
			var a = [],
				b = [];
			for (var c in arr) {
				var d = arr[c];
				if (d === a[c]) {
					continue;
				}
				if (1 !== b[d]){
					a.push(d);
					b[d] = 1;
				}
			}
			return a;
		}

		// calVipPrice
		var calVipPrice = function (price) {
			return (price * config.valItemInfo.vipRate / 100).toFixed(2);
		}

		/**
		 * decorate
		 * @private
		 */
		var decorate = function () {
			// count properties
			propLen = config.elmProps.length;

			// shorcuts
			var skuMap = config.valItemInfo.skuMap,
				oosMap = config.valItemInfo.oosMap,
				strPrice = config.strPrice,
				spanStock = config.spanStock,
				oosCache = [], // out-of-stock element array, may be blank
				defSelQueue = [], // default selection queue
				defSel = config.valItemInfo.defSelected, // default selection item array
				doesDefSel = ('undefined' !== typeof defSel && propLen === defSel.length);

			// decorating
			for (var i = propLen - 1; 0 <= i ; i --) {
				var curElmt = config.elmProps[i],
					curProp = propData[i] = {
						prop:	'',		// prop name
						elmt:	null,	// prop name container element <dt>
						data:	[],		// pv data
						hasImg:	null	// does this prop have image?
					},
					curSel = selProp[i] = {
						pvid:	'',		// pvid
						prop:	'',		// selected prop
						name:	'',		// selected prop value
						elmt:	null	// selected prop element <li>
					};

				// get prop name & element & image status
				curProp.prop = curSel.prop = curElmt.getAttribute('data-property');
				curProp.elmt = YUD.getPreviousSibling(curElmt.parentNode);
				curProp.hasImg = YUD.hasClass(curElmt, 'img');

				// selected anchor
				var selAnchor = document.createElement('i');
				selAnchor.appendChild(document.createTextNode('已选中'));

				// get prop data && binding
				var vals = curElmt.getElementsByTagName('span');
				for (var j = vals.length - 1; 0 <= j; j --) {
					var curSpan = vals[j],
						curLink = curSpan.parentNode,
						curItem = curLink.parentNode,
						curData = {
							name:	'',		// prop value
							pvid:	'',		// prop value id
							elmt:	null,	// prop element <li>
							img:	''		// prop value image
						};
					curData.name = curSpan.firstChild.nodeValue;
					curData.pvid = curItem.getAttribute('data-value');
					curData.elmt = curItem;

					// fetching big image url
					if (true === curProp.hasImg) {
						var bgImg = YUD.getStyle(curLink, 'background-image');
						if ('none' !== bgImg) {
							curData.img = bgImg.replace('url(', '').replace(')', '');
						}
					}
					curProp.data.unshift(curData);

					// default selection queue
					if ((true === doesDefSel && defSel[i] === curData.pvid) || 1 === vals.length) {
						defSelQueue.push(curLink);
					}

					// mouse behavior
					(function () {
						// shortcuts
						var idx = i,
							propName = curProp.prop,
							theItem = curItem,
							theLink = curLink,
							theData = curData,
							theSel = curSel,
							theAchr = selAnchor;
						YUE.on(theLink, 'click', function (evt) {
							// stop events
							if ('undefined' !== typeof evt) {
								YUE.stopEvent(evt);
							}

							// out of stock
							if (YUD.hasClass(theItem, 'out-of-stock')) {
								return false;
							}

							// change booth image
							if ('' !== theData.img) {
								showImg(theData.img);
							}

							// no duplicated
							if (theSel.pvid === theData.pvid) {
								return false;
							}

							// UI changes
							YUD.addClass(theItem, 'selected');
							theItem.appendChild(theAchr);
							YUD.removeClass(theSel.elmt, 'selected');

							// update data
							theSel.pvid = theData.pvid;
							//theSel.prop = propName;	// no need to update for every time
							theSel.name = theData.name;
							theSel.elmt = theItem;

							// detect sku & set out-of-stock status
							var selPvid = [],
								hasOos = false,
								oosArr = [];

							// update choice status
							clearNodes(config.dlChoice);
							var fragment = document.createDocumentFragment();
							var neoDt = document.createElement('dt');
							neoDt.appendChild(document.createTextNode('已选择：'));
							fragment.appendChild(neoDt);
							var neoDd = document.createElement('dd');
							neoDd.className = 'h';
							for (var k = 0; propLen > k; k ++) {
								// create a part of status
								var thisProp = selProp[k],
									thisPvId = thisProp.pvid;
								if ('' !== thisPvId) {
									// update prop choices
									var neoEm = document.createElement('em');
									neoEm.setAttribute('title', thisProp.prop);
									neoEm.appendChild(document.createTextNode('"' + thisProp.name + '"'));
									neoDd.appendChild(neoEm);

									// update sku flag
									selPvid.push(thisPvId);

									// combine oos arraies
									if ('undefined' !== typeof oosMap[thisPvId]) {
										oosArr = oosArr.concat(oosMap[thisPvId]);
										hasOos = true;
									}
								}
								fragment.appendChild(neoDd);
							}
							config.dlChoice.appendChild(fragment);

							// update prop choice for combo mode
							updateComboProp(idx, theData.name);

							// restore out-of-stock items first
							while (0 < oosCache.length) {
								YUD.removeClass(oosCache.pop(), 'out-of-stock');
							}

							// check out if it's out of stock
							if (true === hasOos) {
								// force unique
								oosArr = unique(oosArr);

								for (var k = propLen - 1; 0 <= k; k --) {
									if (0 === oosArr.length) {
										break;
									}
									var curData = propData[k].data,
										tmpArr = [];
									for (var l = curData.length - 1; 0 <= l; l --) {
										if (0 === oosArr.length) {
											break;
										}
										var thisData = curData[l];
										for (var m = oosArr.length - 1; 0 <= m; m --) {
											if (thisData.pvid === oosArr[m]) {
												// UI Change
												YUD.addClass(thisData.elmt, 'out-of-stock');

												// update cache
												oosCache.push(thisData.elmt);

												// delete the item
												oosArr.pop();

												// get in-stock items
												tmpArr.unshift(l);
											}
										}
									}

									// select the only one in-stock
									var tmpLen = tmpArr.length;
									if (curData.length - 1 === tmpLen) {
										for (var l = 0; l < tmpLen; l ++) {
											if (tmpArr[l] !== l) {
												YUE.getListeners(curData[l].elmt.getElementsByTagName('a')[0], 'click')[0].fn();
											}
										}
									}
								}
							}

							// try to get sku id
							if (selPvid.length === propLen) {
								var skuFlag = ';' + selPvid.join(';') + ';';
								if ('undefined' !== typeof skuMap[skuFlag]) {
									var curSku = skuMap[skuFlag];
									// update price
									strPrice.replaceChild(document.createTextNode(curSku.price), strPrice.firstChild);

									// update vip price
									if (config.valMode & 8) {
										config.spanVip.replaceChild(document.createTextNode(calVipPrice(curSku.price)), config.spanVip.firstChild);
									}

									// update 
									if (config.valMode & 16) {
										TB.Detail.ComboHandler.updatePrice();
									}

									// update stock
									spanStock.replaceChild(document.createTextNode(curSku.stock), spanStock.firstChild);

									// field data
									fieldData.skuId = curSku.skuId;
								}
							}
						});
					})();
				}
			}

			// default selection - a brean-new way, cool huh?
			while (0 < defSelQueue.length) {
				YUE.getListeners(defSelQueue.pop(), 'click')[0].fn();
			}

			// binding
			YUE.on(config.linkBuy, 'click', function (evt) {
				// stop events
				YUE.stopEvent(evt);

				// validation
				if (true === validate()) {
					// shortcut
					var formElm = config.frmBid.elements;

					// update
					formElm['quantity'].value = fieldData.amount;
					formElm['skuId'].value = fieldData.skuId;
					formElm['skuInfo'].value = fieldData.skuInfo;

					// submitting
					config.frmBid.submit();
				}
			});

			var hoverTimer = null;
			YUE.on(config.linkBuy, 'mouseover', function (evt) {
				// related target
				var relTarget = YUE.getRelatedTarget(evt);

				// on mouse enter
				if (relTarget !== config.linkBuy && true !== YUD.isAncestor(config.linkBuy, relTarget)) {
					if (null !== hoverTimer) {
						hoverTimer.cancel();
					}
					hoverTimer = YL.later(200, this, function () {
						// validation
						validate();
					});
				}
			});

			var divKeyProp = config.divKeyProp;
			YUE.on(divKeyProp, 'mouseover', function (evt) {
				// remove after mouse over
				YUE.removeListener(divKeyProp, 'mouseover', arguments.callee);

			});
			
			if (6 == YEU.ie) {	// fix for ie6
				YUE.on(divKeyProp, 'mouseover', function (evt) {
					// related target
					var relTarget = YUE.getRelatedTarget(evt);

					// on mouse enter
					if (relTarget !== divKeyProp && true !== YUD.isAncestor(divKeyProp, relTarget)) {
						if (null !== hoverTimer) {
							hoverTimer.cancel();
						}
						hoverTimer = YL.later(100, this, function () {
							YUD.addClass(divKeyProp, 'key-hover');
						});
					}
				});
				YUE.on(divKeyProp, 'mouseout', function (evt) {
					// related target
					var relTarget = YUE.getRelatedTarget(evt);

					// on mouse leave
					if (relTarget !== divKeyProp && true !== YUD.isAncestor(divKeyProp, relTarget)) {
						if (null !== hoverTimer) {
							hoverTimer.cancel();
						}
						hoverTimer = YL.later(100, this, function () {
							YUD.removeClass(divKeyProp, 'key-hover');
						});
					}
				});
			}
		};

		return {
			/**
			 * initialization
			 * @public
			 */
			init: function () {
				// read config
				config = TB.Detail.Setup.getConfig();
				if ('undefined' === typeof config) {
					return false;
				}

				// decoration
				decorate();
			},
			/**
			 * getFieldData
			 * @public
			 */
			getFieldData: function () {
				return fieldData;
			},
			/**
			 * validatePorp
			 * @public
			 */
			validatePorp: function () {
				return validate();
			}
		};
	}();

	/**
	 * Cart Handler Module
	 */
	TB.Detail.CartHandler = function () {
		/**
		 * vars
		 * @private
		 */
		var config = {},
			itemCount = 0,
			isMember = false;

		/**
		 * showErrMsg
		 * @private
		 */
		var showErrMsg = function () {
			// create a new div
			var neoDiv = document.createElement('div');
			neoDiv.className = 'msg';
			var neoP = document.createElement('p');
			if (true === isMember) {
				neoP.appendChild(document.createTextNode('您添加的宝贝种类已经达到上限了'));
			} else {
				var fragment = document.createDocumentFragment();
				fragment.appendChild(document.createTextNode('您添加的宝贝种类已经达到上限了，'));
				var neoLink = document.createElement('a');
				neoLink.href = '#';
				neoLink.appendChild(document.createTextNode('登录'));
				fragment.appendChild(neoLink);
				fragment.appendChild(document.createTextNode('后可继续添加'));
				neoP.appendChild(fragment);
			}
			neoP.className = 'stop';
			neoDiv.appendChild(neoP);
			config.dlChoice.parentNode.insertBefore(neoDiv, config.linkBuy.parentNode);

			return neoDiv;
		};

		/**
		 * updateCart
		 * @private
		 */
		var updateCart = function (result) {
			itemCount = result.cartQuantity;
			config.spanCart.replaceChild(document.createTextNode('(' + itemCount + ')'), config.spanCart.firstChild);
			config.linkCart.setAttribute('title', '购物车内有 ' + result.cartQuantity + ' 件商品，共计 ' + result.cartPrice + ' 元。');
		};

		/**
		 * decorate
		 * @private
		 */
		var decorate = function () {
			// read cart info from cookie
			var cookieStr = document.cookie,
				matches = [
					cookieStr.match(/(=|&)?cart_i=([^&|;]*)/),
					cookieStr.match(/(=|&)?cart_p=([^&|;]*)/)
				];
			updateCart({
				cartQuantity:	(matches[0]) ? matches[0][2] : '0',
				cartPrice:		(matches[1]) ? matches[1][2] : '0'
			});

			// view-cart trigger
			YUD.removeClass(config.divCart, 'invisible');

			// binding
			YUE.on(config.linkAdd, 'click', function (evt) {
				// stop events
				YUE.stopEvent(evt);

				// overload
				if ((false === isMember && 20 <= itemCount) || (true === isMember && 50 <= itemCount)) {
					// show error msg
					showErrMsg();

					// remove after mouse over
					YUE.removeListener(config.linkAdd, 'click', arguments.callee);

					return false;
				}

				// validation
				if (config.valMode & 1) {
					if (true === TB.Detail.PropertyHandler.validatePorp()) {
						// shortcut
						var fieldData = TB.Detail.PropertyHandler.getFieldData();
					} else {
						return;
					}
				}

				// get outer id & type
				if ('undefined' !== typeof fieldData) {
					var outerType = 2,
						outerId = fieldData.skuId,
						amount = fieldData.amount,
						dbNum = config.valCartInfo.dbNum;
				} else {
					var outerType = 1,
						outerId = config.valCartInfo.itemId,
						amount = 1,
						dbNum = config.valCartInfo.dbNum;
				}

				// build query string
				var queryStr = '?outer_id=' + outerId + '&outer_id_type=' + outerType + '&quantity=' + amount + '&x_id=' + dbNum;

				// fetch setup data in a no-cache way
				YU.Get.script(config.apiAddCart + queryStr, {
					onSuccess: function() {
						// check if they were loaded
						if ('undefined' === typeof TB.Detail.CartResult) {
							return halt('无法加载购物车数据');
						}
						
						// get result
						var result = TB.Detail.CartResult;
						delete TB.Detail.CartResult;

						// exception
						if ('undefined' !== typeof result.error) {
							return halt(result.error);
						} else {
							// update cart
							updateCart(result);
						}
					},
					onFailure: function(){
						return halt('接口访问失败，请重试。');
					},
					timeout: 10000,
					autopurge: true,
					charset: document.charset || document.characterSet || 'gb2312'
				});
			});
		};

		return {
			/**
			 * initialization
			 * @public
			 */
			init: function () {
				// read config
				config = TB.Detail.Setup.getConfig();
				if ('undefined' === typeof config) {
					return false;
				}

				// decoration
				decorate();
			}
		};
	}();

	/**
	 * Combination Handler Module
	 */
	TB.Detail.ComboHandler = function () {
		/**
		 * vars
		 * @private
		 */
		var config = {},
			itemData = [],
			itemLen = 0,
			bitSel = 0;

		/**
		 * calBitVal
		 * @private
		 */
		var calBitVal = function (degree) {
			return Math.round(Math.pow(2, degree));
		};

		/**
		 * calPrice
		 * @private
		 */
		var calPrice = function () {
			// get price item
			var priceNode = (config.valMode & 8) ? config.spanVip : config.strPrice,
				marketNode = config.ulPrice.getElementsByTagName('del')[0],
				promotionNode = config.ulPrice.getElementsByTagName('strong')[0];

			// overwrite the function
			calPrice = function () {
				var itemPrice = parseFloat(priceNode.firstChild.nodeValue),
					itemAmount = parseInt(config.iptAmount.value, 10);
				switch (true) {
				case isNaN(itemPrice):
				case isNaN(itemAmount):
					alert('价格计算失败，请刷新后重试');
					return false;
				}

				// calculate prices
				var marketPrice = 0,
					promotionPrice = 0;

				for (var i = itemLen - 1; 0 <= i; i--) {
					var curData = itemData[i];
					if (bitSel & curData.bit) {
						marketPrice += curData.market;
						promotionPrice += curData.promo;
					}
				}
				marketPrice += (marketPrice + itemPrice) * itemAmount;
				promotionPrice += (promotionPrice + itemPrice) * itemAmount;

				// update them
				marketNode.firstChild.nodeValue = marketPrice.toFixed(2);
				promotionNode.firstChild.nodeValue = promotionPrice.toFixed(2);
			};
			return calPrice();
		};

		/**
		 * decorate
		 * @private
		 */
		var decorate = function (triggers, choices) {
			// shortcut
			itemLen = triggers.length;

			// decorating
			for (var i = itemLen - 1; 0 <= i; i --) {
				// shortcuts
				var curTrigger = triggers[i],
					curBit = calBitVal(i);

				// select it by default
				setTimeout(function () {
					curTrigger.checked = true;
				}, 0);
				bitSel += curBit;

				// build data
				var curData = itemData[i] = {
						id:		curTrigger.value,							// item id
						bit:	curBit,										// bit value
						promo:	parseFloat(curTrigger.getAttribute('data-promotion')),	// promotional value
						market:	parseFloat(curTrigger.getAttribute('data-market'))		// market value
					};

				// mouse behavior
				(function () {
					// shortcuts
					var thisBit = curBit,
						thisTrigger = curTrigger,
						thisChoice = choices[i],
						thisData = curData[i];

					// binding
					YUE.on(curTrigger, 'click', function (evt) {
						// stop events
						YUE.stopEvent(evt);

						// prevent from canceling the last one
						if (thisBit === bitSel) {
							alert('请至少保留一件宝贝');
							return;
						}

						// re calculate the prices
						if (false === calPrice()) {
							return;
						}

						// toggle check status
						if (bitSel & thisBit) {
							bitSel -= thisBit;
							YUD.addClass(thisChoice, 'hidden');
							setTimeout(function () {
								thisTrigger.checked = false;
							}, 0);
						} else {
							bitSel += thisBit;
							YUD.removeClass(thisChoice, 'hidden');
							setTimeout(function () {
								thisTrigger.checked = true;
							}, 0);
						}
					});
				})();
			}

			// elements
			var itemImg = config.ulCombo.getElementsByTagName('img'),
				itemLink = config.ulCombo.getElementsByTagName('a');

			// faking
			if (itemImg.length === itemLink.length) {
				for (var i = itemImg.length - 1; 0 <= i; i --) {
					// mouse behavior
					(function () {
						// shortcuts
						var idx = i,
							curImg = itemImg[idx],
							curLink = itemLink[idx];

						// error on loading
						YUE.on(curImg, 'error', function (evt) {
							curImg.src = './assets/img/blank_80.png';
						});

						// fake clicking
						YUE.on(curLink, 'click', function (evt) {
							// stop events
							YUE.stopEvent(evt);
						});
					})();
				}
			}

			// binding
			YUE.on(config.linkCombo, 'click', function (evt) {
				// stop events
				YUE.stopEvent(evt);

				alert('test');
			});
		};

		return {
			/**
			 * initialization
			 * @public
			 */
			init: function () {
				// read config
				config = TB.Detail.Setup.getConfig();
				if ('undefined' === typeof config) {
					return false;
				}

				// requirements
				var triggers = config.ulCombo.getElementsByTagName('input'),
					choices = config.ulChoice.getElementsByTagName('li');
				if (0 < triggers.length && triggers.length === choices.length) {
					// decoration
					decorate(triggers, choices);
				}
			},
			/**
			 * updatePrice
			 * @public
			 */
			updatePrice: function () {
				return calPrice();
			}
		};
	}();

	/**
	 * Setup Module
	 */
	TB.Detail.Setup = function () {
		/**
		 * vars
		 * @private
		 */
		var config = {};

		/**
		 * launch
		 * @private
		 */
		var launch = function () {
			var mode = config.valMode;

			// safety services
			if (null !== config.liSafety) {
				TB.Detail.SafetyService.init();
			}

			// show vip popup for non-vip
			if (0 === (mode & 8) && null !== config.imgVip && null !== config.valVipPrices) {
				TB.Detail.VipPopup.init();
			}

			// gallery
			if (mode & 32) {
				// gallery mode
				TB.Detail.ThumbViewer.init();
			} else if (null !== config.LinkMagnifier && null !== config.divBooth) {
				// simgle mode
				TB.Detail.ImageViewer.init();
			}

			// cart
			if (mode & 2 && '' !== config.valCartInfo.itemId) {
				TB.Detail.CartHandler.init();
			}

			// combination
			if (mode & 16) {
				TB.Detail.ComboHandler.init();
			}

			// property handler
			if (mode & 1 && 'undefined' !== typeof config.elmProps && 0 < config.elmProps.length) {
				TB.Detail.PropertyHandler.init();
			}
		};

		return {
			/**
			 * initialization
			 * @public
			 */
			init: function (configuration) {
				// read config
				config = configuration || {};
				YL.augmentObject(config, {
					// vip popup
					imgVip:			$('J_ImgVip'),		// VIP图标 ID
					valVipPrices:	null,				// VIP 价格，格式为：'级别名': '价格'；如：{'金卡': '120.00', '白金卡': '110.00', '钻石卡': '100.00'}

					// safety services
					liSafety:		$('J_LiSafety'),	// 包含保障图标的区域 ID

					// gallery
					imgBooth:		$('J_ImgBooth'),	// 预览大图 ID
					ulThumb:		$('J_UlThumb'),		// 小图区域 ID

					// single image
					divBooth:		$('J_DivBooth'),	// 预览大图区域 ID，单图时有效
					LinkMagnifier:	$('J_Magnifier'),	// 放大图片链接 ID，单图时有效
					valImageInfo:	{},					// 图片信息，必须同时设置 4 个属性，分别为：{'linkUrl': '', 'swfVars': '', 'imgUrl': '', 'imgPath': ''}

					// property validation
					strPrice:		$('J_StrPrice'),	// 价格元素 ID
					spanStock:		$('J_SpanStock'),	// 库存元素 ID
					spanVip:		$('J_SpanVip'),		// VIP 价格元素 ID

					// has-sale-property mode
					linkBuy:		$('J_LinkBuy'),		// 立即购买链接
					dlChoice:		$('J_DlChoice'),	// 已选项区域 ID
					iptAmount:		$('J_IptAmount'),	// 购买数量域 ID
					frmBid:			$('J_FrmBid'),		// 购买表单 ID
					valItemInfo:	{},					// 商品信息，包括 oosMap, skuMap, defSelected 和 vipRate，数据格式示例见页面尾部

					// cart-enabled mode
					linkAdd:		$('J_LinkAdd'),		// 添加到购物车链接 ID
					spanCart:		$('J_SpanCart'),	// 购物车商品数量区域 ID
					apiAddCart:		'./assets/testData/cart.php',	// 购物车异步 API
					valCartInfo:	{},					// 购物车信息，包括 itemId 和 dbNum，如：{'linkUrl': '', 'swfVars': '', 'imgUrl': '', 'imgPath': ''}

					// combination mode
					linkCombo:		$('J_LinkCombo'),	// 套餐添加到购物车链接 ID
					ulCombo:		$('J_UlCombo'),		// 套餐内容区域 ID
					ulChoice:		$('J_UlChoice'),	// 套餐内商品已选项区域 ID
					ulPrice:		$('J_UlPrice'),		// 套餐价格区域 ID

					// fast buy mode
					valFastBuy:		'',					// 快速拍链接

					// common
					valMode:		0					// 脚本模式，模式可以叠加：0: 基本模式; 1: 销售属性模式; 2: 购物车模式; 4: 普通店铺模式; 8: VIP 模式; 16: 套餐模式; 32: 多图模式
				});
				// for has-sale-property mode
				if (null !== config.dlChoice) {	// 销售属性模式
					config.valMode += 1;
					config.elmProps = YUD.getElementsByClassName('J_ulSaleProp', 'UL', config.iptAmount.parentNode.parentNode.parentNode);	// 销售属性元素数组
					config.divKeyProp = config.dlChoice.parentNode.parentNode;	// 关键属性区域 ID
				}
				// for cart-enabled mode
				if (null !== config.linkAdd && null !== config.spanCart) {	// 购物车模式
					config.valMode += 2;
					config.linkCart = config.spanCart.parentNode;	// 查看购物车链接 ID
					config.divCart = config.linkCart.parentNode;	// 购物车区域 ID
				}
				// for vip mode
				if (null !== config.spanVip && false === isNaN(config.valItemInfo.vipRate)) {	// VIP 模式
					config.valMode += 8;
				}
				// for combination mode
				if (null !== config.linkCombo && null !== config.ulCombo && null !== config.ulChoice && null !== config.ulPrice) {	// 套餐模式
					config.valMode += 16;
				}
				// for thumbnail mode
				if (null !== config.imgBooth && null !== config.ulThumb) {	// 多图模式
					config.valMode += 32;
				}

				// Ah! began? Let's go...
				launch();
			},
			/**
			 * getConfig
			 * @public
			 */
			getConfig: function () {
				return config;
			}
		};
	}();

})();