/*
 * Copyright (c) 2018 Thomas Müller <thomas.mueller@tmit.eu>
 *
 * This file is licensed under the Affero General Public License version 3
 * or later.
 *
 * See the COPYING-README file.
 *
 */

(function(OCA) {
	var NS_DAV = OC.Files.Client.NS_DAV;

	var TEMPLATE_LOCK_STATUS_ACTION =
		'<a class="action action-lock-status permanent" title="{{message}}" href="#">' +
		'<span class="icon icon-lock-closed" />' +
		'</a>';

	/**
	 * Parses an XML lock node
	 *
	 * @param {Node} xmlvalue node to parse
	 * @return {Object} parsed values in associative array
	 */
	function parseLockNode(xmlvalue) {
		var lockInfo = {
			lockscope: getChildNodeLocalName(xmlvalue.getElementsByTagNameNS(NS_DAV, 'lockscope')[0]),
			locktype: getChildNodeLocalName(xmlvalue.getElementsByTagNameNS(NS_DAV, 'locktype')[0]),
			lockroot: getHrefNodeContents(xmlvalue.getElementsByTagNameNS(NS_DAV, 'lockroot')[0]),
			// string, as it can also be "infinite"
			depth: xmlvalue.getElementsByTagNameNS(NS_DAV, 'depth')[0].textContent,
			timeout: xmlvalue.getElementsByTagNameNS(NS_DAV, 'timeout')[0].textContent,
			locktoken: getHrefNodeContents(xmlvalue.getElementsByTagNameNS(NS_DAV, 'locktoken')[0])
		};

		var owner = null;
		var ownerEl = xmlvalue.getElementsByTagNameNS(NS_DAV, 'owner');
		if (ownerEl && ownerEl.length) {
			owner = ownerEl[0].textContent;
		}

		lockInfo.owner = owner || t('files', 'Unknown user');
		return lockInfo;
	}

	function getHrefNodeContents(node) {
		var nodes = node.getElementsByTagNameNS(NS_DAV, 'href');
		if (!nodes.length) {
			return null;
		}
		return nodes[0].textContent;
	}

	/**
	 * Filter out text nodes from a list of XML nodes
	 *
	 * @param {Array.<Node>} nodes nodes to filter
	 * @return {Array.<Node>} filtered array of nodes
	 */
	function getChildNodeLocalName(node) {
		for (var i = 0; i < node.childNodes.length; i++) {
			// skip pure text nodes
			if (node.childNodes[i].nodeType === 1) {
				return node.childNodes[i].localName;
			}
		}
		return null;
	}

	OCA.Files = OCA.Files || {};

	/**
	 * @namespace OCA.Files.LockPlugin
	 */
	OCA.Files.LockPlugin = {

		/**
		 * @param fileList
		 */
		attach: function(fileList) {
			this._extendFileActions(fileList);

			var oldCreateRow = fileList._createRow;
			fileList._createRow = function(fileData) {
				var $tr = oldCreateRow.apply(this, arguments);
				if (fileData.activeLocks) {
					$tr.attr('data-activelocks', JSON.stringify(fileData.activeLocks));
				}
				return $tr;
			};
			var oldElementToFile = fileList.elementToFile;
			fileList.elementToFile = function($el) {
				var fileInfo = oldElementToFile.apply(this, arguments);
				var activeLocks = $el.attr('data-activelocks');
				if (_.isUndefined(activeLocks)) {
					activeLocks = '[]';
				}
				fileInfo.activeLocks = JSON.parse(activeLocks);
				return fileInfo;
			};

			var oldGetWebdavProperties = fileList._getWebdavProperties;
			fileList._getWebdavProperties = function() {
				var props = oldGetWebdavProperties.apply(this, arguments);
				props.push('{DAV:}lockdiscovery');
				return props;
			};

			var lockTab = new OCA.Files.LockTabView('lockTabView', {order: -20});
			fileList.registerTabView(lockTab);

			fileList.filesClient.addFileInfoParser(function(response) {
				var data = {};
				var props = response.propStat[0].properties;
				var activeLocks = props['{DAV:}lockdiscovery'];
				if (!_.isUndefined(activeLocks) && activeLocks !== '') {
					data.activeLocks = _.chain(activeLocks).filter(function(xmlvalue) {
						return (xmlvalue.namespaceURI === NS_DAV && xmlvalue.nodeName.split(':')[1] === 'activelock');
					}).map(function(xmlvalue) {
						return parseLockNode(xmlvalue);
					}).value();
				}
				return data;
			});
		},

		/**
		 * @param fileList
		 * @private
		 */
		_extendFileActions: function(fileList) {
			var self = this;
			fileList.fileActions.registerAction({
				name: 'lock-status',
				displayName: t('files', 'Lock status'),
				mime: 'all',
				permissions: OC.PERMISSION_READ,
				type: OCA.Files.FileActions.TYPE_INLINE,
				render: function(actionSpec, isDefault, context) {
					var $file = context.$file;
					var isLocked = $file.data('activelocks');
					if (isLocked && isLocked.length > 0) {
						var $actionLink = $(self.renderLink());
						context.$file.find('a.name>span.fileactions').append($actionLink);
						return $actionLink;
					}
					return '';
				},
				actionHandler: function(fileName) {
					fileList.showDetailsView(fileName, 'lockTabView');
				}
			});

			if (oc_appconfig.files.enable_lock_file_action) {
				fileList.fileActions.registerAction({
					name: 'lock',
					mime: 'all',
					displayName: t('files', 'Lock file'),
					permissions: OC.PERMISSION_UPDATE,
					type: OCA.Files.FileActions.TYPE_DROPDOWN,
					iconClass: 'icon-lock-closed',
					actionHandler: function (filename, context) {
						const file = context.fileInfoModel.getFullPath();
						context.fileInfoModel._filesClient.lock(file).then(function (result, response) {
							const xml = response.xhr.responseXML;
							const activelock = xml.getElementsByTagNameNS('DAV:', 'activelock');
							const lock = parseLockNode(activelock[0]);
							context.fileInfoModel.set('activeLocks', [lock]);
						}, function (error) {
							console.log(error)
							OC.Notification.show(t('files', 'Failed to lock.'));
						});
					}
				});

				fileList.fileActions.addAdvancedFilter(function (actions, context) {
					var $file = context.$file;
					if (context.fileInfoModel && context.fileInfoModel.attributes.mimetype === 'httpd/unix-directory') {
						delete (actions.lock);
						return actions;
					}
					var isLocked = $file.data('activelocks');
					if (isLocked && isLocked.length > 0) {
						delete (actions.lock);
					}
					return actions;
				});
			}

		},

		renderLink: function () {
			if (!this._template) {
				this._template = Handlebars.compile(TEMPLATE_LOCK_STATUS_ACTION);
			}
			return this._template({
				message: t('files', 'This resource is locked. Click to see more details.')
		});
	}

};

})(OCA);

OC.Plugins.register('OCA.Files.FileList', OCA.Files.LockPlugin);

