/*
 * Copyright (c) 2015
 *
 * This file is licensed under the Affero General Public License version 3
 * or later.
 *
 * See the COPYING-README file.
 *
 */

(function() {
	if(!OC.Share) {
		OC.Share = {};
	}

	var TEMPLATE_BASE =
		'<div class="resharerInfoView subView"></div>' +
		'{{#if isSharingAllowed}}' +
		'{{#if isLinkSharingAllowed}}' +
		'<ul class="subTabHeaders">' +
		'    <li class="subTabHeader selected subtab-localshare">{{localSharesLabel}}</li>' +
		'    <li class="subTabHeader subtab-publicshare">{{publicSharesLabel}}</li>' +
		'</ul>' +
		'{{/if}}' +
		'<div class="tabsContainer">' +
		// TODO: this really should be a separate view class
		'    <div class="localShareView tab" style="padding-left:0;padding-right:0;">' +
		'        <label for="shareWith-{{cid}}" class="hidden-visually">{{shareLabel}}</label>' +
		'        <div class="oneline">' +
		'            <input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{sharePlaceholder}}" />' +
		'            <span class="shareWithLoading icon-loading-small hidden"></span>'+
		'            {{{remoteShareInfo}}}' +
		'        </div>' +
		'        <div class="shareeListView subView"></div>' +
		'        <div class="shareeTreeUserGroupListView subView"></div>' +
		'    </div>' +
		'    <div class="linkShareView tab hidden" style="padding-left:0;padding-right:0;">' +
		'        <div class="linkListView"></div>' +
		'        <div class="shareeTreeLinkListView subView"></div>' +
		'    </div>' +
		'</div>' +
		'{{else}}' +
		'<div class="noSharingPlaceholder">{{noSharingPlaceholder}}</div>' +
		'{{/if}}' +
		'<div class="loading hidden" style="height: 50px"></div>';

	var TEMPLATE_REMOTE_SHARE_INFO =
		'<a target="_blank" class="icon icon-info shareWithRemoteInfo hasTooltip" href="{{docLink}}" ' +
		'title="{{tooltip}}"></a>';

	var TEMPLATE_AUTOCOMPLETE_ITEM =
		'<li class="{{shareTypeClass}}">' +
			'<a>' +
				'<div class="share-autocomplete-item">' +
					'{{#if showAvatar}}' +
					'<div class="avatardiv"></div>' +
					'{{/if}}' +
					'<div class="autocomplete-item-text">' +
						'<span class="autocomplete-item-displayname">{{displayName}}</span>' +
						'{{#if additionalInfo}}' +
						'<br/><span class="autocomplete-item-additional-info">({{additionalInfo}})</span>' +
						'{{/if}}' +
						'<br/><span class="autocomplete-item-typeInfo">{{typeInfo}}</span>' +
					'</div>' +
					'{{#if showIcon}}' +
						'<span class="icon {{iconClass}}"></span>' +
					'{{/if}}' +
				'</div>' +
			'</a>' +
		'</li>';

	/**
	 * @class OCA.Share.ShareDialogView
	 * @member {OC.Share.ShareItemModel} model
	 * @member {jQuery} $el
	 * @memberof OCA.Sharing
	 * @classdesc
	 *
	 * Represents the GUI of the share dialogue
	 *
	 */
	var ShareDialogView = OC.Backbone.View.extend({
		/** @type {Object} **/
		_templates: {},

		/** @type {string} **/
		tagName: 'div',

		/** @type {OC.Share.ShareConfigModel} **/
		configModel: undefined,

		/** @type {object} **/
		resharerInfoView: undefined,

		/** @type {object} **/
		linkShareView: undefined,

		/** @type {object} **/
		shareeListView: undefined,

		/** @type {string} **/
		batchActionSeparator: ',',

		events: {
			'input .shareWithField': 'onShareWithFieldChanged',
			'click .subTabHeader': '_onClickTabHeader'
		},

		initialize: function(options) {
			var view = this;

			this.model.on('fetchError', function() {
				OC.Notification.showTemporary(t('core', 'Share details could not be loaded for this item.'));
			});

			if(!_.isUndefined(options.configModel)) {
				this.configModel = options.configModel;
			} else {
				throw 'missing OC.Share.ShareConfigModel';
			}

			this.configModel.on('change:isRemoteShareAllowed', function() {
				view.render();
			});
			this.model.on('change:permissions', function() {
				view.render();
			});

			this.model.on('request', this._onRequest, this);
			this.model.on('sync', this._onEndRequest, this);

			var subViewOptions = {
				model: this.model,
				configModel: this.configModel
			};

			var subViews = {
				resharerInfoView: 'ShareDialogResharerInfoView',
				shareeListView: 'ShareDialogShareeListView'
			};

			for(var name in subViews) {
				var className = subViews[name];
				this[name] = _.isUndefined(options[name])
					? new OC.Share[className](subViewOptions)
					: options[name];
			}

			this.linkShareView = null;

			_.bindAll(this,
				'autocompleteHandler',
				'_onSelectRecipient',
				'onShareWithFieldChanged'
			);

			OC.Plugins.attach('OC.Share.ShareDialogView', this);
		},

		_onClickTabHeader: function(ev) {
			var $target = $(ev.target);
			this.$('.subTabHeaders .subTabHeader.selected').removeClass('selected');

			$target.addClass('selected');

			this.$('.localShareView').toggleClass('hidden', !$target.hasClass('subtab-localshare'));

			var $linkShareView = this.$('.linkShareView');
			var $linkListView = this.$('.linkListView');
			if ($linkShareView.length) {
				$linkShareView.toggleClass('hidden', !$target.hasClass('subtab-publicshare'));

				if (!this.linkShareView) {
					this.linkShareView = new OC.Share.ShareDialogLinkListView({
						collection: this.model.getLinkSharesCollection(),
						// pass in the legacy stuff...
						itemModel: this.model
					});
					this.linkShareView.render();
					$linkListView.html(this.linkShareView.$el);
				}
			}
		},

		onShareWithFieldChanged: function() {
			var $el = this.$el.find('.shareWithField');
			if ($el.val().length < 2) {
				$el.removeClass('error').tooltip('hide');
			}
		},

		autocompleteHandler: function (search, response) {
			var view = this;
			var $loading = this.$el.find('.shareWithLoading');
			var trimmedSearch = search.term.trim();
			$loading.removeClass('hidden');
			$loading.addClass('inlineblock');
			$.get(
				OC.linkToOCS('apps/files_sharing/api/v1') + 'sharees',
				{
					format: 'json',
					search: trimmedSearch,
					perPage: 200,
					itemType: view.model.get('itemType')
				},
				function (result) {
					$loading.addClass('hidden');
					$loading.removeClass('inlineblock');
					if (result.ocs.meta.statuscode == 100) {
						var users   = result.ocs.data.exact.users.concat(result.ocs.data.users);
						var groups  = result.ocs.data.exact.groups.concat(result.ocs.data.groups);
						var remotes = result.ocs.data.exact.remotes.concat(result.ocs.data.remotes);

						var usersLength;
						var groupsLength;
						var remotesLength;

						var i, j;

						//Filter out the current user
						usersLength = users.length;
						for (i = 0 ; i < usersLength; i++) {
							if (users[i].value.shareWith === OC.currentUser) {
								users.splice(i, 1);
								break;
							}
						}

						// Filter out the owner of the share
						if (view.model.hasReshare()) {
							usersLength = users.length;
							for (i = 0 ; i < usersLength; i++) {
								if (users[i].value.shareWith === view.model.getReshareOwner()) {
									users.splice(i, 1);
									break;
								}
							}
						}

						var shares = view.model.get('shares');
						var sharesLength = shares.length;

						// Now filter out all sharees that are already shared with
						for (i = 0; i < sharesLength; i++) {
							var share = shares[i];

							if (share.share_type === OC.Share.SHARE_TYPE_USER) {
								usersLength = users.length;
								for (j = 0; j < usersLength; j++) {
									if (users[j].value.shareWith === share.share_with) {
										users.splice(j, 1);
										break;
									}
								}
							} else if (share.share_type === OC.Share.SHARE_TYPE_GROUP) {
								groupsLength = groups.length;
								for (j = 0; j < groupsLength; j++) {
									if (groups[j].value.shareWith === share.share_with) {
										groups.splice(j, 1);
										break;
									}
								}
							} else if (share.share_type === OC.Share.SHARE_TYPE_REMOTE) {
								remotesLength = remotes.length;
								for (j = 0; j < remotesLength; j++) {
									if (remotes[j].value.shareWith === share.share_with) {
										remotes.splice(j, 1);
										break;
									}
								}
							}
						}

						var isBatch = trimmedSearch.indexOf(view.batchActionSeparator) !== -1;
						var suggestions = users.concat(groups);
						if (suggestions.length < 1 && !isBatch) {
							suggestions = suggestions.concat(remotes);
						}

						if (isBatch) {
							return view._getUsersForBatchAction(trimmedSearch).then(function (res) {
								if (res.found.length) {
									//Filter out the current user
									for (i = 0; i < res.found.length; i++) {
										if (res.found[i].shareWith === OC.currentUser) {
											res.found.splice(i, 1);
											continue;
										}
									}
								}
								if (res.found.length) {
									// Build the label for the list of users to be batch-added
									var labelArray = [];
									for (i = 0; i < res.found.length; i++) {
										labelArray.push(res.found[i].shareWith)
									}

									suggestions.push({
										batch: res.found,
										failedBatch: res.notFound,
										label: labelArray.join(', '),
										value: {}
									});
								}

								$loading.addClass('hidden');
								$loading.removeClass('inlineblock');
								if (suggestions.length) {
									$('.shareWithField').removeClass('error')
										.tooltip('hide')
										.autocomplete("option", "autoFocus", true);
									return response(suggestions, result);
								}

								view._displayError(t('core', 'No users or groups found'));
								return response(undefined, result);
							})
						}

						if (suggestions.length > 0) {
							suggestions.sort(function (a, b) {
								return OC.Util.naturalSortCompare(a.label, b.label);
							});
							$('.shareWithField').removeClass('error')
								.tooltip('hide')
								.autocomplete("option", "autoFocus", true);
							response(suggestions, result);
						} else {
							var title = t('core', 'No users or groups found for {search}', {search: $('.shareWithField').val()});
							if (!view.configModel.get('allowGroupSharing')) {
								title = t('core', 'No users found for {search}', {search: $('.shareWithField').val()});
							}
							var suggestStarts = OC.getCapabilities().files_sharing.search_min_length;
							if (suggestStarts > $('.shareWithField').val().length) {
								title = title + '. ' + n(
									'core',
									'Please enter at least {chars} character for suggestions',
									'Please enter at least {chars} characters for suggestions',
									suggestStarts,
									{chars: suggestStarts}
								);
							}
							view._displayError(title);
							response(undefined, result);
						}
					} else {
						response(undefined, result);
					}
				}
			).fail(function() {
				$loading.addClass('hidden');
				$loading.removeClass('inlineblock');
				OC.Notification.show(t('core', 'An error occurred. Please try again'));
				window.setTimeout(OC.Notification.hide, 5000);
			});
		},

		autocompleteRenderItem: function(ul, item) {
			var text = item.label;
			var showIcon = false;
			var iconClass = "";
			var typeInfo = t('core', 'User');

			if (item.batch) {
				typeInfo = this._getBatchActionLabel();
			}
			if (item.value.shareType === OC.Share.SHARE_TYPE_GROUP) {
				typeInfo = t('core', 'Group');
			}
			if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE_GROUP) {
				typeInfo = t('core', 'Federated Group');
				showIcon = true
				iconClass = "icon-contacts-dark"
			}
			if (item.value.shareType === OC.Share.SHARE_TYPE_GUEST) {
				typeInfo = t('core', 'Guest');
			}
			if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE) {
				if (item.value.server) {
					typeInfo = t('core', 'At {server}', {
						server: item.value.server
					});
				} else {
					typeInfo = t('core', 'Federated');
				}
			}
			if (item.value.userType === OC.User.USER_TYPE_GUEST) {
				typeInfo = t('core', 'Guest');
			}

			var template = this._getAutocompleteItemTemplate();
			var $el = $(template({
				showAvatar: this.configModel.areAvatarsEnabled(),
				displayName: text,
				showIcon: showIcon,
				iconClass: iconClass,
				typeInfo: typeInfo,
				additionalInfo: item.value.shareWithAdditionalInfo,
				shareTypeClass: (item.value.shareType === OC.Share.SHARE_TYPE_GROUP) ? 'group' : 'user'
			}));

			if (this.configModel.areAvatarsEnabled()) {
				var $avatar = $el.find('.avatardiv');
				if (item.value.shareType === OC.Share.SHARE_TYPE_USER) {
					$avatar.avatar(item.value.shareWith, 32, undefined, undefined, undefined, item.label);
				} else {
					$avatar.imageplaceholder(text, undefined, 32);
				}
			}

			return $el.appendTo(ul);
		},

		_onSelectRecipient: function(e, s) {
			e.preventDefault();
			$(e.target).attr('disabled', true)
				.val(s.item.label);
			var $loading = this.$el.find('.shareWithLoading');
			$loading.removeClass('hidden')
				.addClass('inlineblock');

			if (s.item.failedBatch && s.item.failedBatch.length) {
				this._showFailedBatchSharees(s.item.failedBatch);
			}

			var shares = s.item.batch || [s.item.value];
			for (var i = 0; i < shares.length; i++) {
				this.model.addShare(shares[i], {
					success: function () {
						$(e.target).val('').attr('disabled', false);
						$loading.addClass('hidden').removeClass('inlineblock');
					}, error: function (obj, msg) {
						OC.Notification.showTemporary(msg);
						$(e.target).attr('disabled', false).autocomplete('search', $(e.target).val());
						$loading.addClass('hidden').removeClass('inlineblock');
					}
				});
			}
		},

		_toggleLoading: function(state) {
			this._loading = state;
			this.$el.find('.localShareView, .noSharingPlaceholder').toggleClass('hidden', state);
			this.$el.find('.loading').toggleClass('hidden', !state);
		},

		_onRequest: function() {
			// only show the loading spinner for the first request (for now)
			if (!this._loadingOnce) {
				this._toggleLoading(true);
			}
		},

		_onEndRequest: function() {
			var self = this;
			this._toggleLoading(false);
			if (!this._loadingOnce) {
				this._loadingOnce = true;
				// the first time, focus on the share field after the spinner disappeared
				if (!bowser.msie) {
					_.defer(function () {
						self.$('.shareWithField').focus();
					});
				}
			}
		},

		render: function() {
			var baseTemplate = this._getTemplate('base', TEMPLATE_BASE);

			this.$el.html(baseTemplate({
				cid: this.cid,
				shareLabel: t('core', 'Share'),
				sharePlaceholder: this._renderSharePlaceholderPart(),
				remoteShareInfo: this._renderRemoteShareInfoPart(),
				isSharingAllowed: this.model.sharePermissionPossible(),
				isLinkSharingAllowed: this.configModel.isShareWithLinkAllowed(),
				localSharesLabel: t('core', 'User and Groups'),
				publicSharesLabel: t('core', 'Public Links'),
				noSharingPlaceholder: t('core', 'Sharing is not allowed')
			}));

			var $shareField = this.$el.find('.shareWithField');
			if ($shareField.length) {
				$shareField.autocomplete({
					minLength: 1,
					delay: 750,
					focus: function(event) {
						event.preventDefault();
					},
					source: this.autocompleteHandler,
					select: this._onSelectRecipient,
					appendTo: '#shareTabView'
				}).data('ui-autocomplete')._renderItem = _.bind(this.autocompleteRenderItem, this);
			}

			this.resharerInfoView.$el = this.$el.find('.resharerInfoView');
			this.resharerInfoView.render();

			var resharingAllowed = this.model.sharePermissionPossible();
			if (!resharingAllowed || !this.configModel.isShareWithLinkAllowed()) {
				this.$('.tabHeaders, .linkShareView').remove();
			}

			this.shareeListView.$el = this.$el.find('.shareeListView');
			this.shareeListView.render();

			this.$el.find('.hasTooltip').tooltip();

			return this;
		},

		_renderRemoteShareInfoPart: function() {
			var remoteShareInfo = '';
			if(this.configModel.get('isRemoteShareAllowed')) {
				var infoTemplate = this._getRemoteShareInfoTemplate();
				remoteShareInfo = infoTemplate({
					docLink: this.configModel.getFederatedShareDocLink(),
					tooltip: t('core', 'Share with people on other ownClouds using the syntax username@example.com/owncloud')
				});
			}

			return remoteShareInfo;
		},

		_renderSharePlaceholderPart: function () {
			var sharePlaceholder = t('core', 'Share with users…');

			if (this.configModel.get('allowGroupSharing')) {
				if (this.configModel.get('isRemoteShareAllowed')) {
					sharePlaceholder = t('core', 'Share with users, groups or federated users…');
				} else {
					sharePlaceholder = t('core', 'Share with users or groups…')
				}
			} else if (this.configModel.get('isRemoteShareAllowed')) {
					sharePlaceholder = t('core', 'Share with users or federated users…');
			}

			return sharePlaceholder;
		},

		/**
		 *
		 * @param {string} key - an identifier for the template
		 * @param {string} template - the HTML to be compiled by Handlebars
		 * @returns {Function} from Handlebars
		 * @private
		 */
		_getTemplate: function (key, template) {
			if (!this._templates[key]) {
				this._templates[key] = Handlebars.compile(template);
			}
			return this._templates[key];
		},

		/**
		 * returns the info template for remote sharing
		 *
		 * @returns {Function}
		 * @private
		 */
		_getRemoteShareInfoTemplate: function() {
			return this._getTemplate('remoteShareInfo', TEMPLATE_REMOTE_SHARE_INFO);
		},

		/**
		 * Returns the autocomplete item template
		 *
		 * @returns {Function}
		 * @private
		 */
		_getAutocompleteItemTemplate: function() {
			return this._getTemplate('autocompleteItem', TEMPLATE_AUTOCOMPLETE_ITEM);
		},

		/**
		 * Shows all users with whom the batch share action failed.
		 *
		 * @param {Array.<String>} users
		 * @private
		 */
		_showFailedBatchSharees: function(users) {
			var failedUsersStr = users.join(', ');
			OC.Notification.show(
				t('core', 'Could not be shared with the following users: {users}', {users: failedUsersStr}),
				{type: 'error'}
			);
		},

		/**
		 * Returns the label for the batch action
		 *
		 * @returns {string}
		 * @private
		 */
		_getBatchActionLabel: function() {
			return t('core', 'Add multiple users');
		},

		/**
		 * Displays an error, e.g. when the autocomplete doesn't have results.
		 *
		 * @param {string} title - title of the error
		 * @private
		 */
		_displayError: function(title) {
			$('.shareWithField').addClass('error')
				.attr('data-original-title', title)
				.tooltip('hide')
				.tooltip({
					placement: 'bottom',
					trigger: 'manual'
				})
				.tooltip('fixTitle')
				.tooltip('show');
		},

		/**
		 * Returns a promise which includes all fetched users for batch actions once resolved.
		 *
		 * @param {string} search - trimmed search term
		 * @returns {Promise}
		 * @private
		 */
		_getUsersForBatchAction: function(search) {
			var view = this;
			var foundUsers = [];
			var notFound = [];
			var promises = [];
			var users = Array.from(new Set(search.replace(new RegExp(this.batchActionSeparator + '\\s+', 'g'), this.batchActionSeparator).split(this.batchActionSeparator)));

			for (var i = 0; i < users.length; i++) {
				if (!users[i] || users[i] === OC.currentUser) {
					continue;
				}
				var user = users[i].trim();
				promises.push(
					$.ajax({
						url: OC.linkToOCS('apps/files_sharing/api/v1') + 'sharees',
						contentType: 'application/json',
						dataType: 'json',
						data: {
							format: 'json',
							search: user,
							perPage: 200,
							itemType: view.model.get('itemType')
						},
						context: { user: user }
					})
					.done(function (result) {
						if (result.ocs.data.exact.users.length) {
							var addShare = true;
							var shares = view.model.get('shares');
							if (!shares.length) {
								foundUsers.push(result.ocs.data.exact.users[0].value);
								return;
							}

							// filter out all sharees that are already shared with
							for (j= 0; j < shares.length; j++) {
								if (shares[j].share_type === OC.Share.SHARE_TYPE_USER
									&& result.ocs.data.exact.users[0].value.shareWith === shares[j].share_with) {
									addShare = false;
									break;
								}
							}

							if (addShare) {
								foundUsers.push(result.ocs.data.exact.users[0].value);
							}
						} else {
							notFound.push(this.user);
						}
					})
				);
			}

			return Promise.all(promises).then(function() {
				return {found: foundUsers, notFound: notFound};
			});
		}
	});

	OC.Share.ShareDialogView = ShareDialogView;

})();
