'use strict';

/*
 * Licensed Materials - Property of IBM
 * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2014, 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/Class', 'jquery', '../../canvas/CanvasFactory', './WidgetLoader', '../../lib/@waca/core-client/js/core-client/utils/ClassFactory', './DeploymentReferencesUtil', 'underscore', '../../extension/Extensions', './BoardLoaderHelper', '../../lib/@waca/core-client/js/core-client/utils/Deferred'], function (BaseClass, $, CanvasFactory, WidgetLoader, ClassFactory, DeploymentReferencesUtil, _, Extensions, BoardLoaderHelper, Deferred) {

	/**
  * The board loader's responsibility is to load a dashboard. The board loader will be used in two main scenarios:
  *
  * 1. Loading a board from within the Gemini app (e.g from the homepage)
  * 2. Loading a board directly from a URL
  *
  * @param options
  *
  *	boardSpec			The board specification if avaialble, otherwise the spec will be fetched using the board ID
  *  boardId				The board ID used to fetch the spec
  *  isAuthoringMode		Set to true if the board is being loaded in authoring mode
  *  el					The element to render the board layout to
  *  isLayoutRendered	Set to false if the board's layout hasn't already been rendered
  *
  */
	var BoardLoader = BaseClass.extend({

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

			// start - to be removed after done the refactoring
			this.glassContext = options.glassContext;
			this.appSettings = options.appSettings || {};
			this.services = options.services;
			this.ajaxSvc = options.ajaxSvc;
			// end - to be removed after done the refactoring

			this.dashboardApi = options.dashboardApi;

			this.eventRouter = options.eventRouter;

			this.boardSpec = options.boardSpec;
			this.addOnSpec = options.addOnSpec;
			this.specUrl = options.specUrl;

			this.boardModel = options.boardModel;

			this.setDirty = this.boardModel.isUpgraded || false;

			this.pageViewContentNode = options.el;
			this.contentNode = null;
			this.$viewEl = options.$viewEl;
			this.isLayoutRendered = options.isLayoutRendered;

			this._registry = options.widgetRegistry;

			this.gatewayUrl = options.gatewayUrl || '';
			this.cdnUrl = options.cdnUrl || '';
			this.currentVersion = options.currentVersion;
			this.logger = this.dashboardApi.getGlassCoreSvc('.Logger');

			this.stringResources = this.dashboardApi.getDashboardCoreSvc('.StringResources');

			this.extensions = options.extensions;

			this.boardLoaderHelper = new BoardLoaderHelper(this.dashboardApi);

			this.boardModuleFactory = this.boardLoaderHelper.createBoardModuleFactory(options.boardModules);

			// loading dfds
			this._canvasControllerDfd = new Deferred();

			this.featureLoader = options.featureLoader;
			this._dashboardController = options.dashboardController;
			this._colorsService = this.dashboardApi.getFeature('Colors');
		},

		getCanvasController: function getCanvasController() {
			return this._canvasControllerDfd.promise;
		},

		_createCanvas: function _createCanvas() {
			var _this = this;

			var factory = new CanvasFactory({
				dashboardAPI: this.dashboardApi,
				services: this.services,
				extensions: this.extensions,
				glassContext: this.glassContext,
				eventRouter: this.eventRouter,
				appSettings: this.appSettings,
				logger: this.logger,
				widgetRegistry: this._registry,
				featureLoader: this.featureLoader,
				boardModel: this.boardModel,
				dashboardContent: this._dashboardController.getContent()
			});
			return factory.createCanvas().then(function (factoryResponse) {
				_this.canvas = factoryResponse.canvas;
				_this.internalCanvas = factoryResponse.internalCanvas;
			});
		},

		_createDashboardContent: function _createDashboardContent() {
			return this._dashboardController.createContent(this.boardModel);
		},

		/**
   * Load the board
   *
   * @returns Deferred which is resolved once the board is loaded
   */
		loadBoard: function loadBoard() {
			return this._preDashboardInitialize().then(this._createDashboardContent.bind(this)).then(this._createCanvas.bind(this)).then(this._registerServices.bind(this)).then(this._initializeTranslationService.bind(this)).then(this._renderLayoutHtml.bind(this)).then(this._initBoardController.bind(this)).then(this._postDashboardInitialize.bind(this));
		},

		getCanvas: function getCanvas() {
			return this.canvas;
		},

		_initializeTranslationService: function _initializeTranslationService() {
			return this.dashboardApi.getDashboardSvc('TranslationService').then(function (translationService) {
				return translationService.initialize({ boardModel: this.boardModel, view: this.$viewEl });
			}.bind(this));
		},

		_getDashboardFrameNode: function _getDashboardFrameNode() {
			var parentNode = this.pageViewContentNode;
			var dashboardFrame = parentNode.querySelector('.dashboardFrame');
			if (!dashboardFrame) {
				dashboardFrame = document.createElement('div');
				dashboardFrame.setAttribute('class', 'dashboardFrame');

				var dashboardFrameCentre = document.createElement('div');
				dashboardFrameCentre.setAttribute('class', 'dashboardFrameCentre');

				var dashboardFrameRight = document.createElement('div');
				dashboardFrameRight.setAttribute('class', 'dashboardFrameRight');

				dashboardFrame.appendChild(dashboardFrameCentre);

				dashboardFrame.appendChild(dashboardFrameRight);

				parentNode.appendChild(dashboardFrame);
			}
			return dashboardFrame;
		},

		_getDashboardFrameCentreNode: function _getDashboardFrameCentreNode() {
			var dashboardFrame = this._getDashboardFrameNode();
			return dashboardFrame.querySelector('.dashboardFrameCentre');
		},

		_setContentNode: function _setContentNode() {
			this.contentNode = this._getDashboardFrameCentreNode();
		},
		/**
   * Render the layout HTML into the board's DOM element
   *
   * TODO: This is a bit awkward, it'd be nice if we could just create the board and if the DOM elements don't exist that
   * we'd create them on the fly.
   *
   * @returns deferred which is resolved once the HTML is rendered
   */
		_renderLayoutHtml: function _renderLayoutHtml() {
			var _this2 = this;

			// first set the content node where we want to render the content
			this._setContentNode();

			return this.boardLoaderHelper.loadLayoutExtensions(this.extensions.getLayoutViewExtensions(), this.boardModuleFactory).then(function (layoutExtensions) {
				_this2.boardLoaderHelper.registerLayoutExtensions(layoutExtensions);
				var html = _this2.dashboardApi.getFeature('htmlTemplates').getHtml(_this2.boardModel.layout, _this2.boardModel.widgetInstances);
				if (!_this2.isLayoutRendered) {
					_this2.contentNode.innerHTML = html;
				}
			});
		},

		/**
   * Initialize the board controller
   */
		_initBoardController: function _initBoardController() {
			var _this3 = this;

			return ClassFactory.loadModule('dashboard-core/js/dashboard/CanvasController').then(function (CanvasController) {
				_this3.widgetLoader = new WidgetLoader({
					// TODO begin to be removed
					glassContext: _this3.glassContext,
					services: _this3.services,
					appSettings: _this3.appSettings,
					// end to be removed

					dashboardApi: _this3.dashboardApi,
					eventRouter: _this3.eventRouter,

					widgetRegistry: _this3._registry,
					loadedWidgets: {},
					boardModel: _this3.boardModel,
					contentFeatureLoader: _this3.internalCanvas,
					canvas: _this3.getCanvas()
				});

				_this3.canvasController = new CanvasController({
					//begin to be removed
					glassContext: _this3.glassContext,
					services: _this3.services,
					appSettings: _this3.appSettings,
					//end to be removed

					dashboardApi: _this3.dashboardApi,
					eventRouter: _this3.eventRouter,
					$el: _this3.$viewEl,
					boardModel: _this3.boardModel,
					boardModuleFactory: _this3.boardModuleFactory,
					widgetLoader: _this3.widgetLoader,
					layoutExtensions: _this3.extensions.getLayoutViewExtensions(),
					boardLoader: _this3,
					gatewayUrl: _this3.gatewayUrl,
					cdnUrl: _this3.cdnUrl,
					contentFeatureLoader: _this3.internalCanvas
				});

				// TODO - Explore and storyTelling are using this service
				// Should be removed
				_this3.dashboardApi.registerDashboardSvc('widgetLoader', {
					loadedWidgets: _this3.widgetLoader.loadedWidgets,
					loadingWidgets: _this3.widgetLoader.loadingWidgets,
					load: _this3.widgetLoader.loadWidget.bind(_this3.widgetLoader),
					unload: _this3.widgetLoader.unLoadWidget.bind(_this3.widgetLoader),
					isLoaded: _this3.widgetLoader.isLoaded.bind(_this3.widgetLoader),
					isLoading: _this3.widgetLoader.isLoading.bind(_this3.widgetLoader),
					getWidget: _this3.widgetLoader.getWidget.bind(_this3.widgetLoader)
				});

				return _this3.canvasController.initialize().then(function () {
					_this3._canvasControllerDfd.resolve(_this3.canvasController);
				});
			}).catch(function (err) {
				_this3.logger.error(err);
				// don't rethrow, recover
				// TODO: probably rethrowing is a good idea. if you're
				// brave enough and you know what you're doing, make it do that.
			});
		},

		_preDashboardInitialize: function _preDashboardInitialize() {
			return this.dashboardApi.getFeature('.LifeCycleManager').invokeLifeCycleHandlers('pre:dashboard.initialize');
		},

		_postDashboardInitialize: function _postDashboardInitialize() {
			return this.dashboardApi.getFeature('.LifeCycleManager').invokeLifeCycleHandlers('post:dashboard.initialize');
		},

		_registerServices: function _registerServices() {

			// TODO - these services must go away
			//Add the board loader services
			var services = this.boardLoaderHelper.createBoardServices({
				boardModel: this.boardModel,
				widgetRegistry: this._registry
			});

			this.smartNamingSvc = services.smartNamingSvc;
		},

		/**
   * Populate map of widgetId and containerPageId from given layout. populate recursively if layout has items
   * Widget can be determined by type of layout.
   */
		_mapContainerPageForWidgetsInLayout: function _mapContainerPageForWidgetsInLayout(layout, map, containerPageId) {
			map = map || {};
			if (layout.items) {
				for (var i = 0; i < layout.items.length; i++) {
					map = this._mapContainerPageForWidgetsInLayout(layout.items[i], map, containerPageId);
				}
			} else if (layout.type === 'widget') {
				map[layout.id] = containerPageId;
			}
			return map;
		},

		activate: function activate() {
			if (this._colorsService) {
				this._colorsService.enableTheme();
			}
		},

		deactivate: function deactivate() {
			if (this._colorsService) {
				this._colorsService.disableTheme();
			}
		},

		destroyViews: function destroyViews() {
			this.deactivate();

			// The canvasController and widget loader might not exist if we are loading an invalid dashboard( missing/invalid spec or no permissions)
			if (this.widgetLoader) {
				this.widgetLoader.cleanup();
				this.widgetLoader = null;
			}

			if (this.canvasController) {
				this.canvasController.destroy();
				this.canvasController = null;
			}
		},
		/**
   * Destroy the board loader
   */
		destroyCanvasAPI: function destroyCanvasAPI() {
			if (this.internalCanvas) {
				this.internalCanvas.destroy();
				this.internalCanvas = null;
			}
		},

		_hasPermission: function _hasPermission(permissions) {
			return _.indexOf(permissions, 'read') !== -1 && _.indexOf(permissions, 'execute') !== -1;
		}

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