/* --------- BEGIN LICENSE NOTICE ---------
 * Copyright 2011 Extentech Inc. All Rights Reserved.
 *
 * This file is a part of the Sheetster 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. For a
 * fully supported and redistributable commercial license, please visit
 * <http://www.extentech.com> or contact us at:
 * 
 * sales@extentech.com
 * Extentech Inc.
 * 1032 Irving Street #910
 * San Francisco, CA 94122
 * 415-759-5292
 * ---------- END LICENSE NOTICE ----------
 */

/** @class Manages a single cell in the spreadsheet.
 * 
 * @param {Element} cellElement the TD of the cell to wrap
 * @param [jsonCellData] JSON data used to initialize the cell during the
 *        grid loading process. For an exisiting cell, omit this.
 */
cellHandle = Class.create();
cellHandle.prototype = {
	/** @ignore */
	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.rowCol = null;  // cache for multiple calls
		this.validationMessage == null;
		this.wordWrap = false;
		this.DateValue = null;
		
		if(jsonCellData){
			this.updateInternal(jsonCellData);
			return;
		}
		
		try{
			this.dataContainer = this.cell.down( '.cell-value' );
			this.formattedValue = this.dataContainer.innerHTML;
		}catch(e){}
		
		// hyperlinks
		this.href = cellElement.getAttribute('HRef');
		if(this.href!=null){
			try{
				$('hlink_input').setValue(this.href);	
			}catch(x){;}
			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;
			}
		}		
		
		this.validationMessage = cellElement.getAttribute( 'vmsg' );

		// setting for hiding formula strings
		this.formulahidden =
			cellElement.getAttribute( 'formulahidden' ) !== null;
	},
	
	
	/**
		Returns a non-editable cell
	**/
	toString: function(){
		return "<td>" + this.value + "</td>";
	},
	
	/** Compares this object with the given object for equality.
	 * @param {cellHandle} other the object to be compared
	 * @return {boolean} whether both objects represent the same cell
	 */
	equals: function (other) {
		if (!(other instanceof cellHandle)) throw new ContextualError(
				'only like types can be compared',
				'TypeError', 'InvalidArgument' );
		return this.cell === other.cell;
	},
	
	/** Compares this object with the given object for order.
	 * @param {cellHandle} other the object to be compared
	 * @return {number} a negative integer, zero, or a positive integer as this
	 *         object is less than, equal to, or greater than the given object
	 */
	compareTo: function (other) {
		if (!(other instanceof cellHandle)) throw new ContextualError(
				'only like types can be compared',
				'TypeError', 'InvalidArgument' );
		
		var thisRC = this.getRowCol();
		var otherRC = other.getRowCol();
		
		return thisRC.row - otherRC.row || thisRC.col - otherRC.col;
	},
	
	/**
		get the value of this cell
	**/
	getVal: function(){
		return this.value;
	},

	
	/**
		Get the formatted value from the workbook
	**/
	getFormattedVal: function(){
		return this.formattedVal();
	},
	
	/** Gets the number format string applied to this cell.
	 * @return {string} the applicable Excel number format pattern
	 */
	getFormatPattern: function() {
		var sid = this.cell.className.match( /(?:^|\s)s(\d+)(?:\s|$)/ );
		if (!sid) return null;
		return sheet.styleHandle.getNumberFormat( sid[ 1 ] );
	},
	
	getDateVal: function() {
		return this.DateValue;
	},
	
	/** Sets this cell's value on the server.
	 * The UI will be updated immediately to reduce appearance of lag.
	 * @param {string|object} value the new value to be applied
	 * @param {object} [handlers={}] callback functions for success/failure
	 */
	setVal: function (value, handlers) {
		if(this.isLocked()) // can't change val
			return;
		
		// store off in case of failure
		// user needs to see 'real' val
		if(this.cell == null) // problem?
			return;
		
		var oldvalue = this.value || '';
		
		if (typeof value !== 'object')
			value = { value: value };
		
		if (!handlers) handlers = {};
		
		if (value.value) {
			this.cell.value = value.value;
			this.cell.formattedValue = value.value;
			this.value = value.value;
			this.setDisplayValue( value.value );
		}
		
		var url = '/workbook/' + book.loadby + '/' + sheet.getMemeId()
				+ '/json/cell/add/' + encodeURIComponent(
						sheet.getSheetName() + '!' + this.cellAddress );
		var params = {};
		
		if (value.time) {
			if (value.time instanceof Date)
				params.time = value.time.getTime();
			else params.time = value.time;
			
			if (value.format)
				params.date_format = value.format;
		} else {
			url += '/' + encodeURIComponent( value.value );
		}
		
		new Ajax.Request(url , {
			method: 'GET',
			parameters: params,
			
			onSuccess: function (response) {
				sheet.updateCellsFromJSON( response.responseText );
				if (handlers.success) handlers.success();
			},
			
			onFailure: function (response) {
				try {
					this.setDisplayValue( oldvalue );
				} catch (e) {}
				
				try {
					var json = response.responseText.evalJSON();
					
					if (handlers.validation && json.validation) {
						var dialog = json.validation;
						handlers.validation(
								this, value, dialog.title, dialog.body );
						return;
					}
					
					if (handlers.failure) {
						handlers.failure( json.errorMessage );
						return;
					}
				} catch (e) {
					var message = "error setting value of cell";
					
					try {
						message += ' ' + this.getAddress();
					} catch (e) {}
					
					uiWindowing.showError( message );
					Logger.httpError( response, message );
				}
			}.bind( this )
		});
		
		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){
		if ('' == newval) {
			if (this.dataContainer) {
				this.dataContainer.remove();
				this.dataContainer = null;
			}
			
			return;
		}
		
		var rc = this.getRowCol();
		var colLet = toolkit.getAlphaVal( rc[ 1 ] );
		
		if (!this.dataContainer){
			this.dataContainer = new Element( 'span',
					{ 'class': 'cell-value' });
			this.cell.appendChild(this.dataContainer);
		}
		
		if (this.cell.colSpan>1){
			toolkit.setFixedWidth(this.dataContainer);
			
			this.dataContainer.addClassName('mergedcell');
		}
	
		if (this.cell.rowSpan>1 && colLet == 'A'){
			// TODO: remove?			
			toolkit.setFixedHeight(this.dataContainer);
			this.dataContainer.addClassName('mergedcell');
		}
		// word wrap interferes with visible datacontainer in merged cells
		if(this.wordWrap){
			this.dataContainer.setStyle({
				whiteSpace: 'normal'
			});
		}
		this.dataContainer.innerHTML=newval;
		this.value = newval;
	},
	
	/** Checks whether this cell contains a date value.
	 */
	isDate: function() {
		return this.cell.getAttribute( 'time' ) != null;
	},
	
	/** Check whether this cell contains a formula.
	 * 
	 */
	isFormula: function() {
		// if this cell has a hidden formula, the value is its result
		if (this.formulahidden) return true;
		
		return this.value.charAt( 0 ) === '='; 
	},
	
	/** Check whether this cell contains a hidden formula.
	 * 
	 */
	isFormulaHidden: function() {
		return this.formulahidden;
	},

	/**
	 * locks and unlocks the cell
	 * 
	 * NOTE: cell locking is only enabled when the sheet is protected 
	 * 
	 */
	setLocked: function(lck){
		if (!sheet.isProtected()) // can't change while sheet locked
			this.cell.setAttribute('locked',lck);
	},
	
	/** Returns whether the cell is locked.
	 * This method currently takes into account the sheet protection status.
	 * This is, if the sheet is not protected it will return false even if the
	 * cell is locked.
	 */
	isLocked: function(){
		if (sheet.isProtected()){
			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.time) {
			this.cell.setAttribute( 'time', cellJSON.d.time);
			this.cell.setAttribute('title','ctrl+click for date picker');
		}
		
			
		// 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
		
			
			if(this.href.indexOf('javascript:')==0){ // eval script 
				alert('This link has active Scripting which may access your data. Only run the script if you trust the source of this document.' );
			    try{
			    	eval(this.href);
			    }catch(e){
			    	parent.showError("Error running script: " + e);
			    }
			}else if(this.href.indexOf('pop-in-grid')>-1){			// pop and size windows if link is in-grid
			
				if ((this.href.indexOf('.swf')>-1)
					||(this.href.indexOf('youtube.com')>-1)){ // use flash viewer
					
					createDialogWindow( this.value,
							'/uimodules/docs/docs_flash_viewer.jsp?url='
								+ encodeURIComponent( this.href ),
							'imageembed' );
				} else {
					createDialogWindow( this.value, this.href, 'extentech' );
				}
			}
		}
		
		// 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);
		}
		
		var rc = this.getRowCol();
		// CELLMERGE: handle across merge
 		var cspan = cellJSON.MergeAcross; 
	 	if (cspan != null && cspan > 0) {
			this.cell.setAttribute( 'colspan', cspan + 1 );
			for (var i=1;i<=cspan;i++){
				if (rc!=null){
					var ccx = new Array();
					ccx[0] = rc[0];
					ccx[1] = rc[1] + i;
					
					var delCell = $(toolkit.formatLocation(ccx));
					try{
						if(delCell!=null)delCell.remove();
					}catch(e){
						 console.log('delete merge cell failed: ' + e);
					}							
				}  
			}
		} else {
			this.cell.removeAttribute( 'colspan' );
		}
		
		// CELLMERGE: handle down merge
		var rspan = cellJSON.MergeDown;
		if (rspan != null && rspan > 0) {	
			this.cell.setAttribute( 'rowspan', rspan + 1 );
			var rc = this.getRowCol();
			for (var i=1;i<=rspan;i++){
				if (rc!=null){
					var ccx = new Array();
					ccx[0] = rc[0]+i;
					ccx[1] = rc[1];
					
					var delCell = $(toolkit.formatLocation(ccx));
					try{
						if(delCell!=null)delCell.remove();
					}catch(e){
						 console.log('delete merge cell failed: ' + e);
					}	
				}	
			}
		} else {
			this.cell.removeAttribute( 'rowspan' );
		}
		
		// 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{
			if(typeof( cellJSON.d.v) != 'undefined'){
				this.formattedValue = cellJSON.d.v;
				this.setDisplayValue(cellJSON.d.v);
			}else{ // an empty string
				this.formattedValue = '';
				this.setDisplayValue('');	
			}
		}
		
		if (cellJSON.d.t) this.cell.addClassName(
				'cell-type-' + cellJSON.d.t.toLowerCase() );
		
	},

	/** Gets the Excel-style address of this cell.
	 * @param {boolean} [includesheet=false] whether to include the sheet name
	 * @return {string} this cell's address as a column letter and numeric row
	 */
	getAddress: function(includesheet){
		if(includesheet){
			try{
				return book.getSelectedSheet().getSheetName() + '!' + this.cellAddress;	
			}catch(e){
				return parent.book.getSelectedSheet().getSheetName() + '!' + this.cellAddress;
				
			}
			
		}
		return this.cellAddress;
	},
	
	/** Gets the zero-based numeric address of this cell.
	 * @return {object} an array/object hybrid containing the cell's address
	 *         as returned by {@link gridToolkit#getRowColFromString}
	 */
	getRowCol: function(){
		if (!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.getAlphaVal( 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){
		if(this.isLocked()) // locked
			return;

		var cr = new cellRange( this );
		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;
	},
	
	getOffsetTop: function() {
		return this.cell.offsetTop;
	},
	
	getOffsetLeft: function() {
		return this.cell.offsetLeft;
	},
	
	getOffsetWidth: function() {
		return this.cell.offsetWidth;
	},
	
	getOffsetHeight: function() {
		return this.cell.offsetHeight;
	},
	
	/* sets the hyperlink to the cell
	
		TODO: investigate moving into CellRange -- setting ranges
		with hyperlinks is just as easy for us
	
	*/	
	popHyperlinkDialog: function(){
		if(this.isLocked()) // locked
			return;
		
		_this = this;
		Dialog.confirm($('hlink_form').innerHTML, {
			className:'extentech', 
			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/'
						+ sheet.getSelection().getFocus().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);
				_sheet=book.getSelectedSheet();
				_removelink = removelink;
				new Ajax.Request(url , {
					method: 'get',
					
					onSuccess: function(transport){
						_sheet.updateCellsFromJSON(transport.responseText);
						
						if(_removelink){
							var cell = _sheet.getSelection()
									.getFocus().getCellElement();
							// undo lame static link LNF
							cell.setStyle({color:'black', textDecoration:'none'});
							// undo link
							cell.removeAttribute('href');						
							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;
        	}
		});
	},
	
	/**
	 */
	expandCell: function() {
		if (!this.dataContainer) return;
		
		var overflow = this.dataContainer.getWidth() - this.cell.getWidth();
		var expand = overflow >= 0;

		// make sure there's enough blank space to the right of the cell
		if (expand) {
			var cell = this.cell;
			while (overflow >= 0 && (cell = cell.next( 'td' ))) {
				if (cell.down( '.cell-value' )) {
					expand = false;
					break;
				}
				
				overflow -= cell.getWidth();
			}
		}
				
		if (expand) {
			this.cell.addClassName( 'cell-expanded' );
		}else{
			this.cell.removeClassName( 'cell-expanded' );
		}
	},
	
	/** Returns whether this cell is the parent of a merged range. 
	 */
	isMerged: function() {
		return this.cell.getAttribute("MergeParent") != null
				&& this.cell.getAttribute("MergeParent");
	},
	
	/** Returns whether this cell has a validation condition.
	 */
	hasValidation: function() {
		return this.validationMessage !== null;
	},
	
	/** Gets the message to be displayed when the cell is selected.
	 */
	getValidationComment: function() {
		return this.validationMessage;
	},
	
	/**
		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.getAlphaVal( 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;
	},

	/**
	 * pop up a date picker
	 */
	promptDate: function(){
		if(this.isLocked()) // locked
			return;

		var picker = cellHandle.datePicker;
		if (!picker) picker = cellHandle.datePicker = new DatePickerDialog();
		picker.setFormatEnabled( true );
		
		var time = this.cell.getAttribute( 'time' );
		if (time) picker.setTime( parseInt( time ) );
		
		var format = this.getFormatPattern();
		if (format) picker.setCurrentFormat( format );
		
		picker.show( function (target) {
				this.setVal({
						'time': target.getValue(),
						'format': target.getSelectedFormat()
					});
			}.bind( this ) );
	}
};
