/*!
 * jQuery UI Selectable 1.12.0
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Selectable
//>>group: Interactions
//>>description: Allows groups of elements to be selected with the mouse.
//>>docs: http://api.jqueryui.com/selectable/
//>>demos: http://jqueryui.com/selectable/
//>>css.structure: ../../themes/base/selectable.css
import $ from 'jquery';
import {
	ui
} from '../position.js';

import {
	widget
} from '../widget.js';

import {
	plugin
} from '../plugin.js';

import {
	mouse
} from './mouse.js';

widget("ui.selectable", mouse, {
	version: "1.12.0",
	options: {
		appendTo: "body",
		autoRefresh: true,
		distance: 0,
		filter: "*",
		tolerance: "touch",

		// Callbacks
		selected: null,
		selecting: null,
		start: null,
		stop: null,
		unselected: null,
		unselecting: null
	},
	_create: function () {
		var that = this;

		this._addClass("ui-selectable");

		this.dragged = false;

		// Cache selectee children based on filter
		this.refresh = function () {
			that.elementPos = $(that.element[0]).offset();
			that.selectees = $(that.options.filter, that.element[0]);
			that._addClass(that.selectees, "ui-selectee");
			that.selectees.each(function () {
				var $this = $(this),
					selecteeOffset = $this.offset(),
					pos = {
						left: selecteeOffset.left - that.elementPos.left,
						top: selecteeOffset.top - that.elementPos.top
					};
				$.data(this, "selectable-item", {
					element: this,
					$element: $this,
					left: pos.left,
					top: pos.top,
					right: pos.left + $this.outerWidth(),
					bottom: pos.top + $this.outerHeight(),
					startselected: false,
					selected: $this.hasClass("ui-selected"),
					selecting: $this.hasClass("ui-selecting"),
					unselecting: $this.hasClass("ui-unselecting")
				});
			});
		};
		this.refresh();

		this._mouseInit();

		this.helper = $("<div>");
		this._addClass(this.helper, "ui-selectable-helper");
	},

	_destroy: function () {
		this.selectees.removeData("selectable-item");
		this._mouseDestroy();
	},

	_mouseStart: function (event) {
		var that = this,
			options = this.options;

		this.opos = [event.pageX, event.pageY];
		this.elementPos = $(this.element[0]).offset();

		if (this.options.disabled) {
			return;
		}

		this.selectees = $(options.filter, this.element[0]);

		this._trigger("start", event);

		$(options.appendTo).append(this.helper);

		// position helper (lasso)
		this.helper.css({
			"left": event.pageX,
			"top": event.pageY,
			"width": 0,
			"height": 0
		});

		if (options.autoRefresh) {
			this.refresh();
		}

		this.selectees.filter(".ui-selected").each(function () {
			var selectee = $.data(this, "selectable-item");
			selectee.startselected = true;
			if (!event.metaKey && !event.ctrlKey) {
				that._removeClass(selectee.$element, "ui-selected");
				selectee.selected = false;
				that._addClass(selectee.$element, "ui-unselecting");
				selectee.unselecting = true;

				// selectable UNSELECTING callback
				that._trigger("unselecting", event, {
					unselecting: selectee.element
				});
			}
		});

		$(event.target).parents().addBack().each(function () {
			var doSelect,
				selectee = $.data(this, "selectable-item");
			if (selectee) {
				doSelect = (!event.metaKey && !event.ctrlKey) ||
					!selectee.$element.hasClass("ui-selected");
				that._removeClass(selectee.$element, doSelect ? "ui-unselecting" : "ui-selected")
					._addClass(selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting");
				selectee.unselecting = !doSelect;
				selectee.selecting = doSelect;
				selectee.selected = doSelect;

				// selectable (UN)SELECTING callback
				if (doSelect) {
					that._trigger("selecting", event, {
						selecting: selectee.element
					});
				} else {
					that._trigger("unselecting", event, {
						unselecting: selectee.element
					});
				}
				return false;
			}
		});

	},

	_mouseDrag: function (event) {

		this.dragged = true;

		if (this.options.disabled) {
			return;
		}

		var tmp,
			that = this,
			options = this.options,
			x1 = this.opos[0],
			y1 = this.opos[1],
			x2 = event.pageX,
			y2 = event.pageY;

		if (x1 > x2) {
			tmp = x2;
			x2 = x1;
			x1 = tmp;
		}
		if (y1 > y2) {
			tmp = y2;
			y2 = y1;
			y1 = tmp;
		}
		this.helper.css({
			left: x1,
			top: y1,
			width: x2 - x1,
			height: y2 - y1
		});

		this.selectees.each(function () {
			var selectee = $.data(this, "selectable-item"),
				hit = false,
				offset = {};

			//prevent helper from being selected if appendTo: selectable
			if (!selectee || selectee.element === that.element[0]) {
				return;
			}

			offset.left = selectee.left + that.elementPos.left;
			offset.right = selectee.right + that.elementPos.left;
			offset.top = selectee.top + that.elementPos.top;
			offset.bottom = selectee.bottom + that.elementPos.top;

			if (options.tolerance === "touch") {
				hit = (!(offset.left > x2 || offset.right < x1 || offset.top > y2 ||
					offset.bottom < y1));
			} else if (options.tolerance === "fit") {
				hit = (offset.left > x1 && offset.right < x2 && offset.top > y1 &&
					offset.bottom < y2);
			}

			if (hit) {

				// SELECT
				if (selectee.selected) {
					that._removeClass(selectee.$element, "ui-selected");
					selectee.selected = false;
				}
				if (selectee.unselecting) {
					that._removeClass(selectee.$element, "ui-unselecting");
					selectee.unselecting = false;
				}
				if (!selectee.selecting) {
					that._addClass(selectee.$element, "ui-selecting");
					selectee.selecting = true;

					// selectable SELECTING callback
					that._trigger("selecting", event, {
						selecting: selectee.element
					});
				}
			} else {

				// UNSELECT
				if (selectee.selecting) {
					if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
						that._removeClass(selectee.$element, "ui-selecting");
						selectee.selecting = false;
						that._addClass(selectee.$element, "ui-selected");
						selectee.selected = true;
					} else {
						that._removeClass(selectee.$element, "ui-selecting");
						selectee.selecting = false;
						if (selectee.startselected) {
							that._addClass(selectee.$element, "ui-unselecting");
							selectee.unselecting = true;
						}

						// selectable UNSELECTING callback
						that._trigger("unselecting", event, {
							unselecting: selectee.element
						});
					}
				}
				if (selectee.selected) {
					if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
						that._removeClass(selectee.$element, "ui-selected");
						selectee.selected = false;

						that._addClass(selectee.$element, "ui-unselecting");
						selectee.unselecting = true;

						// selectable UNSELECTING callback
						that._trigger("unselecting", event, {
							unselecting: selectee.element
						});
					}
				}
			}
		});

		return false;
	},

	_mouseStop: function (event) {
		var that = this;

		this.dragged = false;

		$(".ui-unselecting", this.element[0]).each(function () {
			var selectee = $.data(this, "selectable-item");
			that._removeClass(selectee.$element, "ui-unselecting");
			selectee.unselecting = false;
			selectee.startselected = false;
			that._trigger("unselected", event, {
				unselected: selectee.element
			});
		});
		$(".ui-selecting", this.element[0]).each(function () {
			var selectee = $.data(this, "selectable-item");
			that._removeClass(selectee.$element, "ui-selecting")
				._addClass(selectee.$element, "ui-selected");
			selectee.selecting = false;
			selectee.selected = true;
			selectee.startselected = true;
			that._trigger("selected", event, {
				selected: selectee.element
			});
		});
		this._trigger("stop", event);

		this.helper.remove();

		return false;
	}

});

var selectable = $.ui.selectable;
export {
	selectable
};
