/*! AutoFill 2.2.2

 * ©2008-2017 SpryMedia Ltd - datatables.net/license

 */



/**

 * @summary     AutoFill

 * @description Add Excel like click and drag auto-fill options to DataTables

 * @version     2.2.2

 * @file        dataTables.autoFill.js

 * @author      SpryMedia Ltd (www.sprymedia.co.uk)

 * @contact     www.sprymedia.co.uk/contact

 * @copyright   Copyright 2010-2017 SpryMedia Ltd.

 *

 * This source file is free software, available under the following license:

 *   MIT license - http://datatables.net/license/mit

 *

 * This source file 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 license files for details.

 *

 * For details please refer to: http://www.datatables.net

 */

(function( factory ){

	if ( typeof define === 'function' && define.amd ) {

		// AMD

		define( ['jquery', 'datatables.net'], function ( $ ) {

			return factory( $, window, document );

		} );

	}

	else if ( typeof exports === 'object' ) {

		// CommonJS

		module.exports = function (root, $) {

			if ( ! root ) {

				root = window;

			}



			if ( ! $ || ! $.fn.dataTable ) {

				$ = require('datatables.net')(root, $).$;

			}



			return factory( $, root, root.document );

		};

	}

	else {

		// Browser

		factory( jQuery, window, document );

	}

}(function( $, window, document, undefined ) {

'use strict';

var DataTable = $.fn.dataTable;





var _instance = 0;



/** 

 * AutoFill provides Excel like auto-fill features for a DataTable

 *

 * @class AutoFill

 * @constructor

 * @param {object} oTD DataTables settings object

 * @param {object} oConfig Configuration object for AutoFill

 */

var AutoFill = function( dt, opts )

{

	if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {

		throw( "Warning: AutoFill requires DataTables 1.10.8 or greater");

	}



	// User and defaults configuration object

	this.c = $.extend( true, {},

		DataTable.defaults.autoFill,

		AutoFill.defaults,

		opts

	);



	/**

	 * @namespace Settings object which contains customisable information for AutoFill instance

	 */

	this.s = {

		/** @type {DataTable.Api} DataTables' API instance */

		dt: new DataTable.Api( dt ),



		/** @type {String} Unique namespace for events attached to the document */

		namespace: '.autoFill'+(_instance++),



		/** @type {Object} Cached dimension information for use in the mouse move event handler */

		scroll: {},



		/** @type {integer} Interval object used for smooth scrolling */

		scrollInterval: null,



		handle: {

			height: 0,

			width: 0

		},



		/**

		 * Enabled setting

		 * @type {Boolean}

		 */

		enabled: false

	};





	/**

	 * @namespace Common and useful DOM elements for the class instance

	 */

	this.dom = {

		/** @type {jQuery} AutoFill handle */

		handle: $('<div class="dt-autofill-handle"/>'),



		/**

		 * @type {Object} Selected cells outline - Need to use 4 elements,

		 *   otherwise the mouse over if you back into the selected rectangle

		 *   will be over that element, rather than the cells!

		 */

		select: {

			top:    $('<div class="dt-autofill-select top"/>'),

			right:  $('<div class="dt-autofill-select right"/>'),

			bottom: $('<div class="dt-autofill-select bottom"/>'),

			left:   $('<div class="dt-autofill-select left"/>')

		},



		/** @type {jQuery} Fill type chooser background */

		background: $('<div class="dt-autofill-background"/>'),



		/** @type {jQuery} Fill type chooser */

		list: $('<div class="dt-autofill-list">'+this.s.dt.i18n('autoFill.info', '')+'<ul/></div>'),



		/** @type {jQuery} DataTables scrolling container */

		dtScroll: null,



		/** @type {jQuery} Offset parent element */

		offsetParent: null

	};





	/* Constructor logic */

	this._constructor();

};







$.extend( AutoFill.prototype, {

	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	 * Public methods (exposed via the DataTables API below)

	 */

	enabled: function ()

	{

		return this.s.enabled;

	},





	enable: function ( flag )

	{

		var that = this;



		if ( flag === false ) {

			return this.disable();

		}



		this.s.enabled = true;



		this._focusListener();



		this.dom.handle.on( 'mousedown', function (e) {

			that._mousedown( e );

			return false;

		} );



		return this;

	},



	disable: function ()

	{

		this.s.enabled = false;



		this._focusListenerRemove();



		return this;

	},





	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	 * Constructor

	 */



	/**

	 * Initialise the RowReorder instance

	 *

	 * @private

	 */

	_constructor: function ()

	{

		var that = this;

		var dt = this.s.dt;

		var dtScroll = $('div.dataTables_scrollBody', this.s.dt.table().container());



		// Make the instance accessible to the API

		dt.settings()[0].autoFill = this;



		if ( dtScroll.length ) {

			this.dom.dtScroll = dtScroll;



			// Need to scroll container to be the offset parent

			if ( dtScroll.css('position') === 'static' ) {

				dtScroll.css( 'position', 'relative' );

			}

		}



		if ( this.c.enable !== false ) {

			this.enable();

		}



		dt.on( 'destroy.autoFill', function () {

			that._focusListenerRemove();

		} );

	},





	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

	 * Private methods

	 */



	/**

	 * Display the AutoFill drag handle by appending it to a table cell. This

	 * is the opposite of the _detach method.

	 *

	 * @param  {node} node TD/TH cell to insert the handle into

	 * @private

	 */

	_attach: function ( node )

	{

		var dt = this.s.dt;

		var idx = dt.cell( node ).index();

		var handle = this.dom.handle;

		var handleDim = this.s.handle;



		if ( ! idx || dt.columns( this.c.columns ).indexes().indexOf( idx.column ) === -1 ) {

			this._detach();

			return;

		}



		if ( ! this.dom.offsetParent ) {

			// We attach to the table's offset parent

			this.dom.offsetParent = $( dt.table().node() ).offsetParent();

		}



		if ( ! handleDim.height || ! handleDim.width ) {

			// Append to document so we can get its size. Not expecting it to

			// change during the life time of the page

			handle.appendTo( 'body' );

			handleDim.height = handle.outerHeight();

			handleDim.width = handle.outerWidth();

		}



		// Might need to go through multiple offset parents

		var offset = this._getPosition( node, this.dom.offsetParent );



		this.dom.attachedTo = node;

		handle

			.css( {

				top: offset.top + node.offsetHeight - handleDim.height,

				left: offset.left + node.offsetWidth - handleDim.width

			} )

			.appendTo( this.dom.offsetParent );

	},





	/**

	 * Determine can the fill type should be. This can be automatic, or ask the

	 * end user.

	 *

	 * @param {array} cells Information about the selected cells from the key

	 *     up function

	 * @private

	 */

	_actionSelector: function ( cells )

	{

		var that = this;

		var dt = this.s.dt;

		var actions = AutoFill.actions;

		var available = [];



		// "Ask" each plug-in if it wants to handle this data

		$.each( actions, function ( key, action ) {

			if ( action.available( dt, cells ) ) {

				available.push( key );

			}

		} );



		if ( available.length === 1 && this.c.alwaysAsk === false ) {

			// Only one action available - enact it immediately

			var result = actions[ available[0] ].execute( dt, cells );

			this._update( result, cells );

		}

		else {

			// Multiple actions available - ask the end user what they want to do

			var list = this.dom.list.children('ul').empty();



			// Add a cancel option

			available.push( 'cancel' );



			$.each( available, function ( i, name ) {

				list.append( $('<li/>')

					.append(

						'<div class="dt-autofill-question">'+

							actions[ name ].option( dt, cells )+

						'<div>'

					)

					.append( $('<div class="dt-autofill-button">' )

						.append( $('<button class="'+AutoFill.classes.btn+'">'+dt.i18n('autoFill.button', '&gt;')+'</button>')

							.on( 'click', function () {

								var result = actions[ name ].execute(

									dt, cells, $(this).closest('li')

								);

								that._update( result, cells );



								that.dom.background.remove();

								that.dom.list.remove();

							} )

						)

					)

				);

			} );



			this.dom.background.appendTo( 'body' );

			this.dom.list.appendTo( 'body' );



			this.dom.list.css( 'margin-top', this.dom.list.outerHeight()/2 * -1 );

		}

	},





	/**

	 * Remove the AutoFill handle from the document

	 *

	 * @private

	 */

	_detach: function ()

	{

		this.dom.attachedTo = null;

		this.dom.handle.detach();

	},





	/**

	 * Draw the selection outline by calculating the range between the start

	 * and end cells, then placing the highlighting elements to draw a rectangle

	 *

	 * @param  {node}   target End cell

	 * @param  {object} e      Originating event

	 * @private

	 */

	_drawSelection: function ( target, e )

	{

		// Calculate boundary for start cell to this one

		var dt = this.s.dt;

		var start = this.s.start;

		var startCell = $(this.dom.start);

		var endCell = $(target);

		var end = {

			row: dt.rows( { page: 'current' } ).nodes().indexOf( endCell.parent()[0] ),

			column: endCell.index()

		};

		var colIndx = dt.column.index( 'toData', end.column );



		// Be sure that is a DataTables controlled cell

		if ( ! dt.cell( endCell ).any() ) {

			return;

		}



		// if target is not in the columns available - do nothing

		if ( dt.columns( this.c.columns ).indexes().indexOf( colIndx ) === -1 ) {

			return;

		}



		this.s.end = end;



		var top, bottom, left, right, height, width;



		top    = start.row    < end.row    ? startCell : endCell;

		bottom = start.row    < end.row    ? endCell   : startCell;

		left   = start.column < end.column ? startCell : endCell;

		right  = start.column < end.column ? endCell   : startCell;



		top    = this._getPosition( top ).top;

		left   = this._getPosition( left ).left;

		height = this._getPosition( bottom ).top + bottom.outerHeight() - top;

		width  = this._getPosition( right ).left + right.outerWidth() - left;



		var select = this.dom.select;

		select.top.css( {

			top: top,

			left: left,

			width: width

		} );



		select.left.css( {

			top: top,

			left: left,

			height: height

		} );



		select.bottom.css( {

			top: top + height,

			left: left,

			width: width

		} );



		select.right.css( {

			top: top,

			left: left + width,

			height: height

		} );

	},





	/**

	 * Use the Editor API to perform an update based on the new data for the

	 * cells

	 *

	 * @param {array} cells Information about the selected cells from the key

	 *     up function

	 * @private

	 */

	_editor: function ( cells )

	{

		var dt = this.s.dt;

		var editor = this.c.editor;



		if ( ! editor ) {

			return;

		}



		// Build the object structure for Editor's multi-row editing

		var idValues = {};

		var nodes = [];

		var fields = editor.fields();



		for ( var i=0, ien=cells.length ; i<ien ; i++ ) {

			for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {

				var cell = cells[i][j];



				// Determine the field name for the cell being edited

				var col = dt.settings()[0].aoColumns[ cell.index.column ];

				var fieldName = col.editField;



				if ( fieldName === undefined ) {

					var dataSrc = col.mData;



					// dataSrc is the `field.data` property, but we need to set

					// using the field name, so we need to translate from the

					// data to the name

					for ( var k=0, ken=fields.length ; k<ken ; k++ ) {

						var field = editor.field( fields[k] );



						if ( field.dataSrc() === dataSrc ) {

							fieldName = field.name();

							break;

						}

					}

				}



				if ( ! fieldName ) {

					throw 'Could not automatically determine field data. '+

						'Please see https://datatables.net/tn/11';

				}



				if ( ! idValues[ fieldName ] ) {

					idValues[ fieldName ] = {};

				}



				var id = dt.row( cell.index.row ).id();

				idValues[ fieldName ][ id ] = cell.set;



				// Keep a list of cells so we can activate the bubble editing

				// with them

				nodes.push( cell.index );

			}

		}



		// Perform the edit using bubble editing as it allows us to specify

		// the cells to be edited, rather than using full rows

		editor

			.bubble( nodes, false )

			.multiSet( idValues )

			.submit();

	},





	/**

	 * Emit an event on the DataTable for listeners

	 *

	 * @param  {string} name Event name

	 * @param  {array} args Event arguments

	 * @private

	 */

	_emitEvent: function ( name, args )

	{

		this.s.dt.iterator( 'table', function ( ctx, i ) {

			$(ctx.nTable).triggerHandler( name+'.dt', args );

		} );

	},





	/**

	 * Attach suitable listeners (based on the configuration) that will attach

	 * and detach the AutoFill handle in the document.

	 *

	 * @private

	 */

	_focusListener: function ()

	{

		var that = this;

		var dt = this.s.dt;

		var namespace = this.s.namespace;

		var focus = this.c.focus !== null ?

			this.c.focus :

			dt.init().keys || dt.settings()[0].keytable ?

				'focus' :

				'hover';



		// All event listeners attached here are removed in the `destroy`

		// callback in the constructor

		if ( focus === 'focus' ) {

			dt

				.on( 'key-focus.autoFill', function ( e, dt, cell ) {

					that._attach( cell.node() );

				} )

				.on( 'key-blur.autoFill', function ( e, dt, cell ) {

					that._detach();

				} );

		}

		else if ( focus === 'click' ) {

			$(dt.table().body()).on( 'click'+namespace, 'td, th', function (e) {

				that._attach( this );

			} );



			$(document.body).on( 'click'+namespace, function (e) {

				if ( ! $(e.target).parents().filter( dt.table().body() ).length ) {

					that._detach();

				}

			} );

		}

		else {

			$(dt.table().body())

				.on( 'mouseenter'+namespace, 'td, th', function (e) {

					that._attach( this );

				} )

				.on( 'mouseleave'+namespace, function (e) {

					if ( $(e.relatedTarget).hasClass('dt-autofill-handle') ) {

						return;

					}



					that._detach();

				} );

		}

	},





	_focusListenerRemove: function ()

	{

		var dt = this.s.dt;



		dt.off( '.autoFill' );

		$(dt.table().body()).off( this.s.namespace );

		$(document.body).off( this.s.namespace );

	},





	/**

	 * Get the position of a node, relative to another, including any scrolling

	 * offsets.

	 * @param  {Node}   node         Node to get the position of

	 * @param  {jQuery} targetParent Node to use as the parent

	 * @return {object}              Offset calculation

	 * @private

	 */

	_getPosition: function ( node, targetParent )

	{

		var

			currNode = $(node),

			currOffsetParent,

			position,

			top = 0,

			left = 0;



		if ( ! targetParent ) {

			targetParent = $( this.s.dt.table().node() ).offsetParent();

		}



		do {

			position = currNode.position();

			currOffsetParent = currNode.offsetParent();



			top += position.top + currOffsetParent.scrollTop();

			left += position.left + currOffsetParent.scrollLeft();



			// Emergency fall back. Shouldn't happen, but just in case!

			if ( currNode.get(0).nodeName.toLowerCase() === 'body' ) {

				break;

			}



			currNode = currOffsetParent; // for next loop

		}

		while ( currOffsetParent.get(0) !== targetParent.get(0) )



		return {

			top: top,

			left: left

		};

	},





	/**

	 * Start mouse drag - selects the start cell

	 *

	 * @param  {object} e Mouse down event

	 * @private

	 */

	_mousedown: function ( e )

	{

		var that = this;

		var dt = this.s.dt;



		this.dom.start = this.dom.attachedTo;

		this.s.start = {

			row: dt.rows( { page: 'current' } ).nodes().indexOf( $(this.dom.start).parent()[0] ),

			column: $(this.dom.start).index()

		};



		$(document.body)

			.on( 'mousemove.autoFill', function (e) {

				that._mousemove( e );

			} )

			.on( 'mouseup.autoFill', function (e) {

				that._mouseup( e );

			} );



		var select = this.dom.select;

		var offsetParent = $( dt.table().node() ).offsetParent();

		select.top.appendTo( offsetParent );

		select.left.appendTo( offsetParent );

		select.right.appendTo( offsetParent );

		select.bottom.appendTo( offsetParent );



		this._drawSelection( this.dom.start, e );



		this.dom.handle.css( 'display', 'none' );



		// Cache scrolling information so mouse move doesn't need to read.

		// This assumes that the window and DT scroller will not change size

		// during an AutoFill drag, which I think is a fair assumption

		var scrollWrapper = this.dom.dtScroll;

		this.s.scroll = {

			windowHeight: $(window).height(),

			windowWidth:  $(window).width(),

			dtTop:        scrollWrapper ? scrollWrapper.offset().top : null,

			dtLeft:       scrollWrapper ? scrollWrapper.offset().left : null,

			dtHeight:     scrollWrapper ? scrollWrapper.outerHeight() : null,

			dtWidth:      scrollWrapper ? scrollWrapper.outerWidth() : null

		};

	},





	/**

	 * Mouse drag - selects the end cell and update the selection display for

	 * the end user

	 *

	 * @param  {object} e Mouse move event

	 * @private

	 */

	_mousemove: function ( e )

	{	

		var that = this;

		var dt = this.s.dt;

		var name = e.target.nodeName.toLowerCase();

		if ( name !== 'td' && name !== 'th' ) {

			return;

		}



		this._drawSelection( e.target, e );

		this._shiftScroll( e );

	},





	/**

	 * End mouse drag - perform the update actions

	 *

	 * @param  {object} e Mouse up event

	 * @private

	 */

	_mouseup: function ( e )

	{

		$(document.body).off( '.autoFill' );



		var dt = this.s.dt;

		var select = this.dom.select;

		select.top.remove();

		select.left.remove();

		select.right.remove();

		select.bottom.remove();



		this.dom.handle.css( 'display', 'block' );



		// Display complete - now do something useful with the selection!

		var start = this.s.start;

		var end = this.s.end;



		// Haven't selected multiple cells, so nothing to do

		if ( start.row === end.row && start.column === end.column ) {

			return;

		}



		// Build a matrix representation of the selected rows

		var rows       = this._range( start.row, end.row );

		var columns    = this._range( start.column, end.column );

		var selected   = [];

		var dtSettings = dt.settings()[0];

		var dtColumns  = dtSettings.aoColumns;



		// Can't use Array.prototype.map as IE8 doesn't support it

		// Can't use $.map as jQuery flattens 2D arrays

		// Need to use a good old fashioned for loop

		for ( var rowIdx=0 ; rowIdx<rows.length ; rowIdx++ ) {

			selected.push(

				$.map( columns, function (column) {

					var cell = dt.cell( ':eq('+rows[rowIdx]+')', column+':visible', {page:'current'} );

					var data = cell.data();

					var cellIndex = cell.index();

					var editField = dtColumns[ cellIndex.column ].editField;



					if ( editField !== undefined ) {

						data = dtSettings.oApi._fnGetObjectDataFn( editField )( dt.row( cellIndex.row ).data() );

					}



					return {

						cell:  cell,

						data:  data,

						label: cell.data(),

						index: cellIndex

					};

				} )

			);

		}



		this._actionSelector( selected );

		

		// Stop shiftScroll

		clearInterval( this.s.scrollInterval );

		this.s.scrollInterval = null;

	},





	/**

	 * Create an array with a range of numbers defined by the start and end

	 * parameters passed in (inclusive!).

	 * 

	 * @param  {integer} start Start

	 * @param  {integer} end   End

	 * @private

	 */

	_range: function ( start, end )

	{

		var out = [];

		var i;



		if ( start <= end ) {

			for ( i=start ; i<=end ; i++ ) {

				out.push( i );

			}

		}

		else {

			for ( i=start ; i>=end ; i-- ) {

				out.push( i );

			}

		}



		return out;

	},





	/**

	 * Move the window and DataTables scrolling during a drag to scroll new

	 * content into view. This is done by proximity to the edge of the scrolling

	 * container of the mouse - for example near the top edge of the window

	 * should scroll up. This is a little complicated as there are two elements

	 * that can be scrolled - the window and the DataTables scrolling view port

	 * (if scrollX and / or scrollY is enabled).

	 *

	 * @param  {object} e Mouse move event object

	 * @private

	 */

	_shiftScroll: function ( e )

	{

		var that = this;

		var dt = this.s.dt;

		var scroll = this.s.scroll;

		var runInterval = false;

		var scrollSpeed = 5;

		var buffer = 65;

		var

			windowY = e.pageY - document.body.scrollTop,

			windowX = e.pageX - document.body.scrollLeft,

			windowVert, windowHoriz,

			dtVert, dtHoriz;



		// Window calculations - based on the mouse position in the window,

		// regardless of scrolling

		if ( windowY < buffer ) {

			windowVert = scrollSpeed * -1;

		}

		else if ( windowY > scroll.windowHeight - buffer ) {

			windowVert = scrollSpeed;

		}



		if ( windowX < buffer ) {

			windowHoriz = scrollSpeed * -1;

		}

		else if ( windowX > scroll.windowWidth - buffer ) {

			windowHoriz = scrollSpeed;

		}



		// DataTables scrolling calculations - based on the table's position in

		// the document and the mouse position on the page

		if ( scroll.dtTop !== null && e.pageY < scroll.dtTop + buffer ) {

			dtVert = scrollSpeed * -1;

		}

		else if ( scroll.dtTop !== null && e.pageY > scroll.dtTop + scroll.dtHeight - buffer ) {

			dtVert = scrollSpeed;

		}



		if ( scroll.dtLeft !== null && e.pageX < scroll.dtLeft + buffer ) {

			dtHoriz = scrollSpeed * -1;

		}

		else if ( scroll.dtLeft !== null && e.pageX > scroll.dtLeft + scroll.dtWidth - buffer ) {

			dtHoriz = scrollSpeed;

		}



		// This is where it gets interesting. We want to continue scrolling

		// without requiring a mouse move, so we need an interval to be

		// triggered. The interval should continue until it is no longer needed,

		// but it must also use the latest scroll commands (for example consider

		// that the mouse might move from scrolling up to scrolling left, all

		// with the same interval running. We use the `scroll` object to "pass"

		// this information to the interval. Can't use local variables as they

		// wouldn't be the ones that are used by an already existing interval!

		if ( windowVert || windowHoriz || dtVert || dtHoriz ) {

			scroll.windowVert = windowVert;

			scroll.windowHoriz = windowHoriz;

			scroll.dtVert = dtVert;

			scroll.dtHoriz = dtHoriz;

			runInterval = true;

		}

		else if ( this.s.scrollInterval ) {

			// Don't need to scroll - remove any existing timer

			clearInterval( this.s.scrollInterval );

			this.s.scrollInterval = null;

		}



		// If we need to run the interval to scroll and there is no existing

		// interval (if there is an existing one, it will continue to run)

		if ( ! this.s.scrollInterval && runInterval ) {

			this.s.scrollInterval = setInterval( function () {

				// Don't need to worry about setting scroll <0 or beyond the

				// scroll bound as the browser will just reject that.

				if ( scroll.windowVert ) {

					document.body.scrollTop += scroll.windowVert;

				}

				if ( scroll.windowHoriz ) {

					document.body.scrollLeft += scroll.windowHoriz;

				}



				// DataTables scrolling

				if ( scroll.dtVert || scroll.dtHoriz ) {

					var scroller = that.dom.dtScroll[0];



					if ( scroll.dtVert ) {

						scroller.scrollTop += scroll.dtVert;

					}

					if ( scroll.dtHoriz ) {

						scroller.scrollLeft += scroll.dtHoriz;

					}

				}

			}, 20 );

		}

	},





	/**

	 * Update the DataTable after the user has selected what they want to do

	 *

	 * @param  {false|undefined} result Return from the `execute` method - can

	 *   be false internally to do nothing. This is not documented for plug-ins

	 *   and is used only by the cancel option.

	 * @param {array} cells Information about the selected cells from the key

	 *     up function, argumented with the set values

	 * @private

	 */

	_update: function ( result, cells )

	{

		// Do nothing on `false` return from an execute function

		if ( result === false ) {

			return;

		}



		var dt = this.s.dt;

		var cell;



		// Potentially allow modifications to the cells matrix

		this._emitEvent( 'preAutoFill', [ dt, cells ] );



		this._editor( cells );



		// Automatic updates are not performed if `update` is null and the

		// `editor` parameter is passed in - the reason being that Editor will

		// update the data once submitted

		var update = this.c.update !== null ?

			this.c.update :

			this.c.editor ?

				false :

				true;



		if ( update ) {

			for ( var i=0, ien=cells.length ; i<ien ; i++ ) {

				for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {

					cell = cells[i][j];



					cell.cell.data( cell.set );

				}

			}



			dt.draw(false);

		}



		this._emitEvent( 'autoFill', [ dt, cells ] );

	}

} );





/**

 * AutoFill actions. The options here determine how AutoFill will fill the data

 * in the table when the user has selected a range of cells. Please see the

 * documentation on the DataTables site for full details on how to create plug-

 * ins.

 *

 * @type {Object}

 */

AutoFill.actions = {

	increment: {

		available: function ( dt, cells ) {

			return $.isNumeric( cells[0][0].label );

		},



		option: function ( dt, cells ) {

			return dt.i18n(

				'autoFill.increment',

				'Increment / decrement each cell by: <input type="number" value="1">'

			);

		},



		execute: function ( dt, cells, node ) {

			var value = cells[0][0].data * 1;

			var increment = $('input', node).val() * 1;



			for ( var i=0, ien=cells.length ; i<ien ; i++ ) {

				for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {

					cells[i][j].set = value;



					value += increment;

				}

			}

		}

	},



	fill: {

		available: function ( dt, cells ) {

			return true;

		},



		option: function ( dt, cells ) {

			return dt.i18n('autoFill.fill', 'Fill all cells with <i>'+cells[0][0].label+'</i>' );

		},



		execute: function ( dt, cells, node ) {

			var value = cells[0][0].data;



			for ( var i=0, ien=cells.length ; i<ien ; i++ ) {

				for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {

					cells[i][j].set = value;

				}

			}

		}

	},



	fillHorizontal: {

		available: function ( dt, cells ) {

			return cells.length > 1 && cells[0].length > 1;

		},



		option: function ( dt, cells ) {

			return dt.i18n('autoFill.fillHorizontal', 'Fill cells horizontally' );

		},



		execute: function ( dt, cells, node ) {

			for ( var i=0, ien=cells.length ; i<ien ; i++ ) {

				for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {

					cells[i][j].set = cells[i][0].data;

				}

			}

		}

	},



	fillVertical: {

		available: function ( dt, cells ) {

			return cells.length > 1 && cells[0].length > 1;

		},



		option: function ( dt, cells ) {

			return dt.i18n('autoFill.fillVertical', 'Fill cells vertically' );

		},



		execute: function ( dt, cells, node ) {

			for ( var i=0, ien=cells.length ; i<ien ; i++ ) {

				for ( var j=0, jen=cells[i].length ; j<jen ; j++ ) {

					cells[i][j].set = cells[0][j].data;

				}

			}

		}

	},



	// Special type that does not make itself available, but is added

	// automatically by AutoFill if a multi-choice list is shown. This allows

	// sensible code reuse

	cancel: {

		available: function () {

			return false;

		},



		option: function ( dt ) {

			return dt.i18n('autoFill.cancel', 'Cancel' );

		},



		execute: function () {

			return false;

		}

	}

};





/**

 * AutoFill version

 * 

 * @static

 * @type      String

 */

AutoFill.version = '2.2.2';





/**

 * AutoFill defaults

 * 

 * @namespace

 */

AutoFill.defaults = {

	/** @type {Boolean} Ask user what they want to do, even for a single option */

	alwaysAsk: false,



	/** @type {string|null} What will trigger a focus */

	focus: null, // focus, click, hover



	/** @type {column-selector} Columns to provide auto fill for */

	columns: '', // all



	/** @type {Boolean} Enable AutoFill on load */

	enable: true,



	/** @type {boolean|null} Update the cells after a drag */

	update: null, // false is editor given, true otherwise



	/** @type {DataTable.Editor} Editor instance for automatic submission */

	editor: null

};





/**

 * Classes used by AutoFill that are configurable

 * 

 * @namespace

 */

AutoFill.classes = {

	/** @type {String} Class used by the selection button */

	btn: 'btn'

};





/*

 * API

 */

var Api = $.fn.dataTable.Api;



// Doesn't do anything - Not documented

Api.register( 'autoFill()', function () {

	return this;

} );



Api.register( 'autoFill().enabled()', function () {

	var ctx = this.context[0];



	return ctx.autoFill ?

		ctx.autoFill.enabled() :

		false;

} );



Api.register( 'autoFill().enable()', function ( flag ) {

	return this.iterator( 'table', function ( ctx ) {

		if ( ctx.autoFill ) {

			ctx.autoFill.enable( flag );

		}

	} );

} );



Api.register( 'autoFill().disable()', function () {

	return this.iterator( 'table', function ( ctx ) {

		if ( ctx.autoFill ) {

			ctx.autoFill.disable();

		}

	} );

} );





// Attach a listener to the document which listens for DataTables initialisation

// events so we can automatically initialise

$(document).on( 'preInit.dt.autofill', function (e, settings, json) {

	if ( e.namespace !== 'dt' ) {

		return;

	}



	var init = settings.oInit.autoFill;

	var defaults = DataTable.defaults.autoFill;



	if ( init || defaults ) {

		var opts = $.extend( {}, init, defaults );



		if ( init !== false ) {

			new AutoFill( settings, opts  );

		}

	}

} );





// Alias for access

DataTable.AutoFill = AutoFill;

DataTable.AutoFill = AutoFill;





return AutoFill;

}));

