/* Popup.js

{{IS_NOTE
	Purpose:
		
	Description:
		
	History:
		Nov 29, 2011 3:05:20 PM , Created by sam
}}IS_NOTE

Copyright (C) 2011 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
}}IS_RIGHT
*/
(function () {

	/**
	 * Returns the cell's position and dimension
	 */
	function getCellPosAndDim (sheet, row, col) {
		//ZSS-805
		var cell = sheet.getCell(row, col),
			l = col,
			r = col,
			t = row,
			b = row;
		
		if (cell) {
			if (cell.merl && cell.merl < l) {
				l = cell.merl;
			}
			if (cell.merr && cell.merr > r) {
				r = cell.merr;
			}
			if (cell.mert && cell.mert < t) {
				t = cell.mert;
			}
			if (cell.merb && cell.merb > b) {
				b = cell.merb;
			}
		}
		
		var topHeight = sheet.topHeight;
		var leftWidth = sheet.leftWidth;
		var custColWidth = sheet.custColWidth;
		var custRowHeight = sheet.custRowHeight;
		var left = custColWidth.getStartPixel(l);
		var top = custRowHeight.getStartPixel(t);
		var right = custColWidth.getStartPixel(r + 1) - 1;
		var btm = custRowHeight.getStartPixel(b + 1) - 1;
		// ZSS-391: the position calculation should consider scroll position
		// ZSS-448: the position calculation should also consider freeze panels
		if (t > sheet.frozenRow) {
			top -= sheet.spcmp.scrollTop;
		}
		if (b > sheet.frozenRow) {
			btm -= sheet.spcmp.scrollTop;
		}
		if (l > sheet.frozenCol) {
			left -= sheet.spcmp.scrollLeft;
		}
		if (r > sheet.frozenCol) {
			right -= sheet.spcmp.scrollLeft;
		}
		var w = right - left + 1;
		var h = btm - top + 1;
		return {'top': top + topHeight, 'left': left + leftWidth, 'bottom': btm + topHeight, 'right': right + leftWidth, 'width': w, 'height': h};
	}

/**
 * Abstract Popup widget
 */
zssex.Popup = zk.$extends(zk.Widget, {
	$o: zk.$void, //owner, fellows relationship no needed
	$init: function (sht) {
		this.$supers(zssex.Popup, '$init', []);
		this.sheet = sht;
	},
	/**
	 * Open the popup
	 */
	open: function () {
		//to be override
	},
	/**
	 * Close the popup
	 */
	close: function () {
		this.setVisible(false);
	}
});
	
zssex.CellPopup = zk.$extends(zssex.Popup, {
	widgetName: 'CellPopup',
	/**
	 * Returns whether the popup is visible.
	 * @return boolean
	 */
	isOpen: function () {
		return this.$n() && this.isVisible();
	},
	open: function (r, c) {
		if (!this.isOpen()) {
			var n = this.$n();
			if (!n) {
				this.createPopup_();
			}
			var info = this.relocate(r, c);
			this.setVisible(true);
			// ZSS-1259
			var spHeight = this.sheet.spcmp.offsetHeight,
				cellt = info.top,
				cellh = info.height,
				poph = this._node.offsetHeight;
			if ((cellt + cellh + poph) > spHeight) {
				jq(this.$n()).css({'top': jq.px(info.top - poph)});
			}
		}
	},
	relocate: function (row, col) {
		var info = getCellPosAndDim(this.sheet, row, col);
		jq(this.$n()).css({'left': jq.px(info.left), 'top': jq.px(info.bottom), 'width': jq.px(info.width)});
		return info;  // ZSS-1259
	},
	createPopup_: function () {
		// ZSS-391: cell popup should be float on top of spreadsheet, or it will be hidden by frozen panel
		jq(this.sheet.$n()).append(this.redrawHTML_());
		this.clearCache();
		this.bind_();
	},
	redrawHTML_: function () {
		return this.prologHTML_() + this.contentHTML_() + this.epilogHTML_();
	},
	contentHTML_: function () {
		return '';
	},
	prologHTML_: function () {
		return '<div ' + this.domAttrs_() + '>';
	},
	epilogHTML_: function () {
		return '</div>';
	},
	listenSheetFocused_: function (b) {
		var cur = !!this._listenSheetFocused;
		if (cur != b) {
			this.sheet[b ? 'listen' : 'unlisten']({'onFocused': this.proxy(this.onSheetFocused)});
			this._listenSheetFocused = b;
		}
	},
	onSheetFocused: function (evt) {
		//to be override
	},
	listenSheetBlur_: function (b) {
		var cur = !!this._listenSheetBlur;
		if (cur != b) {
			this.sheet._wgt[b ? 'listen' : 'unlisten']({'onBlur': this.proxy(this.onSheetBlur)});
			this._listenSheetBlur = b;
		}
	},
	onSheetBlur: function (evt) {
		//to be override
	},
	getZclass: function () {
		return 'zscellpopup';
	}
});

zssex.ValidationPromptPopup = zk.$extends(zssex.CellPopup, {
	widgetName: 'ValidationPromptPopup',
	$init: function (sht, title, text) {
		this.$supers(zssex.ValidationPopup, '$init', arguments);
		this._pos = {}; //current cell position
		this._title = title;
		this._text = text;
	},
	unbind_: function () {
		delete this._pos;
		this._title = this._text = null;
		this.listenSheetFocused_(false);
		this.$supers(zssex.ValidationPromptPopup, 'unbind_', arguments);
	},
	open: function (r, c) {
		if (!this.isOpen()) {
			this.$supers(zssex.ValidationPromptPopup, 'open', arguments);
			if (zk.ie6_ || zk.ie7_ || zk.opera) {
				//TODO: IE6/IE7/Opera shall calculate text width and reset popup's width/height
				jq(this.$n()).addClass('zsdvp-popup');
			}
			//ZSS-198
			var sf = this;
			setTimeout(function () {
				sf.listenSheetFocused_(true);
			});
		}
	},
	close: function () {
		var sf = this;
		setTimeout(function () {
			//close() may invoke during event processing, need unlisten event using timeout 
			sf.listenSheetFocused_(false);
		});
		this.$supers(zssex.ValidationPromptPopup, 'close', arguments);
	},
	//override
	relocate: function (row, col) {
		var maxWidth = 245,
			widthOffset = 3,
			hghOfs = 6,
			$n = jq(this.$n());
		var sheet = this.sheet,
			info = getCellPosAndDim(this.sheet, row, col),
			pos = this._pos;
		pos.row = row;
		pos.col = col;
		$n.css({'left': jq.px(info.right + widthOffset), 'top': jq.px(info.bottom + hghOfs)});
		if (!zk.ie6_ && !zk.ie7_) {
			var curWidth = zk.parseInt($n.width());
			if (curWidth > maxWidth) {
				$n.width(jq.px(maxWidth));
			}	
		}
		return info; // ZSS-1259
	},
	onSheetFocused: function (evt) {
		var d = evt.data,
			p = this._pos,
			col = d.col,
			row = d.row;
		if (p.row != row || p.col != col) {
			this.close();
		}
	},
	//override
	contentHTML_: function () {
		var uid = this.uuid,
			title = this._title,
			text = this._text;
		return '<div id="' + uid + '-cave" class="zsdvp-popup-cave"><div id="' + uid + '-title" class="zsdvp-title">' + (title ? title : '') + 
			'</div><div id="' + uid + '-text" class="zsdvp-text">' + (text ? text : '') + '</div></div>';
	}
});

	function focusOnValidationTextItem (n) {
		if (n.tagName.toLowerCase() == 'a') {
			return n;
		}
		var chd = n.firstChild;
		return chd && chd.tagName.toLowerCase() == 'a' ? chd : null;
	}
	
	/**
	 * Display cell focus but won't change sheet's state
	 */
	function fakeCellFocus(row, col, sheet) {
		var orgState = sheet.state;
		sheet.state = zss.SSheetCtrl.FOCUSED;
		sheet.moveCellFocus(row, col, true);
		sheet.moveCellSelection(col, row, col, row, false, true);
		sheet.state = orgState;
	}
	
zssex.ValidationPopup = zk.$extends(zssex.CellPopup, {
	widgetName: 'ValidationPopup',
	$init: function (sht) {
		this.$supers(zssex.ValidationPopup, '$init', arguments);
		this._pos = {}; //current cell position
		this._validationList = [];
	},
	bind_: function () {
		this.$supers(zssex.ValidationPopup, 'bind_', arguments);
		
		var size = this._validationList.length,
			n = this.$n();
		if (n) {
			if (size >= 8) {
				jq(n).css({'overflow': 'auto', 'height': '155px'});
			} else
				jq(n).css({'overflow': 'hidden', 'height': ''});
		}
	},
	unbind_: function () {
		delete this._pos;
		delete this._validationList;
		this.listenSheetBlur_(false);
		this.listenSheetFocused_(false);
		this.$supers(zssex.ValidationPopup, 'unbind_', arguments);
	},
	_markSelectedItem: function (row, col) {
		var sheet = this.sheet,
			val = sheet.getCell(row, col).getPureText(),
			item = this.$n('cave').firstChild;
		if (item) {
			for (; item; item = item.nextSibling) {
				var $t = jq(item.firstChild),
					t = $t.text();
				jq(item)[val == t ? 'addClass' : 'removeClass']('zsdv-item-over');
			}
		}
	},
	open: function (r, c) {
		if (this.isOpen()) {
			this.close();
		} else {
			this.$supers(zssex.ValidationPopup, 'open', arguments);
			this._markSelectedItem(r, c);
			this.listenSheetBlur_(true);
			this.listenSheetFocused_(true);
		}
	},
	close: function () {
		var sf = this;
		setTimeout(function () {
			sf.listenSheetBlur_(false);
			sf.listenSheetFocused_(false);
			sf.sheet.dp.gainFocus(false);
		});
		this.$supers(zssex.ValidationPopup, 'close', arguments);
	},
	//override
	onSheetFocused: function (evt) { //skip the first focus evt, since
		this.close();
	},
	//override
	relocate: function (row, col) {
		var sheet = this.sheet,
			info = getCellPosAndDim(this.sheet, row, col),
			btnWidth = 17,
			width = info.width + btnWidth,
			left = info.right + btnWidth - width,
			pos = this._pos;
		pos.row = row;
		pos.col = col;
		jq(this.$n()).css({'left': jq.px(left), 'top': jq.px(info.bottom), 'width': jq.px(width)});
		return info; // ZSS-1259
	},
	setValidationList: function (list) {
		var l = this._validationList,
			size = list.length,
			i = size;
		l.splice(0, l.length); //clear array
		while (i--) {
			l[i] = list[i];
		}
		
		var n = this.$n();
		if (n) {
			if (size >= 8) {
				jq(n).css({'overflow': 'auto', 'height': '155px'});
			} else
				jq(n).css({'overflow': 'hidden', 'height': ''});
		}
	},
	//override
	contentHTML_: function () {
		var uid = this.uuid,
			html = '<ul id="' + uid + '-cave" class="zsdv-popup-cave">',
			list = this._validationList,
			size = list.length;
		for (var i = 0; i < size; i++) {
			html += '<li class="zsdv-item"><a href="javascript:" class="zsdv-item-text">' + list[i] + '</a></li>';
		}
		html += '</ul><a id="' + uid + '-fo" href="javascript:"></a>';
		return html;
	},
	_editCell: function (row, col, val) {
		var sheet = this.sheet,
			orgVal = sheet.getCell(row, col).getPureText();
		if (orgVal != val) {
				var orgState = sheet.state;
			if (sheet.state != zss.SSheetCtrl.START_EDIT) {
				sheet.state = zss.SSheetCtrl.START_EDIT;
				sheet._wgt.fire('onStartEditing',
						{token: "", sheetId: sheet.serverSheetId, row: row, col: col, clienttxt: val, type: 'inlineEditing'}, null, 25);
			}
			sheet.state = orgState;
			sheet._wgt.fire('onStopEditing',
					{token: "", sheetId: sheet.serverSheetId, row: row, col: col, value: val, type: 'inlineEditing'}, {toServer: true}, 25);
		}
	},
	//override
	onSheetBlur: function () {
		if (this.isOpen()) {
			var seld = jq(this.$n()).find('.zsdv-item-over'),
				p = this._pos
				row = p.row,
				col = p.col;
			if (seld.length) {
				jq(seld[0].firstChild).focus();
			} else {
				jq(this.$n('fo')).focus();
			}
			fakeCellFocus(p.row, p.col, this.sheet);
		}
	},
	doMouseOver_: _zkf = function (evt) {
		var t = focusOnValidationTextItem(evt.domTarget);
		if (t) {
			var $prevSeld = jq(this.$n()).find('.zsdv-item-over');
			if ($prevSeld.length) {
				$prevSeld.removeClass('zsdv-item-over');
			}
			jq(t.parentNode).addClass('zsdv-item-over');
		}
	},
	doMouseMove_: _zkf,
	doKeyPress_: function (evt) {
		//do nothing. eat the event.
	},
	doMouseDown_: function (evt) {
		var	n = focusOnValidationTextItem(evt.domTarget);
		if (n) {
			var p = this._pos;
			this._editCell(p.row, p.col, jq(n).text());
			this.close();
		}
	},
	doKeyDown_: function (evt) {
		//move selection
		var keycode = evt.keyCode,
			f = document.activeElement == this.$n('fo'),
			$prevSeld = null,
			sel = null;
		switch (keycode) {
		case 38: //UP
		case 40: //DOWN
			if (f) {
				sel = this.$n('cave').firstChild;
			} else {
				$prevSeld = jq(this.$n()).find('.zsdv-item-over');
				if ($prevSeld.length) {
					sel = keycode == 38 ? $prevSeld[0].previousSibling : $prevSeld[0].nextSibling;
				}
			}
			if (sel) {
				jq(sel).addClass('zsdv-item-over');
				jq(sel.firstChild).focus();
			}
			if (sel && $prevSeld) {
				$prevSeld.removeClass('zsdv-item-over');
			}
			break;
		case 13: //Enter
			var $seld = jq(this.$n()).find('.zsdv-item-over');
			if ($seld.length) {
				var p = this._pos;
				this._editCell(p.row, p.col, jq($seld[0]).text());
			}
			this.close();
			break;
		case 27: //ESC
			this.close();
			break;
		}
		evt.stop();
	}
});

	function getFilterItemNode (elm) {
		var $n = jq(elm);
		return $n.hasClass('zsafp-item') ? 
				$n[0] : $n.hasClass('zsafp-item-checkbox') || (zk.ie6_ && $n.hasClass('zsafp-item-text')) ? $n[0].parentNode : null;
	}

	function markFilterItemOver (n) {
		if (n == null) 
			return;
		var p = n.parentNode,
			chd = p.firstChild;
		for ( ; chd; chd = chd.nextSibling) {
			if (chd != n)
				jq(chd).removeClass('zsafp-item-over');
		}
		jq(n).addClass('zsafp-item-over');
	}
	
	//ZSS-1191
	function getFilterCCItemNode (elm) {
		var $n = jq(elm);
		var $p = jq(elm.parentNode);
		return $n.hasClass('zsafp-ccitem') ? $n[0] : $p.hasClass('zsafp-ccitem') ? $p[0] : null;
	}
	//ZSS-1191
	function getFilterFCItemNode (elm) {
		var $n = jq(elm);
		var $p = jq(elm.parentNode);
		return $n.hasClass('zsafp-fcitem') ? $n[0] : $p.hasClass('zsafp-fcitem') ? $p[0] : null;
	}
	//ZSS-1191
	function getColorFilterOption (elm) {
		var $n = jq(elm);
		var $p = jq(elm.parentNode);
		return $n.hasClass('zsafp-color') ? $n[0] : $p.hasClass('zsafp-color') ? $p[0] : null;
	}
	
	//ZSS-1191
	function showSubDlg (elm) {
		var colordlg = jq(elm);
		if (colordlg != null) {
			jq(colordlg).css("display", "inline-block");
		}
	}
	//ZSS-1191
	function hideSubDlg (elm) {
		var colordlg = jq(elm);
		if (colordlg != null) {
			jq(colordlg).css("display", "none");
		}
	}

	//ZSS-1192
	function getFilterVItemNode (elm) {
		var $n = jq(elm);
		var $p = jq(elm.parentNode);
		return $n.hasClass('zsafp-vitem') ? $n[0] : $p.hasClass('zsafp-vitem') ? $p[0] : null;
	}
	//ZSS-1192
	function getValueFilterOption (elm) {
		var $n = jq(elm);
		var $p = jq(elm.parentNode);
		return $n.hasClass('zsafp-value') ? $n[0] : $p.hasClass('zsafp-value') ? $p[0] : null;
	}
	//ZSS-1195
	function getFilterClearNode (elm) {
		var $n = jq(elm);
		var $p = jq(elm.parentNode);
		return $n.hasClass('zsafp-clear') 
				&& !$n.hasClass('zsafp-clear-disabled') ? $n[0] : 
					$p.hasClass('zsafp-clear') 
						&& !$p.hasClass('zsafp-clear-disabled') ? $p[0] : null;
	}
	//ZSS-1234
	function getDatesInPeriodNode (elm) {
		var $n = jq(elm);
		var $p = jq(elm.parentNode);
		return $n.hasClass('zsafp-vitem-inp') ? $n[0] : $p.hasClass('zsafp-vitem-inp') ? $p[0] : null;
	}
	
//See AutoFilterDefaultHandler.java
zssex.AutoFilterPopup = zk.$extends(zssex.CellPopup, {
	$init: function (sht, afp) {
		this.$supers(zssex.AutoFilterPopup, '$init', arguments);
		this._pos = {};
		this._field = afp.field;
		this._rangeAddr = afp.range;
		this._blank = afp.blank;
		this._select = afp.select; //'all', 'mix' or 'none'
		this._initItems(afp.items, afp.select, afp.blank);
		this.setVisible(false);
		
		//ZSS-1191
		this._ccitems = afp.ccitems; // "t": "No Fill"; "bk": "background: #rrggbb"; "pat": "SOLID"; "fg": "#rrggbb"; "bg": "#rrggbb";
		this._fcitems = afp.fcitems; // "t": "Automatic"; "bk": "background: #rrggbb"; "pat": "SOLID"; "fg": "#rrggbb"; "bg": "#rrggbb";
		this._colorpat = afp.colorpat;
		this._colorfg = afp.colorfg;
		this._colorbg = afp.colorbg;
		this._type = afp.type; //1: Date, 2: Number, 3: Text
		
		//ZSS-1192
		this._vitems = afp.vitems; //{op:"equal", t:"equals"}, {op:"notEqual", t:"does not equal"}, ...
		this._vitem = afp.vitem; //null or one of "equal", "notEqual", ...
		
		//ZSS-1234
		this._pitems = afp.pitems; // datesInPeriod options
		this._pitem = afp.pitem; // selected option in datesInPeriod
		this._dynaf = afp.dynaf; // whether SDynamicFilter exists
		
		//ZSS-1193: SDynamicFilter
		this._avgVal = afp.avgVal;
		this._isAbove = afp.isAbove;
		
		//ZSS-1193: STop10Filter 
		this._filterVal = afp.filterVal;
		this._isTop = afp.isTop;
		this._isPercent = afp.isPercent;
		this._countVal = afp.countVal;
		
		//ZSS-1195
		this._colName = afp.colName;
	},
	_initItems: function (items, select, blank) {
		var dstItems = this._items = [{v: zssex.AutoFilterPopup.SELECT_ALL, s: select}], //ZSS-1239
			size = items.length;
		for (var i = 0; i < size; i++) {
			dstItems.push(items[i]);
		}
		if (blank != undefined) {
			dstItems.push({v:zssex.AutoFilterPopup.BLANK, s: blank});
		}
	},
	unbind_: function () {
		delete this._pos;
		delete this._items;
		delete this._$is;
		this.listenSheetFocused_(false);
		var inp = this.$n('inp');
		this.domUnlisten_(inp, 'onKeyDown', this._onFilterKeyDown);
		this.domUnlisten_(inp, 'onKeyUp', this._onFilterKeyUp);
		this.$supers(zssex.AutoFilterPopup, 'unbind_', arguments);
	},
	open: function (r, c) {
		if (this.isOpen()) {
			this.close();
		} else {
			this.$supers(zssex.AutoFilterPopup, 'open', arguments);
			var inp = this.$n('inp'),
				select = this._select,
				$sel = jq(this._$items()[0]);
			inp.focus(); // Always focus on filter editor, so widget can receive key event
			this.sheet.state = zss.SSheetCtrl.NOFOCUS;
			
			this.domListen_(inp, 'onKeyDown', this._onFilterKeyDown);
			this.domListen_(inp, 'onKeyUp', this._onFilterKeyUp);
			if ('all' == select) {
				$sel.addClass('zsafp-item-seld');
			} else if ('mix' == select) {
				$sel.removeClass('zsafp-item-seld').addClass('zsafp-item-seld-mix'); //1092: contentHTML_() will put zsafp-item-seld in mix mode 
			}
			this.listenSheetFocused_(true);
		}
	},
	//ZSS-1191
	_$ccitems: function () {
		if (!this._$ccis) {
			this._$ccis = jq(this.$n('ccitems')).children();
		}
		return this._$ccis;
	},
	//ZSS-1191
	_$fcitems: function () {
		if (!this._$fcis) {
			this._$fcis = jq(this.$n('fcitems')).children();
		}
		return this._$fcis;
	},
	//ZSS-1192
	_$vitems: function () {
		if (!this._$vis) {
			this._$vis = jq(this.$n('vitems')).children();
		}
		return this._$vis;
	},
	//ZSS-1234
	_$pitems: function () {
		if (!this._$pis) {
			this._$pis = jq(this.$n('pitems')).children();
		}
		return this._$pis;
	},
	_$items: function () {
		if (!this._$is) {
			this._$is = jq(this.$n('items')).children();
		}
		return this._$is;
	},
	_onFilterKeyDown: function (evt) {
		this._prevFilterVal = evt.domTarget.value;
	},
	_onFilterKeyUp: function (evt) {
		var inpVal = evt.domTarget.value.toLowerCase(),
			reEvalHidden = this._prevFilterVal.length > inpVal.length,
			$chd = this._$items(),
			all = true,
			select = false,
			items = this._items,
			pop = this;
		pop._filtered = inpVal.length > 0; 
		$chd.each(function (index, n) {
			var $n = jq(n);
			if (index == 0) { //ZSS-1050: SELECT_ALL should be hidden filter
				if (pop._filtered) {
					$n.addClass('zsafp-item-hide');
					items[0].h = true;
				} else {
					$n.removeClass('zsafp-item-hide');
					delete items[0].h;
				}
			} else if (reEvalHidden) {
				if ($n.hasClass('zsafp-item-hide')) {
					if ($n.text().toLowerCase().indexOf(inpVal) >= 0) {
						$n.removeClass('zsafp-item-hide');
						delete items[index].h; //ZSS-1050: unmark hidden
					}
				}
				//ZSS-1050: handle selectAll state
				if (!items[index].h) { // handle only those un-hiddened
					if (pop._filtered || items[index].s) {
						$n.addClass('zsafp-item-seld');
						select = true;
					} else {
						$n.removeClass('zsafp-item-seld');
						all = false;
					}
				}
			} else {
				if ($n.text().toLowerCase().indexOf(inpVal) < 0) {
					$n.addClass('zsafp-item-hide');
					items[index].h = true; //ZSS-1050: mark hidden
					all = false; //ZSS-1050: handle selectAll state
				} else { //match item
					if (pop._filtered || items[index].s) {
						$n.addClass('zsafp-item-seld');
						select = true; //ZSS-1050: handle selectAll state
					} else {
						$n.removeClass('zsafp-item-seld');
					}
				}
			}
		});
		//ZSS-1050
		var $okBtn = jq(this.$n('okBtn'));
		if (all) {
			items[0].s = 'all';
			$okBtn.removeClass('zsafp-btn-disd');
		} else if (select) {
			items[0].s = 'mix';
			$okBtn.removeClass('zsafp-btn-disd');
		} else {
			items[0].s = 'none';
			$okBtn.addClass('zsafp-btn-disd');
		}
		
		//ZSS-1191
		hideSubDlg(this.$n('colordlg'));
		//ZSS-1192
		hideSubDlg(this.$n('valuedlg'));
		//ZSS-1234
		hideSubDlg(this.$n('perioddlg'));
	},
	close: function () {
		var sf = this;
		setTimeout(function () {
			sf.listenSheetFocused_(false);
			sf.sheet.dp.gainFocus(false);
		});
		this.$supers(zssex.AutoFilterPopup, 'close', arguments);
		this.detach();
		delete this._filtered; //ZSS-1050: remove the state
	},
	//override
	contentHTML_: function () {
		var uid = this.uuid,
			items = this._items,
			size = items.length,
			colorpat = this._colorpat, //ZSS-1191
			type = this._type, //ZSS-1192
			vitem = this._vitem, //ZSS-1192
			html = '<div class="zsafp-popup-cave">';
		
		//ZSS-1191
		var withCellColor = (this._ccitems && this._ccitems.length > 1),
			withFontColor = (this._fcitems && this._fcitems.length > 1), 
			withColorDlg = withCellColor || withFontColor;
		
		//ZSS-1195
		var withFilter = withColorDlg || vitem || this._select != "all";
		
		html += '<div class="zsafp-itemsdlg">';
		//ZSS-1195
		//clear filter for a column
		html += '<div class="zsafp-clear ' + (withFilter ? '' : ' zsafp-clear-disabled') + '"><div class="'+ (withFilter ? 'zsafp-clear-seld ' : ' ') + 'zsafp-clear-icon"></div>' +
				'Clear Filter From "' + this._colName + '"' + 
				'</div>';
		
		//ZSS-1191
		//color filter
		html += '<div class="zsafp-color ' + (withColorDlg ? '' : ' zsafp-color-disabled') + '"><div class="'+ (colorpat ? 'zsafp-color-seld ' : ' ') + 'zsafp-color-checkbox"></div>' +
				'Filter by Color' +
				'<div class="zsafp-color-more"></div></div>';
		
		//ZSS-1192
		//value filter
		html += '<div class="zsafp-value"><div class="' + (vitem ? 'zsafp-value-seld ' : ' ') + 'zsafp-value-checkbox"></div>' + 
				(type == 1 ? 'Date' : type == 2 ? 'Number' : 'Text') + ' Filters' +
				'<div class="zsafp-value-more"></div></div>';
		
		//search
		html += '<div class="zsafp-search"><div class="zsafp-search-cnt">' + 
		 		'<input id="' + uid + '-inp" class="zsafp-search-inp" type="text" autocomplete="off" tabindex="0"></input>' + 
		 		'<div class="zsafp-search-icon"></div></div></div>';
		//items
		html += '<div id="' + uid + '-items" class="zsafp-items">';
		for (var i = 0; i < size; i++) {
			var item = items[i];
			var checkbox = !item.s || item.s == 'none' ? '' : item.s == 'mix' ? ' zsafp-item-seld-mix' : ' zsafp-item-seld'; //ZSS-1234
			html += '<div class="zsafp-item' + checkbox + '"><div class="zsafp-item-checkbox"></div>';
			if (zk.ie6_) {
				html += '<div class="zsafp-item-text">' + item.v + '</div></div>';
			} else {
				html += (item.v + '</div>');
			}
		}
		
		html += '</div>'; // items
		
		//buttons
		html += '<div id="' + uid + '-btns" class="zsafp-btns">' + 
		'<div id="' + uid + '-okBtn" class="zsafp-btn zsafp-ok-btn"></div><div id="' + uid + '-cancelBtn" class="zsafp-btn zsafp-cancel-btn"></div></div>';
		html += '</div>'; // itemsdlg
		
		//ZSS-1191
		//colordlg
		if (withColorDlg) {
			html += '<div id="' + uid + '-colordlg" class="zsafp-colordlg">';
			if (withCellColor) {
				//Filter by Cell Color
				html += '<div class="zsafp-colordlg-title">Filter by Cell Color</div>' +
						'<div id="' + uid + '-ccitems" class="zsafp-ccitems">';
				var ccsize = this._ccitems ? this._ccitems.length : 0;
				for (var i = 0; i < ccsize; ++i) {
					var ccitem = this._ccitems[i];
					html += '<div class="zsafp-ccitem' + (ccitem.s ? ' zsafp-ccitem-seld' : '') + '"><div class="zsafp-ccitem-checkbox"></div>';
					html += '<div class="zsafp-ccitem-fill"' + (ccitem.bk ? ' style="' + ccitem.bk + '">' : '>') + ccitem.t + '</div></div>';
				}
				html += "</div>"; // ccitems
			}
			if (withFontColor) {
				//Filter by Font Color
				html += '<div class="zsafp-colordlg-title">Filter by Font Color</div>' +
						'<div id="' + uid + '-fcitems" class="zsafp-fcitems">';
				var fcsize = this._fcitems ? this._fcitems.length : 0;
				for (var i = 0; i < fcsize; ++i) {
					var fcitem = this._fcitems[i];
					html += '<div class="zsafp-fcitem' + (fcitem.s ? ' zsafp-fcitem-seld' : '') + '"><div class="zsafp-fcitem-checkbox"></div>';
					html += '<div class="zsafp-fcitem-fill"' + (fcitem.bk ? ' style="' + fcitem.bk + '">' : '>') + fcitem.t + '</div></div>';
				}
				html += "</div>"; // fcitems
			}
			html += "</div>"; // colordlg
		}
		
		//ZSS-1192
		html += '<div id="' + uid + '-valuedlg" class="zsafp-valuedlg">';
		//vitems: type: 1: date, 2: number, 3: string
		html += '<div id="' + uid + '-vitems" class="zsafp-vitems">'; 
		var vsize = this._vitems ? this._vitems.length : 0;
		for (var i = 0; i < vsize; ++i) {
			var vitem = this._vitems[i];
			if (vitem.op == "allDatesInPeriod") { //ZSS-1234
				html += '<div class="zsafp-vitem zsafp-vitem-inp' + (vitem.b ? ' zsafp-vitem-border' : '') +
				(vitem.s ? ' zsafp-vitem-seld' : '') + '"><div class="zsafp-vitem-checkbox"></div>' +
				(vitem.t + '<div class="zsafp-vitem-inp-more"></div></div>');
			} else {
				html += '<div class="zsafp-vitem' + (vitem.b ? ' zsafp-vitem-border' : '') +
						(vitem.s ? ' zsafp-vitem-seld' : '') + '"><div class="zsafp-vitem-checkbox"></div>' +
						(vitem.t + '</div>');
			}
		}
		html += "</div>"; // vitems
		html += "</div>"; // valuedlg
		
		//ZSS-1234
		html += '<div id="' + uid + '-perioddlg" class="zsafp-perioddlg zsafp-vitem-inp">';
		html += '<div id="' + uid + '-pitems" class="zsafp-vitems zsafp-vitem-inp">'; 
		var psize = this._pitems ? this._pitems.length : 0;
		for (var i = 0; i < psize; ++i) {
			var pitem = this._pitems[i];
			html += '<div class="zsafp-vitem zsafp-vitem-inp' + (pitem.b ? ' zsafp-vitem-border' : '') +
					(pitem.s ? ' zsafp-vitem-seld' : '') + '"><div class="zsafp-vitem-checkbox"></div>' +
					(pitem.t + '</div>');
		}
		html += "</div>"; // pitems
		html += "</div>"; // perioddlg
		
		html += '</div>'; // cave
		return html;
	},
	onSheetFocused: function (evt) {
		this.close();
	},
	//override
	relocate: function (row, col) {
		var $n = jq(this.$n());
		if ((zk.ie6_ || zk.ie7_) && !$n.width()) {
			$n.addClass('zsafp-popup');
		}
		var sheet = this.sheet,
			leftWidth = sheet.leftWidth,
			info = getCellPosAndDim(this.sheet, row, col),
			left = Math.max(leftWidth, info.right - zk.parseInt($n.width()));
		jq(this.$n()).css({'left': jq.px(left), 'top': jq.px(info.bottom),
			//ZSS-1191
			'border': "none", 'box-shadow': "none", 'background': "transparent",
			'overflow': "visible"});
		return info; // ZSS-1259
	},
	doMouseOver_: function (evt) {
		var itemNode = getFilterItemNode(evt.domTarget);
		if (itemNode != null) {
			markFilterItemOver(itemNode);
			hideSubDlg(this.$n('colordlg')); //ZSS-1191
			hideSubDlg(this.$n('valuedlg')); //ZSS-1192
			hideSubDlg(this.$n('perioddlg')); //ZSS-1234
			return;
		}
		
		//ZSS-1191
		var colorOptionNode = getColorFilterOption(evt.domTarget);
		if (colorOptionNode != null) {
			hideSubDlg(this.$n('valuedlg')); //ZSS-1192
			hideSubDlg(this.$n('perioddlg')); //ZSS-1234
			showSubDlg(this.$n('colordlg'));
		}
		
		//ZSS-1192
		var valueOptionNode = getValueFilterOption(evt.domTarget);
		if (valueOptionNode != null) {
			hideSubDlg(this.$n('colordlg'));
			showSubDlg(this.$n('valuedlg'));
		}
		
		//ZSS-1234
		var datesInPeriodOptionNode = getDatesInPeriodNode(evt.domTarget);
		if (datesInPeriodOptionNode != null) {
			showSubDlg(this.$n('perioddlg'));
		} else {
			hideSubDlg(this.$n('perioddlg'));
		}
	},
	doMouseMove_: function (evt) {
		//do nothing. eat the event. 
	},
	_selectNone: function () {
		var items = this._items,
			$item = this._$items(),
			i = items.length;
		while (i--) {
			var item = items[i],
				prev = item.s,
				$n = jq($item[i]);
			if (i == 0) {
				item.s = 'none';
				var $okBtn = jq(this.$n('okBtn'));
				if ('mix' == prev) {
					$n.removeClass('zsafp-item-seld-mix');
					$okBtn.addClass('zsafp-btn-disd');
				} else if ('all' == prev) {
					$n.removeClass('zsafp-item-seld');
					$okBtn.addClass('zsafp-btn-disd');
				}
			} else {
				item.s = false;
				if (prev)
					$n.removeClass('zsafp-item-seld');
			}
		}
	},
	_selectAll: function () {
		var items = this._items,
			$item = this._$items(),
			i = items.length;
		while (i--) {
			var item = items[i],
				prev = item.s,
				$n = jq($item[i]);
			if (i == 0) {
				item.s = 'all';
				if ('mix' == prev) {
					$n.removeClass('zsafp-item-seld-mix').addClass('zsafp-item-seld');
				} else if ('none' == prev) {
					$n.addClass('zsafp-item-seld');
					jq(this.$n('okBtn')).removeClass('zsafp-btn-disd');
				}
			} else {
				item.s = true;
				if (!prev)
					$n.addClass('zsafp-item-seld');
			}
		}
	},
	_isSelectAll: function () {
		return 'all' == this._items[0].s || this._clearFilter;
	},
	_isSelectNone: function () {
		return 'none' == this._items[0].s;
	},
	_updateSelectAllItem: function () {
		var items = this._items,
			i = items.length,
			all = true,
			select = false,
			prev = this._items[0].s;
		while (i--) {
			var item = items[i];
			if (i == 0) {
				var $n = jq(this._$items()[0]);
				if (all) {
					$n.addClass('zsafp-item-seld');
					item.s = 'all';
				} else if (select) {
					$n.addClass('zsafp-item-seld-mix');
					item.s = 'mix';
				} else {
					item.s = 'none';
					jq(this.$n('okBtn')).addClass('zsafp-btn-disd');
				}
				if (prev != item.s) {
					if ('all' == prev)
						$n.removeClass('zsafp-item-seld');
					else if ('mix' == prev) {
						$n.removeClass('zsafp-item-seld-mix');
					} else { //none
						jq(this.$n('okBtn')).removeClass('zsafp-btn-disd');
					}
				}
			} else {
				//ZSS-1050: filtered none-hidden item is always deemed as selected
				if ((this._filtered && !item.h) || (!this._filtered && item.s)) { 
					select = true;
				} else {
					all = false;
				}
			}
		}
	},
	//ZSS-1193
	_showTop10Filter: function () {
		this.sheet._wgt.fireSheetAction('top10Filter', {op: (this._vitem0 == null ? null : this._vitem0.op), field: this._field});
	},
	//ZSS-1192
	_showCustomFilters: function () {
		this.sheet._wgt.fireSheetAction('customFilters', {op: (this._vitem0 == null ? null : this._vitem0.op), field: this._field});
	},
	//ZSS-1192
	_clickVItem: function (itemNode) {
		this._clickVItem0(this._vitems, this._$vitems()[0], itemNode);
		//ZSS-1234
		if (this._vitem0 == null) {
			this._clickVItem0(this._pitems, this._$pitems()[0], itemNode);
		}
	},
	//ZSS-1234
	_clickVItem0: function (items, n, itemNode) {
		var length = items.length,
			i = 0;
		this._vitem0 = null;
		for (; n; n = n.nextSibling, i++) {
			if (n == itemNode) {
				this._vitem0 = items[i];
				break;
			}
		}
	},
	//ZSS-1195
	_clickClear: function () {
		this._ccitem = null;
		this._fcitem = null;
		this._vitem0 = null;
		this._clearFilter = true;
	},
	//ZSS-1191
	_clickCCItem: function (itemNode) {
		var items = this._ccitems,
			length = items.length,
			i = 0,
			n = this._$ccitems()[0];
		this._ccitem = null;
		for (; n; n = n.nextSibling, i++) {
			if (n == itemNode) {
				this._ccitem = items[i];
				break;
			}
		}
	},
	//ZSS-1191
	_clickFCItem: function (itemNode) {
		var items = this._fcitems,
			length = items.length,
			i = 0,
			n = this._$fcitems()[0];
		this._fcitem = null;
		for (; n; n = n.nextSibling, i++) {
			if (n == itemNode) {
				this._fcitem = items[i];
				break;
			}
		}
	},
	_clickItem: function (itemNode) {
		var items = this._items,
			length = items.length,
			i = 0,
			updateSelectAll = false,
			n = this._$items()[0];
		for (; n; n = n.nextSibling, i++) {
			if (n == itemNode) {
				var item = items[i];
				if (i == 0) {
					var	prev = item.s;
					if ('all' == prev) {
						this._selectNone();
					} else if ('mix' == prev || 'none' == prev) {
						this._selectAll();
					}
				} else {
					updateSelectAll = true;
					jq(itemNode)[item.s ? 'removeClass' : 'addClass']('zsafp-item-seld');
					item.s = !item.s;
				}
				break;
			}
		}
		if (updateSelectAll) {
			this._updateSelectAllItem();
		}
	},
	_isButton: function (n) {
		var okBtn = this.$n('okBtn'),
			cancelBtn = this.$n('cancelBtn');
		if (zUtl.isAncestor(okBtn, n)) {
			return 'ok';
		} else if (zUtl.isAncestor(cancelBtn, n)) {
			return 'cancel';
		}
	},
	doMouseDown_: function (evt) {
		var target = evt.domTarget,
			btn = this._isButton(target);
		if (btn) {
			if ('ok' == btn) {
				if (!this._isSelectNone()) {
					this._applyFilter();
					this.close();
				}
			} else if ('cancel' == btn) {
				this.close();
			}
			return;
		}
		
		//ZSS-1195
		var clearNode = getFilterClearNode(target);
		if (clearNode) {
			this._clickClear();
			this._applyFilter();
			this.close();
			return;
		}
		
		//ZSS-1191
		var ccitemNode = getFilterCCItemNode(target);
		if (ccitemNode) {
			this._clickCCItem(ccitemNode);
			this._applyFilter();
			this.close();
			return;
		}

		//ZSS-1191
		var fcitemNode = getFilterFCItemNode(target);
		if (fcitemNode) {
			this._clickFCItem(fcitemNode);
			this._applyFilter();
			this.close();
			return;
		}
		
		//ZSS-1192
		var vitemNode = getFilterVItemNode(target);
		if (vitemNode) {
			this._clickVItem(vitemNode);
			//ZSS-1193, ZSS-1234: SDynamicFilter
			var apply = 
				(this._vitem0.op == "aboveAverage" 
				|| this._vitem0.op == "belowAverage"
				//ZSS-1234
				|| this._vitem0.op == "tomorrow" 
				|| this._vitem0.op == "today"
				|| this._vitem0.op == "yesterday"
				|| this._vitem0.op == "nextWeek"
				|| this._vitem0.op == "thisWeek"
				|| this._vitem0.op == "lastWeek"
				|| this._vitem0.op == "nextMonth"
				|| this._vitem0.op == "thisMonth"
				|| this._vitem0.op == "lastMonth"
				|| this._vitem0.op == "nextQuarter"
				|| this._vitem0.op == "thisQuarter"
				|| this._vitem0.op == "lastQuarter"
				|| this._vitem0.op == "nextYear"
				|| this._vitem0.op == "thisYear"
				|| this._vitem0.op == "lastYear"
				|| this._vitem0.op == "yearToDate"
				|| this._vitem0.op == "Q1"
				|| this._vitem0.op == "Q2"
				|| this._vitem0.op == "Q3"
				|| this._vitem0.op == "Q4"
				|| this._vitem0.op == "M1"
				|| this._vitem0.op == "M2"
				|| this._vitem0.op == "M3"
				|| this._vitem0.op == "M4"
				|| this._vitem0.op == "M5"
				|| this._vitem0.op == "M6"
				|| this._vitem0.op == "M7"
				|| this._vitem0.op == "M8"
				|| this._vitem0.op == "M9"
				|| this._vitem0.op == "M10"
				|| this._vitem0.op == "M11"
				|| this._vitem0.op == "M12");
			if (apply) {
				this._applyFilter();
			} else if (this._vitem0.op == "top10") { //ZSS-1193: STop10Filter
				this._showTop10Filter();
			} else {
				this._showCustomFilters();
			}
			this.close();
			return;
		}
		
		var itemNode = getFilterItemNode(target),
			f = this.$n('inp');
		if (itemNode) {
			this._clickItem(itemNode);
		}
		
		setTimeout(function () {
			f.focus();
		}, 0)
	},
	doKeyPress_: function (evt) {
		//do nothing. eat the event.
	},
	_getCriteria: function () {
		var ret = [],
			items = this._items,
			size = items.length,
			lastIdx = size - 1,
			blank = this._blank;
		for (var i = 1; i < size; i++) {
			var item = items[i];
			if (i == lastIdx && blank != undefined) { //selected blank
				//ZSS-1050: filtered none-hidden item is always deemed as selected
				if ((this._filtered && !item.h) || (!this._filtered && item.s)) 
					ret.push('=');
			} else {
				//ZSS-1050: filtered none-hidden item is always deemed as selected
				if ((this._filtered && !item.h) || (!this._filtered && item.s)) 
					ret.push(item.v);
			}
		}
		return ret;
	},
	_applyFilter: function () { //see FilterCommand.java
		var	data = {type: 'apply', field: this._field, range: this._rangeAddr};
		//ZSS-1191
		if (this._ccitem) { // op == cell_color
			data.op = "cellColor";
			data.all = false;
			var ret = [];
			ret.push(this._ccitem.pat);
			if (this._ccitem.pat == "SOLID") {
				ret.push(this._ccitem.bg);
				ret.push(this._ccitem.fg);
			} else {
				ret.push(this._ccitem.fg);
				ret.push(this._ccitem.bg);
			}
			data.criteria = ret;
		} else if (this._fcitem) { // op == font_color
			data.op = "fontColor";
			data.all = false;
			var ret = [];
			ret.push(this._fcitem.pat);
			ret.push(this._fcitem.fg);
			ret.push(this._fcitem.bg);
			data.criteria = ret;
		} else if (this._vitem0) { //ZSS-1193: op == aboveAverage ||  op == belowAverage
			data.op = this._vitem0.op;
			data.all = false;
		} else { // op == values
			data.op = "values";
			data.all = this._isSelectAll();
			if (!data.all) {
				data.criteria = this._getCriteria();
			}
		}
		this.sheet._wgt.fire('onZSSFilter', data, {toServer: true});
	},
	_prevVisibleItem: function (n) {
		for (var prev = n.previousSibling; prev; prev = prev.previousSibling) {
			if (prev && prev.className.indexOf('zsafp-item-hide') < 0)
				return prev;
		}
	},
	_nextVisibleItem: function (n) {
		for (var next = n.nextSibling; next; next = next.nextSibling) {
			if (next && next.className.indexOf('zsafp-item-hide') < 0)
				return next;
		}
	},
	_firstVisibleItem: function () {
		for (var n = this._$items()[0]; n; n = n.nextSibling) {
			if (n && n.className.indexOf('zsafp-item-hide') < 0)
				return n;
		}
	},
	doKeyDown_: function (evt) {
		var keycode = evt.keyCode;
		switch (keycode) {
		case 38: //UP
		case 40: //DOWN
			var cnt = this.$n('items'),
				currFocus = jq(cnt).children('.zsafp-item-over')[0];
			if (currFocus) {
				var n = (keycode == 38) ? this._prevVisibleItem(currFocus) : this._nextVisibleItem(currFocus);
				if (n) {
					jq(n).addClass('zsafp-item-over');
					jq(currFocus).removeClass('zsafp-item-over');
				}
			} else {
				jq(this._firstVisibleItem()).addClass('zsafp-item-over');
			}
			break;
		case 13: //Enter
			if (!this._isSelectNone()) {
				this._applyFilter();
				this.close();
			}
			break;
		case 27: //ESC
			this.close();
		}
	}
}, {
	//TODO: provide a mechanism for display i-18n labels
	SELECT_ALL: '(Select All)',
	BLANK: '(Blanks)'
});
})();