(function($){

	$.entwine('ss', function($) {
		$('.ss-gridfield').entwine({
			/**
			 * @param {Object} Additional options for jQuery.ajax() call
			 * @param {successCallback} callback to call after reloading succeeded.
			 */

			reload: function(ajaxOpts, successCallback) {
				var self = this, form = this.closest('form'),
					focusedElName = this.find(':input:focus').attr('name'), // Save focused element for restoring after refresh
					data = form.find(':input').serializeArray();

				if(!ajaxOpts) ajaxOpts = {};
				if(!ajaxOpts.data) ajaxOpts.data = [];
				ajaxOpts.data = ajaxOpts.data.concat(data);


				// Include any GET parameters from the current URL, as the view state might depend on it.
				// For example, a list prefiltered through external search criteria might be passed to GridField.
				if(window.location.search) {
					ajaxOpts.data = window.location.search.replace(/^\?/, '') + '&' + $.param(ajaxOpts.data);
				}

				// For browsers which do not support history.pushState like IE9, ss framework uses hash to track
				// the current location for PJAX, so for them we pass the query string stored in the hash instead
				if(!window.history || !window.history.pushState){
					if(window.location.hash && window.location.hash.indexOf('?') != -1){
						ajaxOpts.data = window.location.hash.substring(window.location.hash.indexOf('?') + 1) + '&' + $.param(ajaxOpts.data);
					}
				}

				form.addClass('loading');

				$.ajax($.extend({}, {
					headers: {"X-Pjax" : 'CurrentField'},
					type: "POST",
					url: this.data('url'),
					dataType: 'html',
					success: function(data) {
						// Replace the grid field with response, not the form.
						// TODO Only replaces all its children, to avoid replacing the current scope
						// of the executing method. Means that it doesn't retrigger the onmatch() on the main container.
						self.empty().append($(data).children());

						// Refocus previously focused element. Useful e.g. for finding+adding
						// multiple relationships via keyboard.
						if(focusedElName) self.find(':input[name="' + focusedElName + '"]').focus();

						// Update filter
						if(self.find('.filter-header').length) {
							var content;
							if(ajaxOpts.data[0].filter=="show") {
								content = '<span class="non-sortable"></span>';
								self.addClass('show-filter').find('.filter-header').show();
							} else {
								content = '<button name="showFilter" class="ss-gridfield-button-filter trigger"></button>';
								self.removeClass('show-filter').find('.filter-header').hide();
							}

							self.find('.sortable-header th:last').html(content);
						}

						form.removeClass('loading');
						if(successCallback) successCallback.apply(this, arguments);
						self.trigger('reload', self);
					},
					error: function(e) {
						alert(ss.i18n._t('GRIDFIELD.ERRORINTRANSACTION'));
						form.removeClass('loading');
					}
				}, ajaxOpts));
			},
			showDetailView: function(url) {
				window.location.href = url;
			},
			getItems: function() {
				return this.find('.ss-gridfield-item');
			},
			/**
			 * @param {String}
			 * @param {Mixed}
			 */
			setState: function(k, v) {
				var state = this.getState();
				state[k] = v;
				this.find(':input[name="' + this.data('name') + '[GridState]"]').val(JSON.stringify(state));
			},
			/**
			 * @return {Object}
			 */
			getState: function() {
				return JSON.parse(this.find(':input[name="' + this.data('name') + '[GridState]"]').val());
			}
		});

		$('.ss-gridfield *').entwine({
			getGridField: function() {
				return this.closest('.ss-gridfield');
			}
		});



		$('.ss-gridfield :button[name=showFilter]').entwine({
			onclick: function(e) {
				$('.filter-header')
					.show('slow') // animate visibility
					.find(':input:first').focus(); // focus first search field
				this.closest('.ss-gridfield').addClass('show-filter');
				this.parent().html('<span class="non-sortable"></span>');
				e.preventDefault();
			}
		});


		$('.ss-gridfield .ss-gridfield-item').entwine({
			onclick: function(e) {
				if($(e.target).closest('.action').length) {
					this._super(e);
					return false;
				}

				var editLink = this.find('.edit-link');
				if(editLink.length) this.getGridField().showDetailView(editLink.prop('href'));
			},
			onmouseover: function() {
				if(this.find('.edit-link').length) this.css('cursor', 'pointer');
			},
			onmouseout: function() {
				this.css('cursor', 'default');
			}
		});

		$('.ss-gridfield .action').entwine({
			onclick: function(e){
				var filterState='show'; //filterstate should equal current state.

				// If the button is disabled, do nothing.
				if (this.button('option', 'disabled')) {
					e.preventDefault();
					return;
				}

				if(this.hasClass('ss-gridfield-button-close') || !(this.closest('.ss-gridfield').hasClass('show-filter'))){
					filterState='hidden';
				}

				this.getGridField().reload({data: [{name: this.attr('name'), value: this.val(), filter: filterState}]});
				e.preventDefault();
			},
			/**
			 * Get the url this action should submit to
			 */
			actionurl: function() {
				var btn = this.closest(':button'), grid = this.getGridField(),
					form = this.closest('form'), data = form.find(':input.gridstate').serialize(),
					csrf = form.find('input[name="SecurityID"]').val();

				// Add current button
				data += "&" + encodeURIComponent(btn.attr('name')) + '=' + encodeURIComponent(btn.val());

				// Add csrf
				if(csrf) {
					data += "&SecurityID=" + encodeURIComponent(csrf);
				}

				// Include any GET parameters from the current URL, as the view
				// state might depend on it. For example, a list pre-filtered
				// through external search criteria might be passed to GridField.
				if(window.location.search) {
					data = window.location.search.replace(/^\?/, '') + '&' + data;
				}

				// decide whether we should use ? or & to connect the URL
				var connector = grid.data('url').indexOf('?') == -1 ? '?' : '&';

				return $.path.makeUrlAbsolute(
					grid.data('url') + connector + data,
					$('base').attr('href')
				);
			}

		});

		/**
		 * Don't allow users to submit empty values in grid field auto complete inputs.
		 */
		$('.ss-gridfield .add-existing-autocompleter').entwine({
			onbuttoncreate: function () {
				var self = this;

				this.toggleDisabled();

				this.find('input[type="text"]').on('keyup', function () {
					self.toggleDisabled();
				});
			},
			onunmatch: function () {
				this.find('input[type="text"]').off('keyup');
			},
			toggleDisabled: function () {
				var $button = this.find('.ss-ui-button'),
					$input = this.find('input[type="text"]'),
					inputHasValue = $input.val() !== '',
					buttonDisabled = $button.is(':disabled');

				if ((inputHasValue && buttonDisabled) || (!inputHasValue && !buttonDisabled)) {
					$button.button("option", "disabled", !buttonDisabled);
				}
			}
		});

		// Covers both tabular delete button, and the button on the detail form
		$('.ss-gridfield .col-buttons .action.gridfield-button-delete, .cms-edit-form .Actions button.action.action-delete').entwine({
			onclick: function(e){
				if(!confirm(ss.i18n._t('TABLEFIELD.DELETECONFIRMMESSAGE'))) {
					e.preventDefault();
					return false;
				} else {
					this._super(e);
				}
			}
		});

		$('.ss-gridfield .action.gridfield-button-print').entwine({
			UUID: null,
			onmatch: function() {
				this._super();
				this.setUUID(new Date().getTime());
			},
			onunmatch: function() {
				this._super();
			},
			onclick: function(e){
				var url = this.actionurl();
				window.open(url);
				e.preventDefault();
				return false;
			}
		});

		$('.ss-gridfield-print-iframe').entwine({
			onmatch: function(){
				this._super();

				this.hide().bind('load', function() {
					this.focus();
					var ifWin = this.contentWindow || this;
					ifWin.print();
				});
			},
			onunmatch: function() {
				this._super();
			}
		});

		/**
		 * Prevents actions from causing an ajax reload of the field.
		 *
		 * Useful e.g. for actions which rely on HTTP response headers being
		 * interpreted natively by the browser, like file download triggers.
		 */
		$('.ss-gridfield .action.no-ajax').entwine({
			onclick: function(e){
				window.location.href = this.actionurl();
				e.preventDefault();
				return false;
			}
		});

		$('.ss-gridfield .action-detail').entwine({
			onclick: function() {
				this.getGridField().showDetailView($(this).prop('href'));
				return false;
			}
		});

		/**
		 * Allows selection of one or more rows in the grid field.
		 * Purely clientside at the moment.
		 */
		$('.ss-gridfield[data-selectable]').entwine({
			/**
			 * @return {jQuery} Collection
			 */
			getSelectedItems: function() {
				return this.find('.ss-gridfield-item.ui-selected');
			},
			/**
			 * @return {Array} Of record IDs
			 */
			getSelectedIDs: function() {
				return $.map(this.getSelectedItems(), function(el) {return $(el).data('id');});
			}
		});
		$('.ss-gridfield[data-selectable] .ss-gridfield-items').entwine({
			onadd: function() {
				this._super();

				// TODO Limit to single selection
				this.selectable();
			},
			onremove: function() {
				this._super();
				if (this.data('selectable')) this.selectable('destroy');
			}
		});

		/**
		 * Catch submission event in filter input fields, and submit the correct button
		 * rather than the whole form.
		 */
		$('.ss-gridfield .filter-header :input').entwine({
			onmatch: function() {
				var filterbtn = this.closest('.fieldgroup').find('.ss-gridfield-button-filter'),
					resetbtn = this.closest('.fieldgroup').find('.ss-gridfield-button-reset');

				if(this.val()) {
					filterbtn.addClass('filtered');
					resetbtn.addClass('filtered');
				}
				this._super();
			},
			onunmatch: function() {
				this._super();
			},
			onkeydown: function(e) {
				// Skip reset button events, they should trigger default submission
				if(this.closest('.ss-gridfield-button-reset').length) return;

				var filterbtn = this.closest('.fieldgroup').find('.ss-gridfield-button-filter'),
					resetbtn = this.closest('.fieldgroup').find('.ss-gridfield-button-reset');

				if(e.keyCode == '13') {
					var btns = this.closest('.filter-header').find('.ss-gridfield-button-filter');
					var filterState='show'; //filterstate should equal current state.
					if(this.hasClass('ss-gridfield-button-close')||!(this.closest('.ss-gridfield').hasClass('show-filter'))){
						filterState='hidden';
					}

					this.getGridField().reload({data: [{name: btns.attr('name'), value: btns.val(), filter: filterState}]});
					return false;
				}else{
					filterbtn.addClass('hover-alike');
					resetbtn.addClass('hover-alike');
				}
			}
		});

		$(".ss-gridfield .relation-search").entwine({
			onfocusin: function (event) {
				this.autocomplete({
					source: function(request, response){
						var searchField = $(this.element);
						var form = $(this.element).closest("form");
						$.ajax({
							headers: {
								"X-Pjax" : 'Partial'
							},
							type: "GET",
							url: $(searchField).data('searchUrl'),
							data: encodeURIComponent(searchField.attr('name'))+'='+encodeURIComponent(searchField.val()),
							success: function(data) {
								response( $.map(JSON.parse(data), function( name, id ) {
									return { label: name, value: name, id: id };
								}));
							},
							error: function(e) {
								alert(ss.i18n._t('GRIDFIELD.ERRORINTRANSACTION', 'An error occured while fetching data from the server\n Please try again later.'));
							}
						});
					},
					select: function(event, ui) {
						$(this).closest(".ss-gridfield").find("#action_gridfield_relationfind").replaceWith(
							'<input type="hidden" name="relationID" value="'+ui.item.id+'" id="relationID"/>'
						);
						var addbutton = $(this).closest(".ss-gridfield").find("#action_gridfield_relationadd");
						if(addbutton.data('button')){
							addbutton.button('enable');
						}else{
							addbutton.removeAttr('disabled');
						}
					}
				});
			}
		});

		$(".ss-gridfield .pagination-page-number input").entwine({
			onkeydown: function(event) {
				if(event.keyCode == 13) {
					var newpage = parseInt($(this).val(), 10);

					var gridfield = $(this).getGridField();
					gridfield.setState('GridFieldPaginator', {currentPage: newpage});
					gridfield.reload();

					return false;
				}
			}
		});
	});
}(jQuery));