text: /*
   * Copyright © 2016-2018 The BeiDouApp Authors
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  export default angular.module('beidouapp.dashboardUtils', [])
      .factory('dashboardUtils', DashboardUtils)
      .name;
  
  /*@ngInject*/
  function DashboardUtils(types, utils, timeService) {
  
      var service = {
          validateAndUpdateDashboard: validateAndUpdateDashboard,
          validateAndUpdateWidget: validateAndUpdateWidget,
          getRootStateId: getRootStateId,
          createSingleWidgetDashboard: createSingleWidgetDashboard,
          createSingleEntityFilter: createSingleEntityFilter,
          getStateLayoutsData: getStateLayoutsData,
          createDefaultState: createDefaultState,
          createDefaultLayoutData: createDefaultLayoutData,
          setLayouts: setLayouts,
          updateLayoutSettings: updateLayoutSettings,
          addWidgetToLayout: addWidgetToLayout,
          removeWidgetFromLayout: removeWidgetFromLayout,
          isSingleLayoutDashboard: isSingleLayoutDashboard,
          removeUnusedWidgets: removeUnusedWidgets,
          getWidgetsArray: getWidgetsArray
      };
  
      return service;
  
      function validateAndUpdateEntityAliases(configuration, datasourcesByAliasId, targetDevicesByAliasId) {
          var aliasId, entityAlias;
          if (angular.isUndefined(configuration.entityAliases)) {
              configuration.entityAliases = {};
              if (configuration.deviceAliases) {
                  var deviceAliases = configuration.deviceAliases;
                  for (aliasId in deviceAliases) {
                      var deviceAlias = deviceAliases[aliasId];
                      entityAlias = validateAndUpdateDeviceAlias(aliasId, deviceAlias, datasourcesByAliasId, targetDevicesByAliasId);
                      configuration.entityAliases[entityAlias.id] = entityAlias;
                  }
                  delete configuration.deviceAliases;
              }
          } else {
              var entityAliases = configuration.entityAliases;
              for (aliasId in entityAliases) {
                  entityAlias = entityAliases[aliasId];
                  entityAlias = validateAndUpdateEntityAlias(aliasId, entityAlias, datasourcesByAliasId, targetDevicesByAliasId);
                  if (aliasId != entityAlias.id) {
                      delete entityAliases[aliasId];
                  }
                  entityAliases[entityAlias.id] = entityAlias;
              }
          }
          return configuration;
      }
  
      function validateAliasId(aliasId, datasourcesByAliasId, targetDevicesByAliasId) {
          if (!aliasId || !angular.isString(aliasId) || aliasId.length != 36) {
              var newAliasId = utils.guid();
              var aliasDatasources = datasourcesByAliasId[aliasId];
              if (aliasDatasources) {
                  aliasDatasources.forEach(
                        function(datasource) {
                            datasource.entityAliasId = newAliasId;
                        }
                  );
              }
              var targetDeviceAliasIdsList = targetDevicesByAliasId[aliasId];
              if (targetDeviceAliasIdsList) {
                  targetDeviceAliasIdsList.forEach(
                      function(targetDeviceAliasIds) {
                          targetDeviceAliasIds[0] = newAliasId;
                      }
                  );
              }
              return newAliasId;
          } else {
              return aliasId;
          }
      }
  
      function validateAndUpdateDeviceAlias(aliasId, deviceAlias, datasourcesByAliasId, targetDevicesByAliasId) {
          aliasId = validateAliasId(aliasId, datasourcesByAliasId, targetDevicesByAliasId);
          var alias = deviceAlias.alias;
          var entityAlias = {
              id: aliasId,
              alias: alias,
              filter: {
                  type: null,
                  entityType: types.entityType.device,
                  resolveMultiple: false
              },
          }
          if (deviceAlias.deviceFilter) {
              entityAlias.filter.type =
                  deviceAlias.deviceFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value;
              if (entityAlias.filter.type == types.aliasFilterType.entityList.value) {
                  entityAlias.filter.entityList = deviceAlias.deviceFilter.deviceList;
              } else {
                  entityAlias.filter.entityNameFilter = deviceAlias.deviceFilter.deviceNameFilter;
              }
          } else {
              entityAlias.filter.type = types.aliasFilterType.entityList.value;
              entityAlias.filter.entityList = [deviceAlias.deviceId];
          }
          return entityAlias;
      }
  
      function validateAndUpdateEntityAlias(aliasId, entityAlias, datasourcesByAliasId, targetDevicesByAliasId) {
          entityAlias.id = validateAliasId(aliasId, datasourcesByAliasId, targetDevicesByAliasId);
          if (!entityAlias.filter) {
              entityAlias.filter = {
                  type: entityAlias.entityFilter.useFilter ? types.aliasFilterType.entityName.value : types.aliasFilterType.entityList.value,
                  entityType: entityAlias.entityType,
                  resolveMultiple: false
              }
              if (entityAlias.filter.type == types.aliasFilterType.entityList.value) {
                  entityAlias.filter.entityList = entityAlias.entityFilter.entityList;
              } else {
                  entityAlias.filter.entityNameFilter = entityAlias.entityFilter.entityNameFilter;
              }
              delete entityAlias.entityType;
              delete entityAlias.entityFilter;
          }
          return entityAlias;
      }
  
      function validateAndUpdateWidget(widget) {
          if (!widget.config) {
              widget.config = {};
          }
          if (!widget.config.datasources) {
              widget.config.datasources = [];
          }
          widget.config.datasources.forEach(function(datasource) {
              if (datasource.type === 'device') {
                  datasource.type = types.datasourceType.entity;
              }
              if (datasource.deviceAliasId) {
                  datasource.entityAliasId = datasource.deviceAliasId;
                  delete datasource.deviceAliasId;
              }
          });
          //TODO: Temp workaround
          if (widget.isSystemType  && widget.bundleAlias == 'charts' && widget.typeAlias == 'timeseries') {
              widget.typeAlias = 'basic_timeseries';
          }
          return widget;
      }
  
      function createDefaultLayoutData() {
          return {
              widgets: {},
              gridSettings: {
                  backgroundColor: '#eeeeee',
                  color: 'rgba(0,0,0,0.870588)',
                  columns: 24,
                  margins: [10, 10],
                  backgroundSizeMode: '100%'
              }
          };
      }
  
      function createDefaultLayouts() {
          return {
              'main': createDefaultLayoutData()
          };
      }
  
      function createDefaultState(name, root) {
          return {
              name: name,
              root: root,
              layouts: createDefaultLayouts()
          }
      }
  
      function validateAndUpdateDashboard(dashboard) {
          if (!dashboard.configuration) {
              dashboard.configuration = {};
          }
          if (angular.isUndefined(dashboard.configuration.widgets)) {
              dashboard.configuration.widgets = {};
          } else if (angular.isArray(dashboard.configuration.widgets)) {
              var widgetsMap = {};
              dashboard.configuration.widgets.forEach(function (widget) {
                  if (!widget.id) {
                      widget.id = utils.guid();
                  }
                  widgetsMap[widget.id] = widget;
              });
              dashboard.configuration.widgets = widgetsMap;
          }
          for (var id in dashboard.configuration.widgets) {
              var widget = dashboard.configuration.widgets[id];
              dashboard.configuration.widgets[id] = validateAndUpdateWidget(widget);
          }
          if (angular.isUndefined(dashboard.configuration.states)) {
              dashboard.configuration.states = {
                  'default': createDefaultState(dashboard.title, true)
              };
  
              var mainLayout = dashboard.configuration.states['default'].layouts['main'];
              for (id in dashboard.configuration.widgets) {
                  widget = dashboard.configuration.widgets[id];
                  mainLayout.widgets[id] = {
                      sizeX: widget.sizeX,
                      sizeY: widget.sizeY,
                      row: widget.row,
                      col: widget.col,
                  };
                  if (angular.isDefined(widget.config.mobileHeight)) {
                      mainLayout.widgets[id].mobileHeight = widget.config.mobileHeight;
                  }
                  if (angular.isDefined(widget.config.mobileOrder)) {
                      mainLayout.widgets[id].mobileOrder = widget.config.mobileOrder;
                  }
              }
          } else {
              var states = dashboard.configuration.states;
              var rootFound = false;
              for (var stateId in states) {
                  var state = states[stateId];
                  if (angular.isUndefined(state.root)) {
                      state.root = false;
                  } else if (state.root) {
                      rootFound = true;
                  }
              }
              if (!rootFound) {
                  var firstStateId = Object.keys(states)[0];
                  states[firstStateId].root = true;
              }
          }
  
          var datasourcesByAliasId = {};
          var targetDevicesByAliasId = {};
          for (var widgetId in dashboard.configuration.widgets) {
              widget = dashboard.configuration.widgets[widgetId];
              widget.config.datasources.forEach(function (datasource) {
                 if (datasource.entityAliasId) {
                     var aliasId = datasource.entityAliasId;
                     var aliasDatasources = datasourcesByAliasId[aliasId];
                     if (!aliasDatasources) {
                         aliasDatasources = [];
                         datasourcesByAliasId[aliasId] = aliasDatasources;
                     }
                     aliasDatasources.push(datasource);
                 }
              });
              if (widget.config.targetDeviceAliasIds && widget.config.targetDeviceAliasIds.length) {
                  var aliasId = widget.config.targetDeviceAliasIds[0];
                  var targetDeviceAliasIdsList = targetDevicesByAliasId[aliasId];
                  if (!targetDeviceAliasIdsList) {
                      targetDeviceAliasIdsList = [];
                      targetDevicesByAliasId[aliasId] = targetDeviceAliasIdsList;
                  }
                  targetDeviceAliasIdsList.push(widget.config.targetDeviceAliasIds);
              }
          }
  
          dashboard.configuration = validateAndUpdateEntityAliases(dashboard.configuration, datasourcesByAliasId, targetDevicesByAliasId);
  
          if (angular.isUndefined(dashboard.configuration.timewindow)) {
              dashboard.configuration.timewindow = timeService.defaultTimewindow();
          }
          if (angular.isUndefined(dashboard.configuration.settings)) {
              dashboard.configuration.settings = {};
              dashboard.configuration.settings.stateControllerId = 'entity';
              dashboard.configuration.settings.showTitle = false;
              dashboard.configuration.settings.showDashboardsSelect = true;
              dashboard.configuration.settings.showEntitiesSelect = true;
              dashboard.configuration.settings.showDashboardTimewindow = true;
              dashboard.configuration.settings.showDashboardExport = true;
              dashboard.configuration.settings.toolbarAlwaysOpen = true;
          } else {
              if (angular.isUndefined(dashboard.configuration.settings.stateControllerId)) {
                  dashboard.configuration.settings.stateControllerId = 'entity';
              }
          }
          if (angular.isDefined(dashboard.configuration.gridSettings)) {
              var gridSettings = dashboard.configuration.gridSettings;
              if (angular.isDefined(gridSettings.showTitle)) {
                  dashboard.configuration.settings.showTitle = gridSettings.showTitle;
                  delete gridSettings.showTitle;
              }
              if (angular.isDefined(gridSettings.titleColor)) {
                  dashboard.configuration.settings.titleColor = gridSettings.titleColor;
                  delete gridSettings.titleColor;
              }
              if (angular.isDefined(gridSettings.showDevicesSelect)) {
                  dashboard.configuration.settings.showEntitiesSelect = gridSettings.showDevicesSelect;
                  delete gridSettings.showDevicesSelect;
              }
              if (angular.isDefined(gridSettings.showEntitiesSelect)) {
                  dashboard.configuration.settings.showEntitiesSelect = gridSettings.showEntitiesSelect;
                  delete gridSettings.showEntitiesSelect;
              }
              if (angular.isDefined(gridSettings.showDashboardTimewindow)) {
                  dashboard.configuration.settings.showDashboardTimewindow = gridSettings.showDashboardTimewindow;
                  delete gridSettings.showDashboardTimewindow;
              }
              if (angular.isDefined(gridSettings.showDashboardExport)) {
                  dashboard.configuration.settings.showDashboardExport = gridSettings.showDashboardExport;
                  delete gridSettings.showDashboardExport;
              }
              dashboard.configuration.states['default'].layouts['main'].gridSettings = gridSettings;
              delete dashboard.configuration.gridSettings;
          }
          return dashboard;
      }
  
      function getRootStateId(states) {
          for (var stateId in states) {
              var state = states[stateId];
              if (state.root) {
                  return stateId;
              }
          }
          return Object.keys(states)[0];
      }
  
      function createSingleWidgetDashboard(widget) {
          if (!widget.id) {
              widget.id = utils.guid();
          }
          var dashboard = {};
          dashboard = validateAndUpdateDashboard(dashboard);
          dashboard.configuration.widgets[widget.id] = widget;
          dashboard.configuration.states['default'].layouts['main'].widgets[widget.id] = {
              sizeX: widget.sizeX,
              sizeY: widget.sizeY,
              row: widget.row,
              col: widget.col,
          };
          return dashboard;
      }
  
      function createSingleEntityFilter(entityType, entityId) {
          return {
              type: types.aliasFilterType.singleEntity.value,
              singleEntity: { entityType: entityType, id: entityId },
              resolveMultiple: false
          };
      }
  
      function getStateLayoutsData(dashboard, targetState) {
          var dashboardConfiguration = dashboard.configuration;
          var states = dashboardConfiguration.states;
          var state = states[targetState];
          if (state) {
              var allWidgets = dashboardConfiguration.widgets;
              var result = {};
              for (var l in state.layouts) {
                  var layout = state.layouts[l];
                  if (layout) {
                      result[l] = {
                          widgets: [],
                          widgetLayouts: {},
                          gridSettings: {}
                      }
                      for (var id in layout.widgets) {
                          result[l].widgets.push(allWidgets[id]);
                      }
                      result[l].widgetLayouts = layout.widgets;
                      result[l].gridSettings = layout.gridSettings;
                  }
              }
              return result;
          } else {
              return null;
          }
      }
  
      function setLayouts(dashboard, targetState, newLayouts) {
          var dashboardConfiguration = dashboard.configuration;
          var states = dashboardConfiguration.states;
          var state = states[targetState];
          var addedCount = 0;
          var removedCount = 0;
          for (var l in state.layouts) {
              if (!newLayouts[l]) {
                  removedCount++;
              }
          }
          for (l in newLayouts) {
              if (!state.layouts[l]) {
                  addedCount++;
              }
          }
          state.layouts = newLayouts;
          var layoutsCount = Object.keys(state.layouts).length;
          var newColumns;
          if (addedCount) {
              for (l in state.layouts) {
                  newColumns = state.layouts[l].gridSettings.columns * (layoutsCount - addedCount) / layoutsCount;
                  state.layouts[l].gridSettings.columns = newColumns;
              }
          }
          if (removedCount) {
              for (l in state.layouts) {
                  newColumns = state.layouts[l].gridSettings.columns * (layoutsCount + removedCount) / layoutsCount;
                  state.layouts[l].gridSettings.columns = newColumns;
              }
          }
          removeUnusedWidgets(dashboard);
      }
  
      function updateLayoutSettings(layout, gridSettings) {
          var prevGridSettings = layout.gridSettings;
          var prevColumns = prevGridSettings ? prevGridSettings.columns : 24;
          var ratio = gridSettings.columns / prevColumns;
          layout.gridSettings = gridSettings;
          var maxRow = 0;
          for (var w in layout.widgets) {
              var widget = layout.widgets[w];
              maxRow = Math.max(maxRow, widget.row + widget.sizeY);
          }
          var newMaxRow = Math.round(maxRow * ratio);
          for (w in layout.widgets) {
              widget = layout.widgets[w];
              if (widget.row + widget.sizeY == maxRow) {
                  widget.row = Math.round(widget.row * ratio);
                  widget.sizeY = newMaxRow - widget.row;
              } else {
                  widget.row = Math.round(widget.row * ratio);
                  widget.sizeY = Math.round(widget.sizeY * ratio);
              }
              widget.sizeX = Math.round(widget.sizeX * ratio);
              widget.col = Math.round(widget.col * ratio);
              if (widget.col + widget.sizeX > gridSettings.columns) {
                  widget.sizeX = gridSettings.columns - widget.col;
              }
          }
      }
  
      function addWidgetToLayout(dashboard, targetState, targetLayout, widget, originalColumns, originalSize, row, column) {
          var dashboardConfiguration = dashboard.configuration;
          var states = dashboardConfiguration.states;
          var state = states[targetState];
          var layout = state.layouts[targetLayout];
          var layoutCount = Object.keys(state.layouts).length;
          if (!widget.id) {
              widget.id = utils.guid();
          }
          if (!dashboardConfiguration.widgets[widget.id]) {
              dashboardConfiguration.widgets[widget.id] = widget;
          }
          var widgetLayout = {
              sizeX: originalSize ? originalSize.sizeX : widget.sizeX,
              sizeY: originalSize ? originalSize.sizeY : widget.sizeY,
              mobileOrder: widget.config.mobileOrder,
              mobileHeight: widget.config.mobileHeight
          };
  
          if (angular.isUndefined(originalColumns)) {
              originalColumns = 24;
          }
  
          var gridSettings = layout.gridSettings;
          var columns = 24;
          if (gridSettings && gridSettings.columns) {
              columns = gridSettings.columns;
          }
  
          columns = columns * layoutCount;
  
          if (columns != originalColumns) {
              var ratio = columns / originalColumns;
              widgetLayout.sizeX *= ratio;
              widgetLayout.sizeY *= ratio;
          }
  
          if (row > -1 && column > - 1) {
              widgetLayout.row = row;
              widgetLayout.col = column;
          } else {
              row = 0;
              for (var w in layout.widgets) {
                  var existingLayout = layout.widgets[w];
                  var wRow = existingLayout.row ? existingLayout.row : 0;
                  var wSizeY = existingLayout.sizeY ? existingLayout.sizeY : 1;
                  var bottom = wRow + wSizeY;
                  row = Math.max(row, bottom);
              }
              widgetLayout.row = row;
              widgetLayout.col = 0;
          }
  
          layout.widgets[widget.id] = widgetLayout;
      }
  
      function removeWidgetFromLayout(dashboard, targetState, targetLayout, widgetId) {
          var dashboardConfiguration = dashboard.configuration;
          var states = dashboardConfiguration.states;
          var state = states[targetState];
          var layout = state.layouts[targetLayout];
          delete layout.widgets[widgetId];
          removeUnusedWidgets(dashboard);
      }
  
      function isSingleLayoutDashboard(dashboard) {
          var dashboardConfiguration = dashboard.configuration;
          var states = dashboardConfiguration.states;
          var stateKeys = Object.keys(states);
          if (stateKeys.length === 1) {
              var state = states[stateKeys[0]];
              var layouts = state.layouts;
              var layoutKeys = Object.keys(layouts);
              if (layoutKeys.length === 1) {
                  return {
                      state: stateKeys[0],
                      layout: layoutKeys[0]
                  }
              }
          }
          return null;
      }
  
      function removeUnusedWidgets(dashboard) {
          var dashboardConfiguration = dashboard.configuration;
          var states = dashboardConfiguration.states;
          var widgets = dashboardConfiguration.widgets;
          for (var widgetId in widgets) {
              var found = false;
              for (var s in states) {
                  var state = states[s];
                  for (var l in state.layouts) {
                      var layout = state.layouts[l];
                      if (layout.widgets[widgetId]) {
                          found = true;
                          break;
                      }
                  }
              }
              if (!found) {
                  delete dashboardConfiguration.widgets[widgetId];
              }
  
          }
      }
  
      function getWidgetsArray(dashboard) {
          var widgetsArray = [];
          var dashboardConfiguration = dashboard.configuration;
          var widgets = dashboardConfiguration.widgets;
          for (var widgetId in widgets) {
              var widget = widgets[widgetId];
              widgetsArray.push(widget);
          }
          return widgetsArray;
      }
  }
  