'use strict';

/**
 * Licensed Materials - Property of IBM
 *
 * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2014, 2019, 2020
 *
 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 */
define(['../../lib/@waca/core-client/js/core-client/ui/core/View', '../../app/nls/StringResources', 'jquery', 'underscore', '../../lib/@waca/core-client/js/core-client/utils/Utils', 'text!./templates/LayoutPickerView.html', 'text!../layout/templates/listing.json', '../../lib/@waca/core-client/js/core-client/utils/Deferred', '../../lib/@waca/core-client/js/core-client/ui/KeyCodes', '../../lib/@waca/core-client/js/core-client/ui/Menu', '../../lib/@waca/core-client/js/core-client/utils/ContentFormatter', '../../lib/@waca/dashboard-common/dist/ui/dialogs/MessageBox', '../../lib/@waca/dashboard-common/dist/lib/@ba-ui-toolkit/ba-graphics/dist/icons-js/overflow-menu--horizontal_16', '../../lib/@waca/dashboard-common/dist/lib/@ba-ui-toolkit/ba-graphics/dist/illustrations-js/connect-images_128'], function (BaseView, stringResources, $, _, Utils, template, templateListing, Deferred, KeyCodes, Menu, ContentFormatter, MessageBox, contextMenuIcon, thumbnailPlaceholderIcon) {

	var LayoutPickerView = BaseView.extend({
		templateString: template,
		events: {
			'primaryaction .layoutTemplateItem': 'onSelect',
			'dblclick .layoutTemplateItem': 'onDoubleClick',
			'keydown .layoutTemplateItem': 'onKeyDown',
			'click .selected .layoutContextMenuButton': 'onContextMenuButtonClick'
		},

		init: function init(options) {
			options = options || {};
			LayoutPickerView.inherited('init', this, arguments);

			this.stringResources = options.stringResources || stringResources;

			var templates = options.templateListing || templateListing;

			this._showContextMenu = options.showContextMenu;
			this._dashboardTemplatesApi = options.dashboardTemplatesApi;

			// process the templates
			var defaultTemplates = this._processTemplates(JSON.parse(templates));

			// remove items from defaultTemplates that were passed in the excludeTemplates array
			if (options.excludeTemplates) {
				var newList = defaultTemplates.templates.filter(function (element) {
					return !_.contains(options.excludeTemplates, element.name);
				});
				defaultTemplates.templates = newList;
			}

			_.extend(this, _.defaults(options, defaultTemplates));

			this._thumbnailCache = [];
			this._addCustomTemplates(options.customTemplates);

			this._whenReady = new Deferred();
			this.whenReady = this._whenReady.promise;
		},

		_addCustomTemplates: function _addCustomTemplates(customTemplates) {
			var _this = this;

			(customTemplates || []).forEach(function (customTemplate) {
				_this.templates.push({
					label: customTemplate.defaultName,
					ariaLabel: customTemplate.defaultName,
					navigationTemplates: 'custom',
					location: customTemplate.location,
					isSelected: false,
					name: customTemplate.id,
					type: 'custom'
				});
			});
		},


		/**
   *	This function takes the template object and sorts the array of templates so that the ones with
   *	descriptions are on top as well as translates any labels and descriptions.
   *
   *	@param templateListObj: Template object to sort.
   *	@private
   *	@returns Object: the sorted template object.
   **/
		_processTemplates: function _processTemplates(templateListObj) {
			var templateList = templateListObj.templates;

			var aWithDesc = [];
			var aWithoutDesc = [];
			for (var i = 0; i < templateList.length; i++) {
				// get the next template object
				var template = templateList[i];

				// translate the label
				if (template.label) {
					template.label = this.stringResources.get(template.label);
				}

				if (template.name) {
					template.ariaLabel = this.stringResources.get(template.name);
				}

				// sort by description into separate arrays
				if (template.description) {
					// translate the description and add to the array
					template.description = this.stringResources.get(template.description);
					aWithDesc.push(template);
				} else {
					// no description so just push to that array
					aWithoutDesc.push(template);
				}
			}

			return {
				'templates': aWithDesc.concat(aWithoutDesc)
			};
		},

		render: function render() {
			this.$el.empty().addClass('layoutPickerView').attr('role', 'listbox').attr('aria-multiselectable', 'false').html(this.dotTemplate(this));

			this.filterTemplates();
			this.generatePreviews();
		},

		onSelect: function onSelect(event) {
			if (event.type === 'keydown' && event.keyCode === 32) {
				// keydown and spacebar
				// Stops the scroll bar from scrolling the page
				event.preventDefault();
			}

			if ((event.type === 'keyup' || event.type === 'keydown') && event.keyCode !== 13 && event.keyCode !== 32) {
				// ignore anything other than enter or space
				return;
			} else {
				event.stopPropagation();
				if (event.keyCode === 13 && $(event.currentTarget).hasClass('selected')) {
					// if the layout was already selected, enter key submits the layout form
					this.action();
				} else {
					this.selectLayout(event.currentTarget.dataset.id);
					if (_.isFunction(this.selectAction)) {
						this.selectAction(event);
					}
				}
			}
		},

		onDoubleClick: function onDoubleClick(event) {
			this.onSelect(event);
			this.action();
		},

		/**
  Enter and Space calling stopPropagation is a very specific fix for defect 255098. Solution with the least risk.
  *call stop propagation when Enter or Space is clicked, so that BaseBoardView.onKeyDown is not called
  *Those are the keys that trigger primaryaction
  *TODO: Please revisit after Endor release
  **/
		onKeyDown: function onKeyDown(event) {
			var items = this.$('.layoutEntry .layoutTemplateItem:not(.filtered)');
			var focusedItem = this.$('.layoutEntry .layoutTemplateItem[tabindex=0]');
			var focusIndex = items.index(focusedItem);
			switch (event.keyCode) {
				case KeyCodes.DOWN_ARROW:
				case KeyCodes.RIGHT_ARROW:
					focusIndex++;
					if (focusIndex >= items.length) {
						focusIndex = items.length - 1;
					}
					break;
				case KeyCodes.UP_ARROW:
				case KeyCodes.LEFT_ARROW:
					focusIndex--;
					if (focusIndex < 0) {
						focusIndex = 0;
					}
					break;
				case KeyCodes.HOME:
					focusIndex = 0;
					break;
				case KeyCodes.END:
					focusIndex = items.length - 1;
					break;
				case KeyCodes.ENTER:
				case KeyCodes.SPACE:
					event.stopPropagation();
					return;
				default:
					return; //For non-matched keys, stop processing immediately.
			}
			//Update tabindex and focus
			event.preventDefault();
			focusedItem.attr('tabindex', -1);
			items.eq(focusIndex).attr('tabindex', 0).focus();
		},

		setNavigationTemplate: function setNavigationTemplate(navTemplate, description) {
			var _this2 = this;

			var result = void 0;
			var animate = this.navTemplate;
			this.navTemplate = navTemplate;

			if (!animate) {
				this.setLabel();
				this.setFooter(description);
				this.filterTemplates();
				result = Promise.resolve();
			} else {
				// TODO: Probably shouldn't use jquery animation anymore. Switch to CSS
				var duration = 300;
				// show some animation if we are switching to a different navigation template

				result = new Promise(function (resolve, reject) {
					try {
						_this2.$el.fadeOut({
							complete: function complete() {
								_this2.setLabel();
								_this2.setFooter(description);
								_this2.filterTemplates();
								_this2.$el.fadeIn({
									complete: function complete() {
										_this2.checkSelection();
										resolve();
									},
									duration: duration
								});
							},
							duration: duration
						});
					} catch (error) {
						reject(error);
					}
				});
			}

			return result;
		},

		setLabel: function setLabel() {
			if (!this.disableHeaderSection) {
				this.layoutLabel = this.stringResources.get(this.navTemplate + 'LayoutLabel');
				var $header = this.$('.layoutHeader');
				$header.text(this.layoutLabel);
				var $view = $header.parent('.layoutPickerView');
				$view.attr('aria-label', this.stringResources.get('selectTemplateLabel'));
			}
		},

		setFooter: function setFooter(description) {
			this.$('.layoutFooter').text(description);
		},

		filterTemplates: function filterTemplates() {
			var posInSet = 1;
			var setSize = 0;
			_.each(this.templates, function (template) {
				var node = this.$('*[data-id=' + template.name + ']');
				if (template.navigationTemplates && template.navigationTemplates.indexOf(this.navTemplate) === -1) {
					node.addClass('filtered');
					node.closest('.layoutEntry').css('display', 'none').find('.layoutTemplateItem').attr('aria-posinset', null);
					if (node.hasClass('selected')) {
						node.removeClass('selected');
					}
				} else {
					node.removeClass('filtered');
					node.closest('.layoutEntry').css('display', '').find('.layoutTemplateItem').attr('aria-posinset', posInSet);
					setSize++;
					posInSet++;
				}
			}.bind(this));
			this.$('.layoutTemplateItem').attr('aria-setsize', setSize);

			this.checkSelection();
		},

		checkSelection: function checkSelection() {
			if (this.$('.selected:not(.filtered)').length === 0) {
				var firstTemplate, template;
				for (var i = 0; i < this.templates.length; i++) {
					template = this.templates[i];
					if (!template.navigationTemplates || template.navigationTemplates.indexOf(this.navTemplate) !== -1) {
						firstTemplate = template.name;
						break;
					}
				}
				this.selectLayout(firstTemplate);
			}
		},

		getNumberOfPossibleTemplates: function getNumberOfPossibleTemplates() {
			var navTemplate = this.navTemplate;
			var count = 0;
			_.each(this.templates, function (template) {
				if (!template.navigationTemplates || template.navigationTemplates.indexOf(navTemplate) !== -1) {
					count++;
				}
			});
			return count;
		},

		selectLayoutNode: function selectLayoutNode(node) {
			var $selected = this.$('.selected');
			$selected.attr('aria-checked', false).attr('tabindex', -1);
			$selected.removeClass('selected');
			$(node).attr('aria-checked', true).attr('tabindex', 0);
			$(node).addClass('selected').focus();
		},

		onOpen: function onOpen() {
			var _this3 = this;

			this.whenReady.then(function () {
				_this3.$('.selected').focus();
			});
		},

		selectLayout: function selectLayout(name) {
			Menu.hideOpenMenus();
			_.each(this.templates, function (template) {
				template.isSelected = template.name === name;
			}.bind(this));
			var selectedTemplate = this.$('.layoutTemplateItem[data-id=' + name + ']')[0];
			this.selectLayoutNode(selectedTemplate);
			if (this.navTemplate === 'custom') {
				this.applyContextMenuPermissions(name, selectedTemplate);
			}
		},

		/**
   * Asynch method that will load and return the selected page layout template
   */
		getSelectedLayoutSpec: function getSelectedLayoutSpec() {
			var selected = this.$('.selected').attr('data-id');
			return this.getLayoutSpecByName(selected);
		},

		getSelectedTemplate: function getSelectedTemplate() {
			return this.$('.layoutTemplateItem.selected');
		},

		getSelectedLayoutId: function getSelectedLayoutId() {
			var $selectedLayoutTemplate = this.$('.selected');
			if ($selectedLayoutTemplate.length > 0) {
				return $selectedLayoutTemplate[0].dataset.id;
			}

			return null;
		},

		_findLayoutByName: function _findLayoutByName(name) {
			return _.find(this.templates, function (template) {
				return template.name === name;
			});
		},

		getLayoutSpecByName: function getLayoutSpecByName(layoutName) {
			var _this4 = this;

			var layout = this._findLayoutByName(layoutName);
			if (!layout) {
				// Error loading the theme. We resolve with no definition.
				this.displayErrorMessage();
				return Promise.resolve();
			}

			return this.getLayoutSpec(layout, function () {
				// Error loading the theme. We resolve with no definition.
				_this4.displayErrorMessage();
			});
		},

		getLayoutSpec: function getLayoutSpec(template, errorHandler) {
			if (template.type === 'custom') {
				return Promise.resolve({ layout: template });
			}
			return new Promise(function (resolve, reject) {
				try {
					var requireFilePath = template.type === 'js' ? '' : 'text!';
					template.type = template.type ? template.type : 'json';
					requireFilePath += template.path + '/' + template.name;
					requireFilePath += template.type === 'js' ? '' : '.' + template.type;
					require([requireFilePath], function (layoutFileContent) {
						var layout = typeof layoutFileContent === 'string' ? JSON.parse(layoutFileContent) : layoutFileContent;
						resolve({
							layout: layout
						});
					}, function () {
						if (errorHandler) {
							errorHandler();
						}
						resolve();
					});
				} catch (error) {
					reject(error);
				}
			});
		},

		displayErrorMessage: function displayErrorMessage() {
			var msgBox = new MessageBox('error', this.stringResources.get('errorMessageTitle'), this.stringResources.get('errorLoadingLayoutFile'));
			msgBox.open();
		},

		generatePreviews: function generatePreviews() {
			var _this5 = this;

			var whenAllLoaded = [];
			_.each(this.templates, function (template) {
				if (template.type === 'custom') {
					var templateLayoutItem = _this5.$('*[data-id=' + template.name + ']').parent();
					ContentFormatter.middleShortenString(templateLayoutItem.find('.layoutLocation')[0]);
					ContentFormatter.middleShortenString(templateLayoutItem.find('.layoutThumbnailLabel')[0]);
					Utils.setIcon(templateLayoutItem.find('.layoutContextMenuButton'), contextMenuIcon.default.id);
					Utils.setIcon(templateLayoutItem.find('.layoutThumbnailContainer'), thumbnailPlaceholderIcon.default.id);
					var cachedThumbnail = _this5._thumbnailCache.find(function (thumbnail) {
						return thumbnail.name == template.name;
					});
					if (cachedThumbnail) {
						_this5._setTemplateThumbnail(template.name, cachedThumbnail.thumbnail);
					} else {
						_this5._dashboardTemplatesApi.getThumbnail(template.name).then(function (thumbnail) {
							_this5._thumbnailCache.push({ name: template.name, thumbnail: thumbnail });
							_this5._setTemplateThumbnail(template.name, thumbnail);
						});
					}
				} else {
					var promise = _this5.getLayoutSpec(template).then(function (_ref) {
						var layout = _ref.layout;

						var previewNode = _this5.$('*[data-id=' + template.name + ']');
						if (!template.label && !template.icon) {
							previewNode.append(_this5.getPreview(layout));
						}

						// set icon - webfont or svg
						if (template.icon) {
							var $templateIcon = _this5.$el.find('[data-id="' + template.name + '"]').find('.layoutIcon');
							Utils.setIcon($templateIcon, template.icon);
						}
					});
					whenAllLoaded.push(promise);
				}
			});

			Promise.all(whenAllLoaded).then(this._whenReady.resolve.bind(this.whenReady));
		},

		getPreview: function getPreview(layout) {
			var style = '';
			if (layout.style) {
				for (var name in layout.style) {
					if (layout.style.hasOwnProperty(name)) {
						style += name + ':' + layout.style[name] + ';';
					}
				}
			}

			var css = layout.css || '';
			css += ' ' + layout.type;
			var preview = '<div class="' + css + ' " style="' + style + '">';

			if (layout.items) {
				for (var i = 0; i < layout.items.length; i++) {
					preview += this.getPreview(layout.items[i]);
				}
			}

			preview += '</div>';

			return preview;
		},

		applyContextMenuPermissions: function applyContextMenuPermissions(templateId, selectedTemplateElement) {
			var _this6 = this;

			this._dashboardTemplatesApi.getTemplate(templateId).then(function (template) {
				_this6._selectedCustomTemplate = template;
				var contextMenuPermissions = ['write', 'execute'];
				if (_.intersection(template.permissions, contextMenuPermissions).length) {
					$(selectedTemplateElement).find('.layoutContextMenuButton').addClass('isVisible');
				}
			});
		},

		_setTemplateThumbnail: function _setTemplateThumbnail(id, image) {
			if (!id || !image) {
				return;
			}
			var templateItem = id && this.$('*[data-id=' + id + ']');
			var thumbnailContainer = templateItem.find('.layoutThumbnailContainer');
			var thumbnailImage = thumbnailContainer && thumbnailContainer.find('.layoutThumbnail');
			if (thumbnailImage && thumbnailImage.length) {
				thumbnailImage.attr('src', 'data:image/png;base64,' + image);
				var thumbnailPlaceholder = thumbnailContainer.find('svg').first();
				thumbnailPlaceholder && thumbnailPlaceholder.remove();
			}
		},

		onDeleteActionDone: function onDeleteActionDone(templateId) {
			var templateItem = templateId && this.$('*[data-id=' + templateId + ']');
			templateItem && templateItem.closest('.layoutEntry').remove();
			this.templates = this.templates.filter(function (template) {
				return template.name !== templateId;
			});
		},

		onContextMenuButtonClick: function onContextMenuButtonClick(event) {
			this._selectedCustomTemplate && this._showContextMenu(this._selectedCustomTemplate, event.pageX, event.pageY);
		},

		addMoreCustomTemplates: function addMoreCustomTemplates(customTemplates) {
			this._addCustomTemplates(customTemplates);
			this.render();
		}
	});

	return LayoutPickerView;
});
//# sourceMappingURL=LayoutPickerView.js.map