'use strict';

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

/**
 * Licensed Materials - Property of IBM
 * IBM Business Analytics (C) Copyright IBM Corp. 2019, 2020
 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 */

/**
 * @class RenderSequenceImpl
 * @hideconstructor
 * @classdesc
 */
define(['underscore', '../../../../lib/@waca/dashboard-common/dist/api/impl/CallbackInvoker', '../../../../lib/@waca/dashboard-common/dist/core/APIFactory', '../../../../lib/@waca/dashboard-common/dist/api/Error', '../api/RenderContextAPI', '../s12y/RenderSequenceInfo', '../s12y/ServiceabilityRenderingInfo', '../s12y/ServiceabilitySQLInfo', './RenderContextImpl', '../s12y/RenderingInfo'], function (_, CallbackInvoker, APIFactory, APIError, RenderContextAPI, RenderSequenceInfo, ServiceabilityRenderingInfo, ServiceabilitySQLInfo, RenderContextImpl, RenderingInfo) {
	var _class, _temp;

	var RenderSequenceImpl = (_temp = _class = function (_CallbackInvoker) {
		_inherits(RenderSequenceImpl, _CallbackInvoker);

		/**
   * TODO: remove the usage of dashboardAPI.getService when dashboardAPI.getFeature includes the glass service
   * @param {Object} options
   * @param {DashboardAPI} options.dashboardAPI
   * @param {Object[]} options.features
   */
		function RenderSequenceImpl(_ref) {
			var dashboardAPI = _ref.dashboardAPI,
			    features = _ref.features,
			    content = _ref.content;

			_classCallCheck(this, RenderSequenceImpl);

			var logger = dashboardAPI.getService(dashboardAPI.GLOBAL_SERVICES.LOGGER);

			var _this = _possibleConstructorReturn(this, _CallbackInvoker.call(this, { logger: logger }));

			_this._logger = logger;
			_this._s12yAPI = features['Serviceability'];
			_this._renderStepProviders = [];
			_this._currentRenderContext = {};
			_this.content = content;
			var impl = _this;
			_this.onStartTaskExecution(function (options) {
				impl.s12yOnStartTaskExecution(options);
			});
			_this.onResolveTaskExecution(function (options) {
				impl.s12yOnResolveTaskExecution(options);
			});
			_this.onRejectTaskExecution(function (options) {
				impl.s12yOnRejectTaskExecution(options);
			});
			return _this;
		}

		RenderSequenceImpl.prototype.registerRenderEngine = function registerRenderEngine(renderEngine) {
			this._engine = renderEngine;
		};

		/**
   * @implements RenderSequenceInternalAPI#triggerRenderSequence
   */


		RenderSequenceImpl.prototype.triggerRenderSequence = function triggerRenderSequence(options) {
			var _this2 = this;

			this._currentRenderContext = {};

			this._s12yStartRenderSequence(options);
			return this._engine.process(options).then(function (result) {
				_this2._s12yResolveRenderSequence(options);
				return result;
			}).catch(function (error) {
				_this2._s12yResolveRenderSequence(options);
				throw error;
			});
		};

		/**
   * @private
   * @function _s12yStartRenderSequence
   * @description Start tracking the widget render time by creating a current render object
   * @param {Object} options
   * @param {number} options.renderId - the current render ID that is being executed
   */


		RenderSequenceImpl.prototype._s12yStartRenderSequence = function _s12yStartRenderSequence(options) {
			try {
				var contentInfo = this._s12yAPI.getContentInfo();
				if (contentInfo) {
					var s12ySQLInfo = contentInfo.getData(RenderSequenceImpl.S12Y_SQL_INFO);
					if (!s12ySQLInfo) {
						//TODO:Seems out of place to access DataQueryExecution inside render sequence
						//see if there is a better way to access this
						//ServiceabilitySQLInfo could be used in other render tasks in theory
						var queryExecution = this.content.getFeature('DataQueryExecution');
						var visApi = this.content.getFeature('WidgetAPI.deprecated').getVisApi();
						s12ySQLInfo = new ServiceabilitySQLInfo(visApi, queryExecution);
						contentInfo.setData(RenderSequenceImpl.S12Y_SQL_INFO, s12ySQLInfo);
					}

					var s12yRenderingInfo = contentInfo.getData(RenderSequenceImpl.S12Y_RENDERING_INFO);
					if (!s12yRenderingInfo) {
						s12yRenderingInfo = new ServiceabilityRenderingInfo(this._logger);
						contentInfo.setData(RenderSequenceImpl.S12Y_RENDERING_INFO, s12yRenderingInfo);
					}

					var renderingInfo = s12yRenderingInfo.getCurrentRendering();

					if (renderingInfo === undefined) {
						renderingInfo = new RenderingInfo({ renderId: options.renderId });
						s12yRenderingInfo.setCurrentRendering(renderingInfo);
					} else {
						renderingInfo.registerSequenceId(options.renderId);
					}
				} else {
					this._logger.info('Serviceability feature is not enabled');
				}
			} catch (error) {
				this._logger.error('Failed to track RenderingInfo for renderId [' + options.renderId + ']', error);
			}
		};

		/**
   * @private
   * @function s12yResolveRenderSequence
   * @description Resolve the tracking for RenderInfo
   * @param {Object} options
   * @param {number} options.renderId - the current render ID that is being executed
   */


		RenderSequenceImpl.prototype._s12yResolveRenderSequence = function _s12yResolveRenderSequence(options) {
			try {
				var contentInfo = this._s12yAPI.getContentInfo();
				if (contentInfo) {
					var s12yRenderingInfo = contentInfo.getData(RenderSequenceImpl.S12Y_RENDERING_INFO);

					var renderingInfo = s12yRenderingInfo.getCurrentRendering();
					if (renderingInfo && renderingInfo.getLastSequenceId() === options.renderId) {
						renderingInfo.setEndTime(Date.now());
						if (renderingInfo.isWithData()) {
							s12yRenderingInfo.setLastRendering(renderingInfo);
						}
						s12yRenderingInfo.setCurrentRendering(undefined);
					}
				}
			} catch (error) {
				this._logger.error('Failed to track RenderingInfo for renderId [' + options.renderId + ']', error);
			}
		};

		RenderSequenceImpl.prototype.getCurrentRenderContext = function getCurrentRenderContext(taskId) {
			return this._currentRenderContext[taskId];
		};

		/**
   * TODO: remove the call to _isStepComplete as a task should be processed only when it needs
   * @implements RenderSequenceInternalAPI#startTaskExecution
   */


		RenderSequenceImpl.prototype.startTaskExecution = function startTaskExecution(taskInfo) {
			var taskId = taskInfo.task.instance.getId();
			try {
				if (taskInfo.task.instance._isStepComplete(taskInfo.renderContext, taskId) === true) {
					this._logger.info('execution of task [' + taskId + '] is ignored for s12y as it is already complete');
				} else {
					this._setSQLFetchParams(taskInfo.renderContext);
					var taskRenderContext = this._createTaskRenderContext(taskInfo.renderContext);
					this.invokeCallbacks(RenderSequenceImpl.START_TASK_EXECUTION, { renderContext: taskRenderContext, taskId: taskId });
				}
			} catch (error) {
				this._logger.error('fail to check if task [' + taskId + '] is complete', error);
			}

			return taskInfo.task.instance.process(taskInfo.renderContext);
		};

		/**
   * @implements RenderSequenceInternalAPI#resolveTaskExecution
   */


		RenderSequenceImpl.prototype.resolveTaskExecution = function resolveTaskExecution(taskInfo) {
			var taskId = taskInfo.task.instance.getId();
			var taskRenderContext = this._createTaskRenderContext(taskInfo.renderContext);
			this.invokeCallbacks(RenderSequenceImpl.RESOLVE_TASK_EXECUTION, { renderContext: taskRenderContext, taskId: taskId });
			taskInfo.taskExecution.resolve();
			this._currentRenderContext[taskInfo.task.id] = taskRenderContext;
		};

		/**
   * @implements RenderSequenceInternalAPI#rejectTaskExecution
   */


		RenderSequenceImpl.prototype.rejectTaskExecution = function rejectTaskExecution(taskInfo) {
			var taskRenderContext = this._createTaskRenderContext(taskInfo.renderContext);
			this.invokeCallbacks(RenderSequenceImpl.REJECT_TASK_EXECUTION, { error: taskInfo.error, renderContext: taskRenderContext, taskId: taskInfo.task.instance.getId() });
			taskInfo.taskExecution.reject(taskInfo.error);
			this._currentRenderContext[taskInfo.task.id] = taskRenderContext;
		};

		/**
   * @implements RenderSequenceAPI#onStartTaskExecution
   */


		RenderSequenceImpl.prototype.onStartTaskExecution = function onStartTaskExecution(method) {
			this.registerCallback(RenderSequenceImpl.START_TASK_EXECUTION, method);
		};

		/**
   * @implements RenderSequenceAPI#onSuccessEndTaskExecution
   */


		RenderSequenceImpl.prototype.onResolveTaskExecution = function onResolveTaskExecution(method) {
			this.registerCallback(RenderSequenceImpl.RESOLVE_TASK_EXECUTION, method);
		};

		/**
   * @implements RenderSequenceAPI#onFailureEndTaskExecution
   */


		RenderSequenceImpl.prototype.onRejectTaskExecution = function onRejectTaskExecution(method) {
			this.registerCallback(RenderSequenceImpl.REJECT_TASK_EXECUTION, method);
		};

		/**
   * @implements RenderSequenceAPI#registerRenderStepProvider
   */


		RenderSequenceImpl.prototype.registerRenderStepProvider = function registerRenderStepProvider(provider) {
			if (provider) {
				if (typeof provider.getRenderStepList !== 'function') {
					throw new Error('the provide must implement "getRenderStepList()" ');
				}
				this._renderStepProviders.push(provider);
			}
		};

		/**
   * @implements RenderSequenceAPI#getProvidersRenderStepList
   */


		RenderSequenceImpl.prototype.getProvidersRenderStepList = function getProvidersRenderStepList() {
			var _this3 = this;

			var steps = [];
			this._renderStepProviders.forEach(function (provider) {
				try {
					var extraSteps = provider.getRenderStepList();
					if (Array.isArray(extraSteps)) {
						steps.push.apply(steps, extraSteps);
					} else {
						_this3._logger.warn('Provide render steps are ignored. The render step provider did not return an array. ');
					}
				} catch (e) {
					_this3._logger.error('An error while getting the render step list from the provider', e);
				}
			});
			return steps;
		};

		/**
   * creates an instance of RenderContext with the API method of {@link RenderContextAPI}
   * @param {Object} renderContext - sequence renderContext
   */


		RenderSequenceImpl.prototype._createTaskRenderContext = function _createTaskRenderContext(renderContext) {
			var renderContextImpl = new RenderContextImpl({ logger: this._logger, renderContext: renderContext });
			var api = APIFactory.createAPI(renderContextImpl, [RenderContextAPI]);
			return api;
		};

		/**
   * Callback to task execution start
   * @param {RenderContextAPI} payload
   */


		RenderSequenceImpl.prototype.s12yOnStartTaskExecution = function s12yOnStartTaskExecution(payload) {
			var s12yInfo = this._s12yAPI.getContentInfo();
			if (!s12yInfo) {
				this._logger.info('Serviceability feature is not enabled');
			} else {
				var sequenceId = payload.renderContext.getSequenceId();
				var renderingInfo = s12yInfo.getData(RenderSequenceImpl.S12Y_RENDERING_INFO);
				var currentRender = renderingInfo.getCurrentRendering();
				if (currentRender) {
					currentRender.setWithData(true);
					var renderSequenceInfo = currentRender.getRenderSequenceWithData();
					if (this._isNewerSequence(sequenceId, renderSequenceInfo)) {
						renderSequenceInfo = new RenderSequenceInfo({ id: sequenceId });
						renderSequenceInfo.addTaskInfo({ taskId: payload.taskId });
						currentRender.setRenderSequenceWithData(renderSequenceInfo);
					}
				}
			}
		};

		/**
   * Callback to task resolution
   * TODO: introduce a generic way to get task providing their own result
   * @param {RenderContextAPI} payload
   */


		RenderSequenceImpl.prototype.s12yOnResolveTaskExecution = function s12yOnResolveTaskExecution(payload) {
			var taskExecInfo = this._setTaskExecEndTime(payload);
			this._setQueryFeedbackSQLResult(payload.renderContext.getData(payload.taskId));
			if (taskExecInfo) {
				this._setDataResult(taskExecInfo, payload.renderContext.getData(payload.taskId));
			}
		};

		/**
   * Callback to task rejection
   * TODO: remove the assumption the task is a data task
   * @param {RenderContextAPI} payload
   */


		RenderSequenceImpl.prototype.s12yOnRejectTaskExecution = function s12yOnRejectTaskExecution(payload) {
			var taskExecInfo = this._setTaskExecEndTime(payload);
			if (taskExecInfo) {
				this._setTaskExecError(taskExecInfo, payload.error);
			}
		};

		RenderSequenceImpl.prototype._setQueryFeedbackSQLResult = function _setQueryFeedbackSQLResult(data) {
			var contentInfo = this._s12yAPI.getContentInfo();
			if (contentInfo) {
				var sqlInfo = contentInfo.getData(RenderSequenceImpl.S12Y_SQL_INFO);
				if (!_.isEmpty(data)) {
					data.getQueryResultIdList().forEach(function (id) {
						var queryResult = data.getResult(id);
						sqlInfo.widgetsLastCognosQuery = queryResult.getPropertyValue('QueryFeedback.cognosSQL');
						sqlInfo.widgetsLastNativeQuery = queryResult.getPropertyValue('QueryFeedback.nativeSQL');
						sqlInfo.widgetsLastMDXQuery = queryResult.getPropertyValue('QueryFeedback.MDX');
					});
				}
			} else {
				this._logger.info('Serviceability feature is not enabled');
			}
		};

		RenderSequenceImpl.prototype._setSQLFetchParams = function _setSQLFetchParams(renderContext) {
			var contentInfo = this._s12yAPI.getContentInfo();
			if (contentInfo) {
				renderContext.extraInfo = renderContext.extraInfo || {};
				var sqlInfo = contentInfo.getData(RenderSequenceImpl.S12Y_SQL_INFO);
				if (sqlInfo.shouldFetchQuery) {
					renderContext.extraInfo.dataQueryParams = { qfb: 'nativeCommandText,nativeCommandType,CognosCommandText' };
				}
			} else {
				this._logger.info('Serviceability feature is not enabled');
			}
		};

		/**
   * @private
   * @param {integer} startedSequenceId
   * @param {RenderSequenceInfo} s12ySequenceInfo
   * @returns {boolean} true if s12ySequenceInfo is undefined or the startedSequenceId is greater than the s12ySequenceInfo one
   */


		RenderSequenceImpl.prototype._isNewerSequence = function _isNewerSequence(startedSequenceId, s12ySequenceInfo) {
			return !s12ySequenceInfo || startedSequenceId > s12ySequenceInfo.getId();
		};

		/**
   * sets the task end time if needed
   * @private
   * @param {RenderContextAPI} options - callback payload
   * @returns {RenderTaskExecInfo} - the task exec info or undefined if none is to be updated
   */


		RenderSequenceImpl.prototype._setTaskExecEndTime = function _setTaskExecEndTime(options) {
			var taskExecInfo = void 0;
			var s12yInfo = this._s12yAPI.getContentInfo();
			if (!s12yInfo) {
				this._logger.info('Serviceability feature is not enabled');
			} else {
				var sequenceId = options.renderContext.getSequenceId();
				var s12yRenderingInfo = s12yInfo.getData(RenderSequenceImpl.S12Y_RENDERING_INFO);
				var currentRenderInfo = s12yRenderingInfo.getCurrentRendering();
				if (currentRenderInfo) {
					var renderSequenceInfo = currentRenderInfo.getRenderSequenceWithData();
					if (renderSequenceInfo && sequenceId === renderSequenceInfo.getId()) {
						taskExecInfo = renderSequenceInfo.getTaskInfo(options.taskId);
						taskExecInfo.setEndTime();
					} else {
						this._logger.info('s12y - setting end time - task [' + options.taskId + '] sequence ' + sequenceId + ' from is ignored by the registered s12y sequence info', renderSequenceInfo);
					}
				}
			}
			return taskExecInfo;
		};

		/**
   * creates an error object and sets it in the taskExecInfo
   * TODO: there should be only one logic to generate the error object; there is one in VisRenderSequence and one here
   * @param {RenderTaskExecInfo} taskExecInfo
   * @param {Object} error
   */


		RenderSequenceImpl.prototype._setTaskExecError = function _setTaskExecError(taskExecInfo, error) {
			var msg = 'dwErrorRenderingVisualization';
			if (error) {
				if (error.msg) {
					msg = error.msg;
				} else if (error.message) {
					msg = error.message;
				}
			}
			var errorInfo = error ? error.errorInfo : undefined;
			taskExecInfo.setError(new APIError({ msg: msg, params: { errorInfo: errorInfo } }));
			if (errorInfo && typeof errorInfo.getResponseHeader === 'function') {
				taskExecInfo.addRequestTimeInfo(errorInfo.getResponseHeader('x-ca-requesttime'));
			}
		};

		/**
   * set data result; create a data with a toJSON method to make sure to grab the values only when needed
   * @param {RenderTaskExecInfo} taskExecInfo
   * @param {QueryResultObject} data
   */


		RenderSequenceImpl.prototype._setDataResult = function _setDataResult(taskExecInfo, data) {
			if (taskExecInfo && !_.isEmpty(data)) {
				data.getQueryResultIdList().forEach(function (id) {
					var queryResult = data.getResult(id);
					var requestTime = queryResult.getPropertyValue('RequestTime.internal');
					taskExecInfo.addRequestTimeInfo(requestTime);
				});

				var taskResults = {
					toJSON: function toJSON() {
						var result = [];
						data.getQueryResultIdList().forEach(function (id) {
							var queryResult = data.getResult(id);
							result.push({
								'spec': JSON.parse(queryResult.getPropertyValue('QuerySpec.internal')),
								'data': JSON.parse(queryResult.getPropertyValue('RawData.internal')),
								requestTime: queryResult.getPropertyValue('RequestTime.internal')
							});
						});
						return result;
					}
				};
				taskExecInfo.setData('queryResults', taskResults);
			}
		};

		return RenderSequenceImpl;
	}(CallbackInvoker), _class.START_TASK_EXECUTION = 'startTaskExecution', _class.RESOLVE_TASK_EXECUTION = 'resolveTaskExecution', _class.REJECT_TASK_EXECUTION = 'rejectTaskExecution', _class.LAST_RENDER_WITH_DATA = 'lastRenderingWithDataRequest', _class.S12Y_RENDERING_INFO = 'ServiceabilityRenderingInfo', _class.S12Y_SQL_INFO = 'ServiceabilitySQLInfo', _temp);


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