/**
 * Mixin class for ReorderableContainer, that contains view model logic.
 */
Ext.define("Terrasoft.mixins.ReorderableContainerVMMixin", {
	alternateClassName: "Terrasoft.ReorderableContainerVMMixin",

	/**
  * Initializes mixin.
  * @protected
  */
	preInit: function () {
		this.initAttributes();
		this.initEvents();
		var items = Ext.create("Terrasoft.BaseViewModelCollection", {
			itemClass: this.get("DefaultItemClassName")
		});
		this.set("ViewModelItems", items);
	},

	/**
  * Register mixin events.
  * @protected
  */
	initEvents: function () {
		this.addEvents("beforeItemMove");
	},

	/**
  * Inits attributes of view model.
  * @protected
  */
	initAttributes: function () {
		var columns = this.columns;
		columns.Name = columns.Name || {
			type: Terrasoft.core.enums.ViewModelColumnType.VIRTUAL_COLUMN,
			caption: "Name",
			dataValueType: Terrasoft.core.enums.DataValueType.TEXT
		};
		columns.ReorderableIndex = columns.ReorderableIndex || {
			type: Terrasoft.core.enums.ViewModelColumnType.VIRTUAL_COLUMN,
			caption: "ReorderableIndex",
			dataValueType: Terrasoft.core.enums.DataValueType.INTEGER
		};
		columns.ViewModelItems = columns.ViewModelItems || {
			type: Terrasoft.core.enums.ViewModelColumnType.VIRTUAL_COLUMN,
			caption: "ViewModelItems",
			dataValueType: Terrasoft.core.enums.DataValueType.COLLECTION
		};
		columns.Schema = columns.Schema || {
			type: Terrasoft.core.enums.ViewModelColumnType.VIRTUAL_COLUMN,
			dataValueType: Terrasoft.core.enums.DataValueType.CUSTOM_OBJECT
		};
		columns.DefaultItemClassName = columns.DefaultItemClassName || {
			type: Terrasoft.core.enums.ViewModelColumnType.VIRTUAL_COLUMN,
			dataValueType: Terrasoft.core.enums.DataValueType.TEXT
		};
	},

	/**
  * Returns reorderable view model items.
  * @protected
  * @return {Terrasoft.BaseViewModel[]}
  */
	getViewModelItems: function () {
		return this.get("ViewModelItems");
	},

	/**
  * Getting position of the element in the container.
  * @protected
  * @param {String} key Desired element key.
  * @return {Number} Position of an element in the container.
  */
	indexOf: function (key) {
		var viewModelItems = this.getViewModelItems();
		var viewModelItemsKeys = viewModelItems.getKeys();
		return viewModelItemsKeys.indexOf(key);
	},

	/**
  * DragOver event handler.
  * @protected
  * @param {String} dragItemId Dragged item id.
  * @param {String} dragOverItemId Item id.
  */
	onDragOver: function (dragItemId, dragOverItemId) {
		this.clearReorderableIndex();
		var getDragOverData = this.getDragOverData(dragItemId, dragOverItemId);
		if (getDragOverData.isValid) {
			this.set("ReorderableIndex", getDragOverData.reorderableIndex);
		}
		return getDragOverData.isValid;
	},

	/**
  * Returns data for dragOver event.
  * @protected
  * @param {String} dragItemId Drag item id.
  * @param {String} dragOverItemId Id of item over which is dragged.
  * @return {Object}
  * @return {Number} return.reorderableIndex Reorderable index.
  * @return {Boolean} return.isValid Indicates whether that drop zone is valid.
  */
	getDragOverData: function (dragItemId, dragOverItemId) {
		var index = this.indexOf(dragOverItemId);
		if (index < 0) {
			index = this.getLastIndex(dragItemId);
		} else {
			index--;
		}
		return {
			reorderableIndex: index,
			isValid: true
		};
	},

	/**
  * Handles block insertion events.
  * @protected
  * @param {String} dropItemId The element identifier.
  */
	onDragDrop: function (dropItemId) {
		this.moveItem(dropItemId);
	},

	/**
  * Adds item to collection.
  * @protected
  * @param {Terrasoft.BaseViewModel} viewModelItem View model of element.
  */
	addItem: function (viewModelItem) {
		var viewModelItemId = viewModelItem.get("Id");
		var viewModelItems = this.get("ViewModelItems");
		viewModelItems.add(viewModelItemId, viewModelItem);
	},

	/**
  * Moves item to collection.
  * @protected
  * @param {String} moveItemId Item Id.
  * @return {Number} insert position.
  */
	moveItem: function (moveItemId) {
		var moveData = this.getMoveData(moveItemId);
		if (moveData.cancel === true) {
			return -1;
		}
		this.set("ReorderableIndex", null);
		if (this.fireEvent("beforeItemMove", this, moveData) === false) {
			return -1;
		}
		this.move(moveData);
		return moveData.targetIndex;
	},

	/**
  * Returns current index to insert item.
  * @protected
  */
	getReorderableIndex: function () {
		return this.get("ReorderableIndex");
	},

	/**
  * Returns data to move item in items collection.
  * @protected
  * @param {String} moveItemId Moved item id.
  * @return {Object}
  * @return {Boolean} [return.cancel] Indicates whether that need cancel item moves.
  * @return {Object} [return.item] Moved item.
  * @return {String} [return.item] Moved item id.
  * @return {Terrasoft.Collection} [return.sourceCollection] Collection from which item is moved.
  * @return {Terrasoft.Collection} [return.sourceIndex Item] index in source collection.
  * @return {Terrasoft.Collection} [return.targetCollection] Collection to which item is moved.
  * @return {Terrasoft.Collection} [return.targetIndex] Item index in target collection.
  */
	getMoveData: function (moveItemId) {
		var reorderableIndex = this.getReorderableIndex();
		if (Ext.isEmpty(reorderableIndex)) {
			return {
				cancel: true
			};
		}
		var sourceViewModelItems = this.findViewModeCollectionByKey(moveItemId);
		var viewModelItem = sourceViewModelItems.get(moveItemId);
		var viewModelItemId = viewModelItem.get("Id");
		var itemIndex = this.indexOf(moveItemId);
		if (itemIndex === -1 || reorderableIndex < itemIndex && itemIndex > 0) {
			reorderableIndex += 1;
		}
		var viewModelItems = this.get("ViewModelItems");
		var sourceIndex = sourceViewModelItems.indexOf(viewModelItem);
		return {
			item: viewModelItem,
			itemId: viewModelItemId,
			sourceCollection: sourceViewModelItems,
			sourceIndex: sourceIndex,
			targetCollection: viewModelItems,
			targetIndex: reorderableIndex
		};
	},

	move: function (moveData) {
		//TODO CRM-26037
		moveData.sourceCollection.removeByKey(moveData.itemId);
		moveData.targetCollection.insert(moveData.targetIndex, moveData.itemId, moveData.item);
		return moveData.targetIndex;
	},

	/**
  * DragOut event handler
  * @protected
  */
	onDragOut: function () {
		this.set("ReorderableIndex", null);
	},

	/**
  * Finds items collection by key.
  * @protected
  * @param {String} key Item id.
  * @return {Terrasoft.BaseViewModelCollection|null}
  */
	findViewModeCollectionByKey: function (key) {
		var result = null;
		var viewModelItems = this.get("ViewModelItems");
		if (viewModelItems.contains(key)) {
			result = viewModelItems;
		}
		return result;
	},

	/**
  * Clears reorderable index.
  * @protected
  */
	clearReorderableIndex: function () {
		this.set("ReorderableIndex", null);
	},

	/**
  * Returns last index in collection. If the last element is dragged, it returns penultimate index.
  * @private
  * @param {String} dragItemId Dragged item id.
  * @return {Number}
  */
	getLastIndex: function (dragItemId) {
		var viewModelItems = this.getViewModelItems();
		var indexOf = viewModelItems.getCount() - 1;
		var indexDragItem = this.indexOf(dragItemId);
		if (indexDragItem > -1 && indexOf === indexDragItem) {
			indexOf--;
		}
		return indexOf;
	}
});