'use strict';

/**
 * Licensed Materials - Property of IBM
 * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2015, 2020
 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 */

define(['require', '../lib/@waca/core-client/js/core-client/ui/core/Class', '../lib/@waca/core-client/js/core-client/utils/Deferred', 'jquery', 'underscore', '../nls/StringResources'], function (require, Class, Deferred, $, _, stringResources) {

	/**
  * A helper that provides the event handlers typically used to add a widget.
  */
	var WidgetAddUIHelper = Class.extend({
		init: function init(options) {
			WidgetAddUIHelper.inherited('init', this, arguments);
			this.dashboardApi = options.dashboardApi;
			this.requireFn = options.requireFn || require;
			this.logger = this.dashboardApi.getGlassCoreSvc('.Logger');
		},

		fetchWidgetList: function fetchWidgetList(url) {
			var _this = this;

			return this.panelAttributes.glassContext.getCoreSvc('.Ajax').ajax({
				url: url,
				// TODO: For some reason Safari on iOS was caching results, force off for now. This shouldn't be required.
				cache: false
			}).then(function (widgets) {
				return _this.fetchRequiredWidgetAttributes(widgets).then(function () {
					return widgets;
				});
			}).catch(function () {
				var msg = stringResources.get('errorLoadingWidgetList');

				return Promise.reject(msg);
			});
		},

		fetchWidgetListFromPerspective: function fetchWidgetListFromPerspective(collectionId, context) {
			var _this2 = this;

			return context.appController.findCollection(collectionId).then(function (collection) {
				var widgets = {
					list: collection ? JSON.parse(JSON.stringify(collection)) : collection
				};
				return _this2.fetchRequiredWidgetAttributes(widgets).then(function () {
					return widgets;
				});
			}).catch(function () {
				var msg = stringResources.get('errorLoadingWidgetList');

				return Promise.reject(msg);
			});
		},

		fetchRequiredWidgetAttributes: function fetchRequiredWidgetAttributes(widgetList) {
			var _this3 = this;

			var deferredArray = [];

			_.each(widgetList.list, function (w) {
				w.options = w.options || {};
				w.options.ext = _this3._hasExtensionTemplate(w);

				// extension templates are already localized from the perspective level
				if (!w.title && w.name) {
					w.title = w.options.ext ? w.name : stringResources.get(w.name);
				}

				if (!w.name) {
					w.name = w.title;
				}

				if (w.options.templatePath && !w.options.template) {
					deferredArray.push(_this3._loadTemplate(w));
				} else if (w.options.imageLink) {
					deferredArray.push(_this3._loadImage(w));
				} else {
					// ensure the deferred array maps with the widget list
					deferredArray.push(true);
				}

				if (w.url) {
					w.getEntries = _this3.fetchWidgetList.bind(_this3, w.url);
				}
			});

			if (deferredArray.length) {
				return Promise.all(deferredArray).then(function (isLoaded) {
					// filter out any widgets that has failed to load
					widgetList.list = _.filter(widgetList.list, function (w, i) {
						return isLoaded[i];
					});
				});
			}

			return Promise.resolve();
		},

		_loadImage: function _loadImage(widget) {
			return new Promise(function (resolve) {
				// eslint-disable-next-line no-undef
				var img = new Image();
				img.onload = function () {
					resolve(true);
				};
				img.onerror = function () {
					resolve(false);
				};
				img.src = widget.options.imageLink;
			});
		},

		_loadTemplate: function _loadTemplate(widget) {
			var _this4 = this;

			var cdnUrl = '';
			var extensionTemplate = this._hasExtensionTemplate(widget);

			if (!extensionTemplate) {
				cdnUrl = this.panelAttributes.cdnUrl || '';
			}

			return new Promise(function (resolve) {
				_this4.requireFn(['text!' + cdnUrl + widget.options.templatePath], function (template) {
					if (extensionTemplate) {
						var xml = $.parseXML(template);
						var svgRoot = $(xml).find('svg');
						if (svgRoot.length > 0) {
							if (typeof widget.options.viewBox === 'undefined') {
								// respect the viewbox defined in the svg
								var viewbox = svgRoot.attr('viewBox');
								if (viewbox) {
									widget.options.viewBox = viewbox;
									widget.options.previewBox = widget.options.viewBox;
								} else {
									// create a viewbox based on the size
									var width = parseInt(svgRoot.attr('width'), 10) || 100;
									var height = parseInt(svgRoot.attr('height'), 10) || 100;
									widget.options.viewBox = '0 0 ' + width + ' ' + height;
									widget.options.previewBox = '-10 -10 ' + width * 1.2 + ' ' + height * 1.2;
								}
							}
							template = '';
							var content = svgRoot.children();
							_.each(content, function (node) {
								// eslint-disable-next-line no-undef
								template += new XMLSerializer().serializeToString(node);
							});
						}
					}
					widget.options.template = template;
					// resolve as succeeded
					resolve(true);
				}, function (error) {
					_this4.logger.error('Failed to load widget', error);
					// resolve as failed - don't reject since we want continue with other successful widgets
					resolve(false);
				});
			});
		},

		_hasExtensionTemplate: function _hasExtensionTemplate(widget) {
			if (widget && widget.options) {
				var ext = new RegExp('^v[0-9]+/ext/.+$');
				return ext.test(widget.options.templatePath);
			}
			return false;
		},

		_getDefaultSpec: function _getDefaultSpec(Widget, widget) {
			if (Widget.getDefaultSpec) {
				if (widget.options) {
					widget.options.dashboardApi = this.dashboardApi;
				}
				/** getDefaultSpec() is expected to return a promise that will be resolved with the default spec. for the widget. */
				return Widget.getDefaultSpec(widget.name, widget.options);
			} else {
				var copyDefaultSpec = widget.defaultSpec ? JSON.parse(JSON.stringify(widget.defaultSpec)) : {};
				return Promise.resolve(copyDefaultSpec);
			}
		},

		_addFillAndBorderToAvatarIfNeeded: function _addFillAndBorderToAvatarIfNeeded(Widget, avatar, spec) {
			if (Widget.addFillAndBorderToAvatarIfNeeded) {
				Widget.addFillAndBorderToAvatarIfNeeded(avatar, spec);
			}
		},

		addWidgetBySelection: function addWidgetBySelection(widget, ev, options) {
			var _this5 = this;

			options = options || {};

			if (ev.gesture) {
				// prevent simulated click if we have a touch gesture.
				ev.gesture.preventDefault();
			}

			var sWidget = widget.widget;
			var dndManagerFeature = this.dashboardApi.getFeature('DashboardDnd.internal');
			return new Promise(function (resolve) {
				var api = _this5.dashboardApi.getCanvas();
				var onAddDone = function onAddDone(id) {
					if (id) {
						api.selectWidget(id, {
							isTouch: ev.type === 'tap',
							options: options.selectOptions ? options.selectOptions : undefined
						});
					}
					// Computers click very quickly (during functional tests). This call to
					// resetDragging() needs to happen *after* the call to startDrag() in
					// addWidgetByDrag, or else the drag started there won't be cancelled
					// and you can end up with a dragging widget hanging on the mouse after
					// clicking on a widget in a panel.
					dndManagerFeature.resetDragging();
					resolve(id);
				};

				// we are adding a dashboard fragment
				if (widget.fragment) {
					// add a copy of the fragment
					var id = api.addFragment({ model: JSON.parse(JSON.stringify(widget.fragment)) });
					onAddDone(id);
					return;
				}

				_this5.requireFn([sWidget], function (Widget) {

					var id = null;
					if (!api.hasMaximizedWidget()) {
						_this5._getDefaultSpec(Widget, widget).then(function (spec) {
							// Remove properties piggy-backed on spec
							spec.model.avatarHtml = undefined;
							spec.model.visTypeLocked = true; //On create widget of specific type, lock that type in
							var content = {
								spec: spec.model
							};
							if (spec.layoutProperties) {
								//liveWidget does not have layoutProperties in defaultSpec
								content.layout = spec.layoutProperties.style;
							}
							var transactionApi = _this5.dashboardApi.getFeature('Transaction');
							var transactionToken = transactionApi.startTransaction();
							api.addContent(content, transactionToken).then(function (content) {
								onAddDone(content.getId());
								resolve(content.getId());
							}).finally(transactionApi.endTransaction.bind(transactionApi, transactionToken));
						}).catch(function (e) {
							_this5.logger.error(e);
							resolve(id);
						});
					} else {
						resolve(id);
					}
				});
			});
		},

		addWidgetByDrag: function addWidgetByDrag(widget, ev) {
			var _this6 = this;

			if (widget.fragment || widget.widget) {
				ev.stopPropagation();
				var dndManagerFeature = this.dashboardApi.getFeature('DashboardDnd.internal');
				return new Promise(function (resolve, reject) {

					var prepareDrag = function prepareDrag(type, dropInfo, ev, widget, spec, avatarStyle) {
						var avatar = $('<div>');
						var moveX, moveY;
						moveX = moveY = ev.showAvatarImmediately ? 0 : 20;

						avatar.addClass('avatar');
						avatar.addClass('widget');

						// if avatarHtml is provided, it should take precedence
						if (spec) {
							if (spec.model.avatarHtml) {
								avatar.html(spec.model.avatarHtml);
								// Don't store the avatar HTML
								spec.model.avatarHtml = undefined;
							} else if (spec.model.content) {
								avatar.html(spec.model.content);
							}
							avatar.addClass(spec.model.type + 'Widget');
						}

						if (widget) {
							_this6._addFillAndBorderToAvatarIfNeeded(widget, avatar, spec);
						}

						var style = avatarStyle || spec && spec.layoutProperties && spec.layoutProperties.style;
						if (style) {
							avatar.css(style);
						}

						// TODO: having widgetType and widgetSpec seems redundant since this information is is in the dropInfo
						// We need to revisit and cleanu the DnD payload
						var dragInfo = {
							event: ev,
							type: type,
							data: dropInfo,
							widgetSpec: spec || null,
							widgetType: spec && spec.model.type || null,
							avatar: avatar,
							moveXThreshold: moveX,
							moveYThreshold: moveY,
							showAvatarImmediately: ev.showAvatarImmediately || false
						};

						return dragInfo;
					};

					// wW are dragging a fragment
					// piggy back on the pin drag payload since it uses a fragment. 
					// TODO: ideally we should make the fragment drag to be generic and not related to just pins.
					var fragment = widget.fragment;
					if (fragment) {
						var dropInfo = {
							operation: 'new',
							pinSpec: {
								contentType: 'boardFragment',
								content: JSON.parse(JSON.stringify(fragment))
							}
						};
						var dragInfo = prepareDrag('pin', dropInfo, ev, null, null, fragment.layout && fragment.layout.style);
						dndManagerFeature.startDrag(dragInfo);
						resolve(dragInfo);
						return;
					}

					_this6.requireFn([widget.widget], function (Widget) {
						_this6._getDefaultSpec(Widget, widget).then(function (spec) {
							//On create widget of specific type, lock that type in
							spec.model.visTypeLocked = true;
							var dropInfo = _.extend(spec, {
								operation: 'new'
							});
							var dragInfo = prepareDrag('widget', dropInfo, ev, Widget, spec);
							dndManagerFeature.startDrag(dragInfo);
							resolve(dragInfo);
						}).catch(reject);
					});
				});
			}
			return Promise.reject();
		}

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