/* Copyright (c) 2008 Extentech Inc. All Rights Reserved

##### Sheetster&trade; Web Application #####

This file is a part of the Sheetster&trade; Web Application

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

If you would like to redistribute this software in a closed-source application,
dual-licensed commercial versions are available from Extentech.

For a fully supported and redistributable commercial license, 
please visit www.extentech.com or contact us at:

 sales@extentech.com
 Extentech Inc.
 1032 Irving Street #910
 San Francisco, CA 94122
 415-759-5292
 
*/
/**
	cellHandle  
	
	use a cellHandle to work with individual cells in the spreadsheet
    
    @class cellHandle represents a spreadsheet cell.  
 */
cellHandle = Class.create();
cellHandle.prototype = {
	/**
		constructor, takes a cell element (td), and an optional container of jsonCellData
		
		The optional constructor argument is used during initialization of the grid when the cell is being
		created with data.  For a cell that already has a value omit this value
	**/
	initialize: function(cellElement, jsonCellData){
		this.cjson = jsonCellData;		
		if(!cellElement){
			parent.debug('CellHandle.initialize failed. Cell element undefined.');
			return;
		}else if(cellElement == null){
			parent.debug('CellHandle.initialize failed. Cell element is null.');
			return;
		}
		
		this.readonly = false; // TODO: set from JSON
		this.cell = Element.extend(cellElement);
		this.cellAddress = cellElement.getAttribute('id');
		this.dt=null;
		this.spanningCell = false;
		this.rowCol = null;  // cache for multiple calls
		this.validationMessage == null;
		this.wordWrap = false;
		this.DateValue = null;
		
		if(jsonCellData){
			this.updateInternal(jsonCellData);
			return;
		}
		this.formattedValue = cellElement.innerHTML; // update this to real val
		try{
			this.dataContainer = cellElement.childNodes[0];
		}catch(e){}
		
		// hyperlinks
		this.href = cellElement.getAttribute('HRef');
		if(this.href!=null){
			parent.showStatus("ctrl+click to open: "+this.href);
		}
		
		//value
		if (cellElement.getAttribute('fs')!=null){
			this.value = cellElement.getAttribute('fs');
		}else if (cellElement.getAttribute('val')!=null){
			this.value = cellElement.getAttribute('val');
		}else{
			if(this.dataContainer){
				this.value = this.dataContainer.innerHTML;
			}else{
				this.value = cellElement.innerHTML;
			}
		}		
		
		if(cellElement.getAttribute('spanning')=='true'){
			this.spanningCell = true;
		}
		if(cellElement.getAttribute('vmsg')!=null){
			this.validationMessage = cellElement.getAttribute('vmsg');
		}
		
		this.rowCol = null; // cache for multiple calls
		this.locked = false; // setting for locked (cannot edit) cells
		this.formulahidden = false; // setting for hiding formula strings
			
	},
	
	
	/**
		Returns a non-editable cell
	**/
	toString: function(){
		return "<td>" + this.value + "</td>"
	},
	
	/**
		get the value of this cell
	**/
	getVal: function(){
		return this.value;
	},

	
	/**
		Get the formatted value from the workbook
	**/
	getFormattedVal: function(){
		return this.formattedVal();
	},
	
	
	/**
		set the value of this cell.  Immediately set the underlying val
		on the td so it seems snappy to the user.  background the ajax call
		http://127.0.0.1:8080/workbook/'+book.loadby+'/906/xml/cell/add/Invoice!A2/=SUM(10+11)
	**/
	setVal: function(newValue){
		// store off in case of failure
		// user needs to see 'real' val
		var oldvalue = '';
		if(this.cell == null) // problem?
			return;
			
		oldvalue = this.value;
	
		if(oldvalue==null)
			oldvalue='';
		this.cell.value = newValue;
		this.cell.formattedValue = newValue;
		this.value = newValue;
		this.setDisplayValue(newValue);
		var _this = this;
		var url = '/workbook/'+book.loadby+'/' + book.selectedSheet.getMemeId() + '/json/cell/add/' + book.selectedSheet.getSheetName() + '!' + this.cellAddress + '/' + newValue;
		new Ajax.Request(url , {
			method: 'get',
			onSuccess: function(transport){
				book.selectedSheet.updateCellsFromJSON(transport.responseText);
			},
			onFailure: function(transport){ 
				var response = transport.responseText || "failure";     
				try{
					var rJSON = response.evalJSON();
					parent.showError("Unable to set server cell value: " + rJSON.errorMessage); 
					if(_this.cell!=null)
						_this.setDisplayValue(oldvalue); // unset
				}catch(e){
					parent.showError("Unable to set server cell value:" + _this.newValue); 
				}
			}
			
		});
		this.expandCell();
	},
	/**
		Sets the inner value of the cell,
		handles creating/setting the value of the div
		rather than the td itself
		
		all dom based, no server functionality
	**/
	setDisplayValue: function(newval){
		var rc = this.getRowCol();
		var colLet = toolkit.ALPHAS[rc[1]];
		if (!this.dataContainer){
			this.dataContainer = Element.extend(document.createElement('div'));
			this.dataContainer.setAttribute('id', 'cont' + this.cellAddress);
			this.cell.appendChild(this.dataContainer)
			this.dataContainer.className += (this.dataContainer.className ? ' ' : '') + 'datacell';
			this.dataContainer.className += (this.dataContainer.className ? ' ' : '') + 'colwidth' + colLet; // faster call than addClassName...
			if(colLet == 'A')this.dataContainer.className += (this.dataContainer.className ? ' ' : '') + 'rowheight' + (rc[0]+1);
		}else{
			this.dataContainer.addClassName('colwidth' + colLet); // this call dedupes, slower but needed if already existing
			if(colLet == 'A')this.dataContainer.addClassName('rowheight' + (rc[0]+1));
		}
		if (this.cell.colSpan>1){
			toolkit.setFixedWidth(this.dataContainer);
			this.dataContainer.addClassName('mergedcell');
		}		
		if (this.cell.rowSpan>1 && colLet == 'A'){
			toolkit.setFixedHeight(this.dataContainer);
			this.dataContainer.addClassName('mergedcell');
		}
		if(this.wordWrap){
			this.dataContainer.setStyle({
				whiteSpace: 'normal'
			});
		}
		this.dataContainer.innerHTML=newval;
		this.value = newval;
	},
	
	/**
	 * Returns if the cell is locked.
	 */
	isLocked: function(){
		if (sheet.cellProtection){
			if(this.cell.getAttribute('locked')==null)return true;
			if(this.cell.getAttribute('locked')=='true')return true;
		}
		return false;
	},
	
	/**
		Updates the cell with information from
		the json cell passed in.  value, formula, format, etc.
		
		This does not update the in memory workbook at all, rather it is
		called with return information from an update cell event, so it is 
		just updating the DOM grid
		
	**/
	updateInternal: function(cellJSON){
		// hold onto json for cloning
		this.cjson = cellJSON;
		
		
		// CLEAR: existing
		this.cell.removeAttribute('fs');
		this.cell.removeAttribute('val');
		this.cell.removeAttribute('href');
		this.cell.removeAttribute('dt');		
		this.DateValue = null;
		
		// CELL: basic setup
		this.cell.setAttribute('id', cellJSON.loc);
		this.cellAddress = cellJSON.loc;
		if (cellJSON.fm != null){ // formula
		
			// formula hiding
			if(cellJSON.fhd == null){ 
				this.cell.setAttribute('fs', cellJSON.fm);
			}else{
				this.formulahidden = true;
				this.cell.setAttribute('formulahidden','true');
			}
			this.value = cellJSON.fm;
		}
		if(cellJSON.sid != null){
			book.selectedSheet.styleHandle.updateAttachedCSS('s'+cellJSON.sid, this.cell);
		}
		if(cellJSON.vm !=null){
			this.validationMessage = cellJSON.vm;
			this.cell.setAttribute("vmsg", cellJSON.vm);
		}
		if(cellJSON.wrap !=null){
			this.wordWrap = true;
		}
		
		// DATE: help the date popper
		// {"Cell":{"sid":41,"d":{"v":"01/01/00","DateValue":36526},"loc":"G7"}}
	
		if(cellJSON.d.DateValue!=null){
			this.cell.setAttribute('dt', cellJSON.d.DateValue); // should be an Excel date float ... just a flag
			this.cell.setAttribute('title','ctrl+click for date picker');
			this.DateValue = cellJSON.d.DateValue;
		}
		
			
		// TODO: implement cell locking to/from JSON
		if(cellJSON.lck != null){ 
				this.cell.setAttribute('locked',cellJSON.lck);
		}
		
		// HLINK: set hyperlink
		if(cellJSON.HRef !=null){
			// alert('cell update href:'+cellJSON.HRef);
			this.href = cellJSON.HRef;
			this.cell.setAttribute('href',cellJSON.HRef);
			this.cell.setAttribute('title','ctrl+click to open: ' + cellJSON.HRef);
			this.cell.setStyle({color:'blue', textDecoration:'underline'}); // lame temporary link look
		
			// pop and size windows if link is in-grid
			if(this.href.indexOf('pop-in-grid')>-1){
			
				if((this.href.indexOf('.swf')>-1)
					||(this.href.indexOf('youtube.com')>-1)){ // use flash viewer
					
					// TODO: handle urlparams
					// var urlx = this.href.replace(/&/g, '~|');
					
					// use escape(hlink) to URL encode the link
					createDialogWindow(this.value,'/uimodules/docs/docs_flash_viewer.jsp?url='+ escape(this.href) ,'imageembed');
				}else{
					createDialogWindow(this.value,this.href,book.theme);
				}
			}
		
		}
		
		// STYLE:
		if (cellJSON.sid != null){
		  this.cell.addClassName("s" + cellJSON.sid);
		}
		
		if(cellJSON.negRed !=null){
			this.cell.addClassName("negativeNumber");
		}else{
			this.cell.removeClassName("negativeNumber");
		}
		
		// CHILDMERGE: if this is a child merged cell, remove it
		if(cellJSON.MergeChild!=null && cellJSON.MergeChild){
			this.cell.remove();
			return;
		}
		if(cellJSON.MergeParent!=null && cellJSON.MergeParent){
			this.cell.setAttribute("MergeParent", true);
		}
		
		// CELLMERGE: handle across merge
 		var cspan = cellJSON.MergeAcross; 
	 	if(cspan !=null){
	 		if(cspan>0)
				this.cell.colSpan = (cspan+1);
				var rc = this.getRowCol();
				for (var i=1;i<=cspan;i++){
					if (rc!=null){
						rc[1] += i;
						var delCell = $(toolkit.formatLocation(rc));
						try{
							if(delCell!=null)delCell.remove();
						}catch(e){;}							
					}  
				}
		}else{ // we may have removed colspan, so set to one
			if(!this.spanningCell)this.cell.colSpan=1;
		}
		
		// CELLMERGE: handle down merge
		var rspan = cellJSON.MergeDown;
		if(rspan !=null){
			if(rspan>0){	
					this.cell.rowSpan = (rspan+1);
					var rc = this.getRowCol();
					for (var i=1;i<=rspan;i++){
						if (rc!=null){
							rc[0] += i;
							var delCell = $(toolkit.formatLocation(rc));
							try{
								if(delCell!=null)delCell.remove();
							}catch(e){
								// console.log('error in cellmerge');
							}
						}  
					}		
			}
		}else{ 
			if (this.cell.getAttribute('rowspan')!=1){
				this.cell.rowSpan = 1;
			}
		}
		
		// Formatted value
		if(cellJSON.d.fv !=null){
			try{
				this.formattedValue = cellJSON.d.fv;
				this.setDisplayValue(cellJSON.d.fv);
				this.cell.setAttribute('val', cellJSON.d.v);
			}catch(e){
				parent.showError("cellHandle.init value failed:"+e.toString());
			}
		}else{
			this.formattedValue = cellJSON.d.v;
			this.setDisplayValue(cellJSON.d.v);
		}
		
		
	},

	/**
		Return the address of this cell
		
		@param include the sheet name in the cell address
	**/
	getAddress: function(includesheet){
		if(includesheet){
			return parent.uiWindowing.getActiveSheet().getSheetName() + '!' + this.cellAddress;
		}
		return this.cellAddress;
	},
	
	/**
		Acts as a caching call to toolkit.getRowColFromString();
	**/
	getRowCol: function(addy){
		if(this.rowCol)return this.rowCol;
		this.rowCol = toolkit.getRowColFromString(this.cellAddress);
		return this.rowCol;
	},
	
	
	/**
	Get the ColHandle (object) that contains this cell
	**/
	getColHandle: function(){
		var colNum = this.getRowCol()[1];
		var cHandle =  new colHandle(toolkit.ALPHAS[colNum]);
		return cHandle;
	},
	
	/**
		get the RowHandle (object) that contains this cell
	**/
	getRowHandle: function(){
		var rowNum = this.getRowCol()[0];
		var rHandle =  new rowHandle(rowNum);
		return rHandle;
	},
	
	/**
		Gets the classes that this cell incorporates for its styles
	**/
	getClasses: function(){
		var cellStyles = this.cell.classNames();
		return cellStyles;
	},
	
	/**
		Set the css classes for this element
	**/
	setClasses: function(classEnumerable){
		var cellAddress = this.cellAddress;
		classEnumerable.each(function(s){
			$(cellAddress).addClassName(s);
		});
	},
	
	/**
		Return a css string representing the style of this cell
	**/
	getStyleString: function(){
		return this.cell.getStyle();
	},
	
	/**	
		SwitchStyle turns on and off a style state	
	**/
	switchStyle: function(cssIdent, onVal, ajaxPost){
		var cr = new cellRange(this.cellAddress + ':' + this.cellAddress, book.selectedSheet.sheetName);
		cr.switchStyle(cssIdent, onVal, ajaxPost);
	},
	
	/**
		just get the element (td) that represents the cell in the dom
		as an extended prototype element
	**/
	getCellElement: function(){
		return this.cell;
	},
	
	/* sets the hyperlink to the cell
	
		TODO: investigate moving into CellRange -- setting ranges
		with hyperlinks is just as easy for us
	
	*/	
	popHyperlinkDialog: function(){
		_this = this;
		Dialog.confirm($('hlink_form').innerHTML, {
			className:book.theme, 
			width:300, 
			height:100,
			zIndex:100,
          	okLabel: "set link",
          	cancelLabel: "cancel",
          	cancel:function(win) {
        		parent.showStatus('set hyperlink canceled.')
        		return false;
        	},
          	onOk:function(win){
	          	var linkURL = $('hlink_input').getValue();
    			// parent.showStatus('setting hyperlink : ' + linkURL);
                var popingrid = $('pop-in-grid').getValue();
                
              // alert(popingrid);
                
                // set with null to remove a link...
				var	removelink = (linkURL == '');

				// alert(linkURL + ':' + removelink);

				// send hlink command to server
				var url = '/workbook/'+book.loadby+'/' + book.selectedSheet.memeId 
				+ '/json/cell/setlink/' + cursor.liveCell.getAddress(true) +'/'+linkURL ;
				
				if(popingrid == 'on'){ // append the pop-in-grid flag
					if(url.indexOf('?')>-1)
						url+='&pop-in-grid=true';
					else
						url+='?pop-in-grid=true';
				}
				// alert(url);
				_cursor = cursor;
				_sheet=uiWindowing.getActiveSheet();
				_removelink = removelink;
				new Ajax.Request(url , {
					method: 'get',
					
					onSuccess: function(transport){
						_sheet.updateCellsFromJSON(transport.responseText);
						
						if(_removelink){
						// undo lame static link LNF
							_cursor.liveCell.cell.setStyle({color:'black', textDecoration:'none'});
						// undo link
							_cursor.liveCell.cell.removeAttribute('href');						
							_cursor.liveCell.cell.removeAttribute('title');
							parent.showStatus("Removed hyperlink: " + transport.responseText); 
						}
					},
					onFailure: function(transport){ 
						var response = transport.responseText || "failure";     
						parent.showError("Set hyperlink failed: " + response); 
					}		
				});
				return true;
        	}
		});
	},	
	
	/**
		Determines if a cell should expand.
		
		Parameters for expanding are the cell contents being wider than 
		the column, and the following cell being empty/null
		
		passing in the width checker just due to avoiding another lookup
		
		nextDataCol is an optional parameter that tells the cell how far it can merge,
		keeps lookups from needing to occur
		
	**/
	shouldExpand: function(theChecker, nextDataCol){
		var currSpan = 1;
		if(this.cell.getAttribute('colspan')!=null&&this.cell.getAttribute('colspan')!=1){
			if (this.cell.getAttribute('spanning')!='true'){
				return false;// no expando for merged cells!
			}else{
				currSpan = parseInt(this.cell.getAttribute('colspan'));
			}
		}
		var rc = this.getRowCol();
		if (rc!=null){
					rc[1] += currSpan;
					if (nextDataCol){
						if (rc[1]>=nextDataCol) return false;
					}else{
						var followdata = $('cont' + toolkit.formatLocation(rc));
						if (followdata != null){
							if(followdata.innerHTML!='')return false;
						}
					}
		}
		var width1 =  theChecker.clientWidth;
		var width2 = this.cell.clientWidth;
		if(width1>width2){
			return true;
		}
		return false;
	},
	

	
	/**
		Determine if the cell which is display spanning should 
		shink upon a set value
	**/
	shouldShrink: function(theChecker){
		if(!this.spanningCell)return false;
		var width1 = theChecker.clientWidth;
		var width2 = this.cell.getWidth();
		if(theChecker.getWidth()<this.cell.getWidth()){
			return true;
		}
		return false;
	},
	
	
	
	/**
		Set up the width checker with existing style and text
	**/
	initWidthChecker: function(){
			var theChecker = sheet.widthChecker;
			var classArray = $w(theChecker.className);
			for (var i=0; i<classArray.size();i++) {
				theChecker.removeClassName(classArray[i]);
			}
			this.getClasses().each(function(s){
				theChecker.className += (theChecker.className ? ' ' : '') + s;
			});
			theChecker.innerHTML = this.getVal();
			return theChecker;
	},
	
	
	/**
		Handle automagic spanning based on content.
	**/
	shrinkCell: function(){
		var wChecker = this.initWidthChecker();
		if(this.shouldShrink(wChecker)){
			this.spanningCell = false;
			this.cell.setAttribute('spanning', 'false');
			toolkit.removeFixedWidth(this.dataContainer);
			this.unmerge();
		}
	},
	
	/**
		Handle automagic spanning based on content.
		Returns int representing the amount of spanning.  
	**/
	expandCell: function(){
		var wChecker = this.initWidthChecker();
		var returnval = 1;
		if (this.cell.colSpan <=1)return returnval;
		while (this.shouldExpand(wChecker)){ // if you are able to recreate an infinite loop here please provide xls file for me!  -nick
			returnval++;
			this.spanningCell = true;
			this.cell.setAttribute('spanning', 'true');
			var cspan = 1;
			if (this.cell.getAttribute('colspan')!=null){
				cspan = this.cell.getAttribute('colspan');
			}
			cspan = parseInt(cspan);
			cspan++;
			this.cell.colSpan = cspan;	
			var rc = this.getRowCol();
			for (var i=1;i<cspan;i++){
				if (rc!=null){
					rc[1] += i;
					var delCell = this.cell.next();
					try{
						if(delCell!=null)delCell.remove();
					}catch(e){;}							
				}  
			}
		}
	    var colLet = toolkit.ALPHAS[this.getRowCol()[1]];
		this.dataContainer.addClassName('colwidth' + colLet);
		if(cspan>1){
			toolkit.setFixedWidth(this.dataContainer);
			this.dataContainer.addClassName('mergedcell');
		}
		return returnval;
	},
	

	/**
		Very similar to expandCell, this method is called upon row initialization
		and avoids the expensive lookups needed during sheet load.
		
		It allows merge up to the nextDataCol, which is the next cell that has data
	**/
	automerge: function(nextDataCol){
		var returnval = 1;
		if (this.cell.colSpan <=1)return returnval;
		if(this.value.length > sheet.automergelimit){
			var wChecker = this.initWidthChecker();
			var cspan = 1;
			while (this.shouldExpand(wChecker,nextDataCol)){ 
				returnval++;
				this.spanningCell = true;
				this.cell.setAttribute('spanning', 'true');
				if (this.cell.getAttribute('colspan')!=null){
					cspan = this.cell.getAttribute('colspan');
				}
				cspan = parseInt(cspan);
				cspan++;
				this.cell.colSpan = cspan;	
				var rc = this.getRowCol();
				for (var i=1;i<cspan;i++){
					if (rc!=null){
						rc[1] += i;
						var delCell = this.cell.next();
						try{
							if(delCell!=null)delCell.remove();
						}catch(e){;}							
					}  
				}
			}
			if(cspan>1){
				var colLet = toolkit.ALPHAS[this.getRowCol()[1]];
				this.dataContainer.addClassName('colwidth' + colLet);
				toolkit.setFixedWidth(this.dataContainer);
				this.dataContainer.addClassName('mergedcell');
			}
		}
		return returnval;
	},
	
	/**
		Unmerges a cell.
		
		Note, this only handles dom aspects of unmerging - removing the colspan,
		adding cells where needed, etc.
	**/
	unmerge: function(){
			var rc = this.getRowCol();
			var cspan = 1;
			if (this.cell.getAttribute('colspan')!=null){
				cspan = parseInt(this.cell.getAttribute('colspan'));
			}
			if (cspan > 1){
				this.cell.colSpan = 1; //setAttribute('colspan', 1);
				var theRow = $('Rw' + (rc[0]));
				var newRc = new Array();
				newRc[0] = rc[0];
				for(var x=cspan;x>1;x--){
						var theCol = rc[1] + (x-1);
						var domCell = theRow.insertCell(rc[1]+1);
						newRc[1] = theCol;
						var theId = toolkit.formatLocation(newRc);
						try{
							domCell.setAttribute('id', toolkit.formatLocation(newRc));
						}catch(e){;}
				}
			}
			var rspan = 1;
			if (this.cell.getAttribute('rowspan')!=null){
				rspan = parseInt(this.cell.getAttribute('rowspan'));
			}
			if(rspan > 1){
				this.cell.rowSpan = 1;
				var newRc = new Array();
				newRc[1] = rc[1];
				for (var i=1;i<rspan;i++){
					var theRow = $('Rw' + (rc[0]+i));
					var domCell = theRow.insertCell(rc[1]);
					newRc[0] =  (rc[0]+i);
					var theId = toolkit.formatLocation(newRc);
					try{
						domCell.setAttribute('id', toolkit.formatLocation(newRc));
					}catch(e){;}
				}
			}
	},
	
	
	/**
		In a display-merged cell determines if the click occurred in the
		original/main cell or outside in the merged zone.
		
		This is handled by looking at offset of cell below, if no cell exists (should never happen?)  then 
		we just return false, as an incorrect false is no big deal for display, but incorrect 
		true is bad bad.
	**/
	eventInMainCell: function(evt){
		var rc = this.getRowCol();
		var left = $(toolkit.ALPHAS[rc[1]+1] +'0').positionedOffset()[0] + 30; // 30 is the corner/rowheader width;
		if (evt.clientX > left)return false;
		return true;
	},

	/**
		does the cell in question have vertical borders?
	**/
	hasVerticalBorders: function(){
		var theNames = $w(this.cell.className);
		for (var i=0;i<theNames.length;i++){
			if (theNames[i].indexOf('s')==0){
				var cRule = toolkit.getExternalRule('.'+ theNames[i] ,0);
				if(cRule.cssText.indexOf('border-right')>-1 || cRule.cssText.indexOf('border-left')>-1 || cRule.cssText.indexOf('border:')>-1)return true;
			}
		}
		return false;
	},
	
	/**
		does the cell in question have horizontal borders?
	**/
	hasHorizontalBorders: function(){
		var theNames = $w(this.cell.className);
			for (var i=0;i<theNames.length;i++){
				if (theNames[i].indexOf('s')==0){
					var cRule = toolkit.getExternalRule('.'+ theNames[i] ,0);
					if(cRule.cssText.indexOf('border-top')>-1 || cRule.cssText.indexOf('border-bottom')>-1|| cRule.cssText.indexOf('border:')>-1){
						return true;
					}
				}
			}
			return false;
	},
		
	/* adds a date to the cell
	
		TODO: investigate moving into CellRange -- filling ranges
		with dates is just as easy for us
	
	*/	
	promptDate: function(){
		_this = this;
		// if day is missing, then it loads
		// calendar, otherwise fires date select events
		datetoolkit.setCell(this);
		datetoolkit.showCalendar();
		try{
			var dvz = _this.cell.getAttribute('dt');
			datetoolkit.initCalendar(dvz);			
		}catch(e){
			 showError('cellHandle.promptDate failed: '+e.toString());
			//datetoolkit.initCalendar(null); 
		}

	}
}