text: /*
   * Copyright © 2016-2018 The Thingsboard 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.
   */
  import 'angular-material-data-table/dist/md-data-table.min.css';
  import './attribute-table.scss';
  
  /* eslint-disable import/no-unresolved, import/default */
  
  import attributeTableTemplate from './attribute-table.tpl.html';
  import addAttributeDialogTemplate from './add-attribute-dialog.tpl.html';
  import addWidgetToDashboardDialogTemplate from './add-widget-to-dashboard-dialog.tpl.html';
  import editAttributeValueTemplate from './edit-attribute-value.tpl.html';
  
  /* eslint-enable import/no-unresolved, import/default */
  
  import EditAttributeValueController from './edit-attribute-value.controller';
  import AliasController from '../../api/alias-controller';
  
  /*@ngInject*/
  export default function AttributeTableDirective($compile, $templateCache, $rootScope, $q, $mdEditDialog, $mdDialog,
                                                  $mdUtil, $document, $translate, $filter, $timeout, utils, types, dashboardUtils,
                                                  entityService, attributeService, widgetService) {
  
      var linker = function (scope, element, attrs) {
  
          var template = $templateCache.get(attributeTableTemplate);
  
          element.html(template);
  
          var getAttributeScopeByValue = function(attributeScopeValue) {
              if (scope.types.latestTelemetry.value === attributeScopeValue) {
                  return scope.types.latestTelemetry;
              }
              for (var attrScope in scope.attributeScopes) {
                  if (scope.attributeScopes[attrScope].value === attributeScopeValue) {
                      return scope.attributeScopes[attrScope];
                  }
              }
          }
  
          scope.types = types;
  
          scope.entityType = attrs.entityType;
  
          if (scope.entityType === types.entityType.device || scope.entityType === types.entityType.entityView) {
              scope.attributeScopes = types.attributesScope;
              scope.attributeScopeSelectionReadonly = false;
          } else {
              scope.attributeScopes = {};
              scope.attributeScopes.server = types.attributesScope.server;
              scope.attributeScopeSelectionReadonly = true;
          }
  
          scope.attributeScope = getAttributeScopeByValue(attrs.defaultAttributeScope);
  
          if (scope.entityType != types.entityType.device) {
              if (scope.attributeScope != types.latestTelemetry) {
                  scope.attributeScope = scope.attributeScopes.server;
              }
          }
  
          scope.attributes = {
              count: 0,
              data: []
          };
  
          scope.selectedAttributes = [];
          scope.mode = 'default'; // 'widget'
          scope.subscriptionId = null;
  
          scope.query = {
              order: 'key',
              limit: 5,
              page: 1,
              search: null
          };
  
          scope.$watch("entityId", function(newVal) {
              if (newVal) {
                  scope.resetFilter();
                  scope.getEntityAttributes(false, true);
              }
          });
  
          scope.$watch("attributeScope", function(newVal, prevVal) {
              if (newVal && !angular.equals(newVal, prevVal)) {
                  scope.mode = 'default';
                  scope.query.search = null;
                  scope.selectedAttributes = [];
                  scope.getEntityAttributes(false, true);
              }
          });
  
          scope.resetFilter = function() {
              scope.mode = 'default';
              scope.query.search = null;
              scope.selectedAttributes = [];
              scope.attributeScope = getAttributeScopeByValue(attrs.defaultAttributeScope);
          }
  
          scope.enterFilterMode = function(event) {
              let $button = angular.element(event.currentTarget);
              let $toolbarsContainer = $button.closest('.toolbarsContainer');
  
              scope.query.search = '';
  
              $timeout(()=>{
                  $toolbarsContainer.find('.searchInput').focus();
              })
          }
  
          scope.exitFilterMode = function() {
              scope.query.search = null;
              scope.getEntityAttributes();
          }
  
          scope.$watch("query.search", function(newVal, prevVal) {
              if (!angular.equals(newVal, prevVal) && scope.query.search != null) {
                  scope.getEntityAttributes();
              }
          });
  
          function success(attributes, update, apply) {
              scope.attributes = attributes;
              if (!update) {
                  scope.selectedAttributes = [];
              }
              if (apply) {
                  scope.$digest();
              }
          }
  
          scope.onReorder = function() {
              scope.getEntityAttributes(false, false);
          }
  
          scope.onPaginate = function() {
              scope.getEntityAttributes(false, false);
          }
  
          scope.getEntityAttributes = function(forceUpdate, reset) {
              if (scope.attributesDeferred) {
                  scope.attributesDeferred.resolve();
              }
              if (scope.entityId && scope.entityType && scope.attributeScope) {
                  if (reset) {
                      scope.attributes = {
                          count: 0,
                          data: []
                      };
                  }
                  scope.checkSubscription();
                  scope.attributesDeferred = attributeService.getEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value,
                      scope.query, function(attributes, update, apply) {
                          success(attributes, update || forceUpdate, apply);
                      }
                  );
              } else {
                  var deferred = $q.defer();
                  scope.attributesDeferred = deferred;
                  success({
                      count: 0,
                      data: []
                  });
                  deferred.resolve();
              }
          }
  
          scope.checkSubscription = function() {
              var newSubscriptionId = null;
              if (scope.entityId && scope.entityType && scope.attributeScope.clientSide && scope.mode != 'widget') {
                  newSubscriptionId = attributeService.subscribeForEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value);
              }
              if (scope.subscriptionId && scope.subscriptionId != newSubscriptionId) {
                  attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
              }
              scope.subscriptionId = newSubscriptionId;
          }
  
          scope.$on('$destroy', function() {
              if (scope.subscriptionId) {
                  attributeService.unsubscribeForEntityAttributes(scope.subscriptionId);
              }
          });
  
          scope.editAttribute = function($event, attribute) {
              if (!scope.attributeScope.clientSide) {
                  $event.stopPropagation();
                  $mdEditDialog.show({
                      controller: EditAttributeValueController,
                      templateUrl: editAttributeValueTemplate,
                      locals: {attributeValue: attribute.value,
                               save: function (model) {
                                  var updatedAttribute = angular.copy(attribute);
                                  updatedAttribute.value = model.value;
                                  attributeService.saveEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, [updatedAttribute]).then(
                                      function success() {
                                          scope.getEntityAttributes();
                                      }
                                  );
                              }},
                      targetEvent: $event
                  });
              }
          }
  
          scope.addAttribute = function($event) {
              if (!scope.attributeScope.clientSide) {
                  $event.stopPropagation();
                  $mdDialog.show({
                      controller: 'AddAttributeDialogController',
                      controllerAs: 'vm',
                      templateUrl: addAttributeDialogTemplate,
                      parent: angular.element($document[0].body),
                      locals: {entityType: scope.entityType, entityId: scope.entityId, attributeScope: scope.attributeScope.value},
                      fullscreen: true,
                      targetEvent: $event
                  }).then(function () {
                      scope.getEntityAttributes();
                  });
              }
          }
  
          scope.deleteAttributes = function($event) {
              if (!scope.attributeScope.clientSide) {
                  $event.stopPropagation();
                  var confirm = $mdDialog.confirm()
                      .targetEvent($event)
                      .title($translate.instant('attribute.delete-attributes-title', {count: scope.selectedAttributes.length}, 'messageformat'))
                      .htmlContent($translate.instant('attribute.delete-attributes-text'))
                      .ariaLabel($translate.instant('attribute.delete-attributes'))
                      .cancel($translate.instant('action.no'))
                      .ok($translate.instant('action.yes'));
                  $mdDialog.show(confirm).then(function () {
                          attributeService.deleteEntityAttributes(scope.entityType, scope.entityId, scope.attributeScope.value, scope.selectedAttributes).then(
                              function success() {
                                  scope.selectedAttributes = [];
                                  scope.getEntityAttributes();
                              }
                          )
                  });
              }
          }
  
          scope.nextWidget = function() {
              $mdUtil.nextTick(function () {
                  if (scope.widgetsCarousel.index < scope.widgetsList.length - 1) {
                      scope.widgetsCarousel.index++;
                  }
              });
          }
  
          scope.prevWidget = function() {
              $mdUtil.nextTick(function () {
                  if (scope.widgetsCarousel.index > 0) {
                      scope.widgetsCarousel.index--;
                  }
              });
          }
  
          scope.enterWidgetMode = function() {
  
              if (scope.widgetsIndexWatch) {
                  scope.widgetsIndexWatch();
                  scope.widgetsIndexWatch = null;
              }
  
              if (scope.widgetsBundleWatch) {
                  scope.widgetsBundleWatch();
                  scope.widgetsBundleWatch = null;
              }
  
              scope.mode = 'widget';
              scope.checkSubscription();
              scope.widgetsList = [];
              scope.widgetsListCache = [];
              scope.widgetsLoaded = false;
              scope.widgetsCarousel = {
                  index: 0
              }
              scope.widgetsBundle = null;
              scope.firstBundle = true;
              scope.selectedWidgetsBundleAlias = types.systemBundleAlias.cards;
  
              var entityAlias = {
                  id: utils.guid(),
                  alias: scope.entityName,
                  filter: dashboardUtils.createSingleEntityFilter(scope.entityType, scope.entityId)
              };
              var entitiAliases = {};
              entitiAliases[entityAlias.id] = entityAlias;
  
              var stateController = {
                  getStateParams: function() {
                      return {};
                  }
              };
              scope.aliasController = new AliasController(scope, $q, $filter, utils,
                  types, entityService, stateController, entitiAliases);
  
              var dataKeyType = scope.attributeScope === types.latestTelemetry ?
                  types.dataKeyType.timeseries : types.dataKeyType.attribute;
  
              var datasource = {
                  type: types.datasourceType.entity,
                  entityAliasId: entityAlias.id,
                  dataKeys: []
              }
              var i = 0;
              for (var attr =0; attr < scope.selectedAttributes.length;attr++) {
                  var attribute = scope.selectedAttributes[attr];
                  var dataKey = {
                      name: attribute.key,
                      label: attribute.key,
                      type: dataKeyType,
                      color: utils.getMaterialColor(i),
                      settings: {},
                      _hash: Math.random()
                  }
                  datasource.dataKeys.push(dataKey);
                  i++;
              }
  
              scope.widgetsIndexWatch = scope.$watch('widgetsCarousel.index', function(newVal, prevVal) {
                  if (scope.mode === 'widget' && (newVal != prevVal)) {
                      var index = scope.widgetsCarousel.index;
                      for (var i = 0; i < scope.widgetsList.length; i++) {
                          scope.widgetsList[i].splice(0, scope.widgetsList[i].length);
                          if (i === index) {
                              scope.widgetsList[i].push(scope.widgetsListCache[i][0]);
                          }
                      }
                  }
              });
  
              scope.widgetsBundleWatch = scope.$watch('widgetsBundle', function(newVal, prevVal) {
                  if (scope.mode === 'widget' && (scope.firstBundle === true || newVal != prevVal)) {
                      scope.widgetsList = [];
                      scope.widgetsListCache = [];
                      scope.widgetsCarousel.index = 0;
                      scope.firstBundle = false;
                      if (scope.widgetsBundle) {
                          scope.widgetsLoaded = false;
                          var bundleAlias = scope.widgetsBundle.alias;
                          var isSystem = scope.widgetsBundle.tenantId.id === types.id.nullUid;
                          widgetService.getBundleWidgetTypes(scope.widgetsBundle.alias, isSystem).then(
                              function success(widgetTypes) {
  
                                  widgetTypes = $filter('orderBy')(widgetTypes, ['-descriptor.type','-createdTime']);
  
                                  for (var i = 0; i < widgetTypes.length; i++) {
                                      var widgetType = widgetTypes[i];
                                      var widgetInfo = widgetService.toWidgetInfo(widgetType);
                                      if (widgetInfo.type !== types.widgetType.static.value) {
                                          var sizeX = widgetInfo.sizeX * 2;
                                          var sizeY = widgetInfo.sizeY * 2;
                                          var col = Math.floor(Math.max(0, (20 - sizeX) / 2));
                                          var widget = {
                                              isSystemType: isSystem,
                                              bundleAlias: bundleAlias,
                                              typeAlias: widgetInfo.alias,
                                              type: widgetInfo.type,
                                              title: widgetInfo.widgetName,
                                              sizeX: sizeX,
                                              sizeY: sizeY,
                                              row: 0,
                                              col: col,
                                              config: angular.fromJson(widgetInfo.defaultConfig)
                                          };
  
                                          widget.config.title = widgetInfo.widgetName;
                                          widget.config.datasources = [datasource];
                                          var length;
                                          if (scope.attributeScope === types.latestTelemetry && widgetInfo.type !== types.widgetType.rpc.value) {
                                              length = scope.widgetsListCache.push([widget]);
                                              scope.widgetsList.push(length === 1 ? [widget] : []);
                                          } else if (widgetInfo.type === types.widgetType.latest.value) {
                                              length = scope.widgetsListCache.push([widget]);
                                              scope.widgetsList.push(length === 1 ? [widget] : []);
                                          }
                                      }
                                  }
                                  scope.widgetsLoaded = true;
                              }
                          );
                      }
                  }
              });
          }
  
          scope.exitWidgetMode = function() {
              if (scope.widgetsBundleWatch) {
                  scope.widgetsBundleWatch();
                  scope.widgetsBundleWatch = null;
              }
              if (scope.widgetsIndexWatch) {
                  scope.widgetsIndexWatch();
                  scope.widgetsIndexWatch = null;
              }
              scope.selectedWidgetsBundleAlias = null;
              scope.mode = 'default';
              scope.getEntityAttributes(true);
          }
  
          scope.addWidgetToDashboard = function($event) {
              if (scope.mode === 'widget' && scope.widgetsListCache.length > 0) {
                  var widget = scope.widgetsListCache[scope.widgetsCarousel.index][0];
                  $event.stopPropagation();
                  $mdDialog.show({
                      controller: 'AddWidgetToDashboardDialogController',
                      controllerAs: 'vm',
                      templateUrl: addWidgetToDashboardDialogTemplate,
                      parent: angular.element($document[0].body),
                      locals: {entityId: scope.entityId, entityType: scope.entityType, entityName: scope.entityName, widget: angular.copy(widget)},
                      fullscreen: true,
                      targetEvent: $event
                  }).then(function () {
  
                  });
              }
          }
  
          scope.loading = function() {
              return $rootScope.loading;
          }
  
          $compile(element.contents())(scope);
      }
  
      return {
          restrict: "E",
          link: linker,
          scope: {
              entityId: '=',
              entityName: '=',
              disableAttributeScopeSelection: '@?'
          }
      };
  }
  