(function($, F){

	// add in console we use in case it's missing

	window.console = window.console || { log:function(){}, error:function(){} };



	/**

	 * The jQuery plugin initializer.

	 * @function jQuery.fn.footable

	 * @param {(object|FooTable.Defaults)} [options] - The options to initialize the plugin with.

	 * @param {function} [ready] - A callback function to execute for each initialized plugin.

	 * @returns {jQuery}

	 */

	$.fn.footable = function (options, ready) {

		options = options || {};

		// make sure we only work with tables

		return this.filter('table').each(function (i, tbl) {

			F.init(tbl, options, ready);

		});

	};



	var debug_defaults = {

		events: []

	};

	F.__debug__ = JSON.parse(localStorage.getItem('footable_debug')) || false;

	F.__debug_options__ = JSON.parse(localStorage.getItem('footable_debug_options')) || debug_defaults;



	/**

	 * Gets or sets the internal debug variable which enables some additional logging to the console.

	 * When enabled this value is stored in the localStorage so it can persist across page reloads.

	 * @param {boolean} value - Whether or not to enable additional logging.

	 * @param {object} [options] - Any debug specific options.

	 * @returns {(boolean|undefined)}

	 */

	F.debug = function(value, options){

		if (!F.is.boolean(value)) return F.__debug__;

		F.__debug__ = value;

		if (F.__debug__){

			localStorage.setItem('footable_debug', JSON.stringify(F.__debug__));

			F.__debug_options__ = $.extend(true, {}, debug_defaults, options || {});

			if (F.is.hash(options)){

				localStorage.setItem('footable_debug_options', JSON.stringify(F.__debug_options__));

			}

		} else {

			localStorage.removeItem('footable_debug');

			localStorage.removeItem('footable_debug_options');

		}

	};



	/**

	 * Gets the FooTable instance of the supplied table if one exists.

	 * @param {(jQuery|jQuery.selector|HTMLTableElement)} table - The jQuery table object, selector or the HTMLTableElement to retrieve FooTable from.

	 * @returns {(FooTable.Table|undefined)}

	 */

	F.get = function(table){

		return $(table).first().data('__FooTable__');

	};



	/**

	 * Initializes a new instance of FooTable on the supplied table.

	 * @param {(jQuery|jQuery.selector|HTMLTableElement)} table - The jQuery table object, selector or the HTMLTableElement to initialize FooTable on.

	 * @param {object} options - The options to initialize FooTable with.

	 * @param {function} [ready] - A callback function to execute once the plugin is initialized.

	 * @returns {FooTable.Table}

	 */

	F.init = function(table, options, ready){

		var ft = F.get(table);

		if (ft instanceof F.Table) ft.destroy();

		return new F.Table(table, options, ready);

	};



	/**

	 * Gets the FooTable.Row instance for the supplied element.

	 * @param {(jQuery|jQuery.selector|HTMLTableElement)} element - A jQuery object, selector or the HTMLElement of an element to retrieve the FooTable.Row for.

	 * @returns {FooTable.Row}

	 */

	F.getRow = function(element){

		// to get the FooTable.Row object simply walk up the DOM, find the TR and grab the __FooTableRow__ data value

		var $row = $(element).closest('tr');

		// if this is a detail row get the previous row in the table to get the main TR element

		if ($row.hasClass('footable-detail-row')){

			$row = $row.prev();

		}

		// grab the row object

		return $row.data('__FooTableRow__');

	};



	// The below are external type definitions mainly used as pointers to jQuery docs for important information

	/**

	 * jQuery is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler with an easy-to-use API

	 * that works across a multitude of browsers. With a combination of versatility and extensibility, jQuery has changed the way that millions of people write JavaScript.

	 * @name jQuery

	 * @constructor

	 * @returns {jQuery}

	 * @see {@link http://api.jquery.com/}

	 */



	/**

	 * This object provides a subset of the methods of the Deferred object (then, done, fail, always, pipe, and state) to prevent users from changing the state of the Deferred.

	 * @typedef {object} jQuery.Promise

	 * @see {@link http://api.jquery.com/Types/#Promise}

	 */



	/**

	 * As of jQuery 1.5, the Deferred object provides a way to register multiple callbacks into self-managed callback queues, invoke callback queues as appropriate,

	 * and relay the success or failure state of any synchronous or asynchronous function.

	 * @typedef {object} jQuery.Deferred

	 * @see {@link http://api.jquery.com/Types/#Deferred}

	 */



	/**

	 * jQuery's event system normalizes the event object according to W3C standards. The event object is guaranteed to be passed to the event handler. Most properties from

	 * the original event are copied over and normalized to the new event object.

	 * @typedef {object} jQuery.Event

	 * @see {@link http://api.jquery.com/category/events/event-object/}

	 */



	/**

	 * Provides a way to execute callback functions based on one or more objects, usually Deferred objects that represent asynchronous events.

	 * @memberof jQuery

	 * @function when

	 * @param {...jQuery.Deferred} deferreds - Any number of deferred objects to wait for.

	 * @returns {jQuery.Promise}

	 * @see {@link http://api.jquery.com/jQuery.when/}

	 */



	/**

	 * The jQuery.fn namespace used to register plugins with jQuery.

	 * @memberof jQuery

	 * @namespace fn

	 * @see {@link http://learn.jquery.com/plugins/basic-plugin-creation/}

	 */

})(

	jQuery,

	/**

	 * The core FooTable namespace containing all the plugin code.

	 * @namespace

	 */

	FooTable = window.FooTable || {}

);