(function($, F){

	if (F.is.undef(window.moment)){
		// The DateColumn requires moment.js to parse and format date values. Goto http://momentjs.com/ to get it.
		return;
	}

	F.DateColumn = F.Column.extend(/** @lends FooTable.DateColumn */{
		/**
		 * The date column class is used to handle date values. This column is dependent on [moment.js]{@link http://momentjs.com/} to provide date parsing and formatting functionality.
		 * @constructs
		 * @extends FooTable.Column
		 * @param {FooTable.Table} instance -  The parent {@link FooTable.Table} this column belongs to.
		 * @param {object} definition - An object containing all the properties to set for the column.
		 * @returns {FooTable.DateColumn}
		 */
		construct: function(instance, definition){
			this._super(instance, definition, 'date');
			/**
			 * The format string to use when parsing and formatting dates.
			 * @instance
			 * @type {string}
			 */
			this.formatString = F.is.string(definition.formatString) ? definition.formatString : 'MM-DD-YYYY';
		},
		/**
		 * This is supplied either the cell value or jQuery object to parse. Any value can be returned from this method and will be provided to the {@link FooTable.DateColumn#format} function
		 * to generate the cell contents.
		 * @instance
		 * @protected
		 * @param {(*|jQuery)} valueOrElement - The value or jQuery cell object.
		 * @returns {(moment|null)}
		 * @this FooTable.DateColumn
		 */
		parser: function(valueOrElement){
			if (F.is.element(valueOrElement) || F.is.jq(valueOrElement)){
				var data = $(valueOrElement).data('value');
				valueOrElement = F.is.defined(data) ? data : $(valueOrElement).text();
				if (F.is.string(valueOrElement)) valueOrElement = isNaN(valueOrElement) ? valueOrElement : +valueOrElement;
			}
			if (F.is.date(valueOrElement)) return moment(valueOrElement);
			if (F.is.object(valueOrElement) && F.is.boolean(valueOrElement._isAMomentObject)) return valueOrElement;
			if (F.is.string(valueOrElement)){
				// if it looks like a number convert it and do nothing else otherwise create a new moment using the string value and formatString
				if (isNaN(valueOrElement)){
					return moment(valueOrElement, this.formatString);
				} else {
					valueOrElement = +valueOrElement;
				}
			}
			if (F.is.number(valueOrElement)){
				return moment(valueOrElement);
			}
			return null;
		},
		/**
		 * This is supplied the value retrieved from the {@link FooTable.DateColumn#parser} function and must return a string, HTMLElement or jQuery object.
		 * The return value from this function is what is displayed in the cell in the table.
		 * @instance
		 * @protected
		 * @param {*} value - The value to format.
		 * @returns {(string|HTMLElement|jQuery)}
		 * @this FooTable.DateColumn
		 */
		formatter: function(value){
			return F.is.object(value) && F.is.boolean(value._isAMomentObject) && value.isValid() ? value.format(this.formatString) : '';
		},
		/**
		 * This is supplied either the cell value or jQuery object to parse. A string value must be returned from this method and will be used during filtering operations.
		 * @param {(*|jQuery)} valueOrElement - The value or jQuery cell object.
		 * @returns {string}
		 * @this FooTable.DateColumn
		 */
		filterValue: function(valueOrElement){
			// if we have an element or a jQuery object use jQuery to get the value
			if (F.is.element(valueOrElement) || F.is.jq(valueOrElement)) valueOrElement = $(valueOrElement).data('filterValue') || $(valueOrElement).text();
			// if options are supplied with the value
			if (F.is.hash(valueOrElement) && F.is.hash(valueOrElement.options)){
				if (F.is.string(valueOrElement.options.filterValue)) valueOrElement = valueOrElement.options.filterValue;
				if (F.is.defined(valueOrElement.value)) valueOrElement = valueOrElement.value;
			}
			// if the value is a moment object just return the formatted value
			if (F.is.object(valueOrElement) && F.is.boolean(valueOrElement._isAMomentObject)) return valueOrElement.format(this.formatString);
			// if its a string
			if (F.is.string(valueOrElement)){
				// if its not a number return it
				if (isNaN(valueOrElement)){
					return valueOrElement;
				} else { // otherwise convert it and carry on
					valueOrElement = +valueOrElement;
				}
			}
			// if the value is a number or date convert to a moment object and return the formatted result.
			if (F.is.number(valueOrElement) || F.is.date(valueOrElement)){
				return moment(valueOrElement).format(this.formatString);
			}
			// try use the native toString of the value if its not undefined or null
			if (F.is.defined(valueOrElement) && valueOrElement != null) return valueOrElement+'';
			return ''; // otherwise we have no value so return an empty string
		}
	});

	F.columns.register('date', F.DateColumn);

})(jQuery, FooTable);
