text: /**
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you 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.
   */
  
  var App = require('app');
  require('utils/configs/ha_config_initializer_class');
  require('utils/configs/hosts_based_initializer_mixin');
  
  /**
   * @typedef {topologyLocalDB} extendedTopologyLocalDB
   * @property {string[]} installedServices list of installed service names
   */
  
  /**
   * Setting for <code>rename</code>-initializer
   * Used for configs which should be renamed
   * Replace some part if their names with <code>namespaceId</code> (provided by user on the wizard's 1st step)
   *
   * @param {string} toReplace
   * @returns {{type: string, toReplace: string}}
   */
  function getRenameWithNamespaceConfig(toReplace) {
    return {
      type: 'rename',
      toReplace: toReplace
    };
  }
  
  /**
   * Settings for <code>namespace</code>-initializer
   * Used for configs with value equal to the <code>namespaceId</code> (provided by user on the wizard's 1st step)
   * Value may be customized with prefix and suffix
   *
   * @param {string} [prefix=''] substring added before namespace in the replace
   * @param {string} [suffix=''] substring added after namespace in the replace
   * @returns {{type: string, modifier: {prefix: (string), suffix: (string)}}}
   */
  function getNamespaceConfig (prefix, suffix) {
    prefix = prefix || '';
    suffix = suffix || '';
    return {
      type: 'namespace',
      modifier: {
        prefix: prefix,
        suffix: suffix
      }
    }
  }
  
  /**
   * Settings for <code>replace_namespace</code>
   * Used for configs with values that have to be modified with replacing some part of them
   * to the <code>namespaceId</code> (provided by user on the wizard's 1st step)
   *
   * @param {string} toReplace
   * @returns {{type: string, toReplace: *}}
   */
  function getReplaceNamespaceConfig(toReplace) {
    return {
      type: 'replace_namespace',
      toReplace: toReplace
    };
  }
  
  /**
   * Initializer for configs that are updated when NameNode HA-mode is activated
   *
   * @class {NnHaConfigInitializer}
   */
  App.NnHaConfigInitializer = App.HaConfigInitializerClass.create(App.HostsBasedInitializerMixin, {
  
    initializers: function () {
  
      return {
        'dfs.ha.namenodes.${dfs.nameservices}': getRenameWithNamespaceConfig('${dfs.nameservices}'),
        'dfs.namenode.rpc-address.${dfs.nameservices}.nn1': [
          this.getHostWithPortConfig('NAMENODE', true, '', '', 'nnRpcPort', true),
          getRenameWithNamespaceConfig('${dfs.nameservices}')
        ],
        'dfs.namenode.rpc-address.${dfs.nameservices}.nn2': [
          this.getHostWithPortConfig('NAMENODE', false, '', '', '8020', false),
          getRenameWithNamespaceConfig('${dfs.nameservices}')
        ],
        'dfs.namenode.http-address.${dfs.nameservices}.nn1': [
          this.getHostWithPortConfig('NAMENODE', true, '', '', 'nnHttpPort', true),
          getRenameWithNamespaceConfig('${dfs.nameservices}')
        ],
        'dfs.namenode.http-address.${dfs.nameservices}.nn2': [
          this.getHostWithPortConfig('NAMENODE', false, '', '', '50070', false),
          getRenameWithNamespaceConfig('${dfs.nameservices}')
        ],
        'dfs.namenode.https-address.${dfs.nameservices}.nn1': [
          this.getHostWithPortConfig('NAMENODE', true, '', '', 'nnHttpsPort', true),
          getRenameWithNamespaceConfig('${dfs.nameservices}')
        ],
        'dfs.namenode.https-address.${dfs.nameservices}.nn2': [
          this.getHostWithPortConfig('NAMENODE', false, '', '', '50470', false),
          getRenameWithNamespaceConfig('${dfs.nameservices}')
        ],
        'dfs.client.failover.proxy.provider.${dfs.nameservices}': getRenameWithNamespaceConfig('${dfs.nameservices}'),
        'dfs.nameservices': getNamespaceConfig(),
        'dfs.internal.nameservices': getNamespaceConfig(),
        'fs.defaultFS': getNamespaceConfig('hdfs://'),
        'dfs.namenode.shared.edits.dir': [
          this.getHostsWithPortConfig('JOURNALNODE', 'qjournal://', '/${dfs.nameservices}', ';', '8485', false),
          getReplaceNamespaceConfig('${dfs.nameservices}')
        ],
        'ha.zookeeper.quorum': this.getHostsWithPortConfig('ZOOKEEPER_SERVER', '', '', ',', 'zkClientPort', true)
      };
    }.property(),
  
    uniqueInitializers: {
      'hbase.rootdir': '_initHbaseRootDir',
      'hawq_dfs_url': '_initHawqDfsUrl',
      'instance.volumes': '_initInstanceVolumes',
      'instance.volumes.replacements': '_initInstanceVolumesReplacements',
      'dfs.journalnode.edits.dir': '_initDfsJnEditsDir'
    },
  
    initializerTypes: [
      {name: 'rename', method: '_initWithRename'},
      {name: 'namespace', method: '_initAsNamespace'},
      {name: 'replace_namespace', method: '_initWithNamespace'}
    ],
  
    /**
     * Initializer for configs that should be renamed
     * Some part of their names should be replaced with <code>namespaceId</code> (user input this value on the wizard's 1st step)
     * Affects both - name and displayName
     * <b>Important! It's not the same as <code>_updateInitializers</code>!</b>
     * Main diff - this initializer used for configs
     * with names that come with some "predicates" in their names. <code>_updateInitializers</code> is used to determine needed
     * config name that depends on other config values or someting else
     *
     * @param {configProperty} configProperty
     * @param {extendedTopologyLocalDB} localDB
     * @param {nnHaConfigDependencies} dependencies
     * @param {object} initializer
     * @returns {object}
     * @private
     * @method _initWithRename
     */
    _initWithRename: function (configProperty, localDB, dependencies, initializer) {
      var replaceWith = dependencies.namespaceId;
      var toReplace = initializer.toReplace;
      Em.assert('`dependencies.namespaceId` should be not empty string', !!replaceWith);
      var name = Em.getWithDefault(configProperty, 'name', '');
      var displayName = Em.getWithDefault(configProperty, 'displayName', '');
      name = name.replace(toReplace, replaceWith);
      displayName = displayName.replace(toReplace, replaceWith);
      Em.setProperties(configProperty, {
        name: name,
        displayName: displayName
      });
      return configProperty;
    },
  
    /**
     * Initializer for configs wih value equal to the <code>namespaceId</code> (user input this value on the wizard's 1st step)
     * Value may be customized with prefix and suffix (see <code>initializer.modifier</code>)
     * Value-examples: 'SOME_COOL_PREFIXmy_namespaceSOME_COOL_SUFFIX', 'my_namespace'
     *
     * @param {configProperty} configProperty
     * @param {extendedTopologyLocalDB} localDB
     * @param {nnHaConfigDependencies} dependencies
     * @param {object} initializer
     * @returns {object}
     * @private
     * @method _initAsNamespace
     */
    _initAsNamespace: function (configProperty, localDB, dependencies, initializer) {
      var value = dependencies.namespaceId;
      Em.assert('`dependencies.namespaceId` should be not empty string', !!value);
      value = initializer.modifier.prefix + value + initializer.modifier.suffix;
      Em.setProperties(configProperty, {
        value: value,
        recommendedValue: value
      });
      return configProperty;
    },
  
    /**
     * Initializer for configs with value that should be modified with replacing some substring
     * to the <code>namespaceId</code> (user input this value on the wizard's 1st step)
     *
     * @param {configProperty} configProperty
     * @param {extendedTopologyLocalDB} localDB
     * @param {nnHaConfigDependencies} dependencies
     * @param {object} initializer
     * @returns {object}
     * @private
     * @method _initWithNamespace
     */
    _initWithNamespace: function (configProperty, localDB, dependencies, initializer) {
      var replaceWith = dependencies.namespaceId;
      var toReplace = initializer.toReplace;
      Em.assert('`dependencies.namespaceId` should be not empty string', !!replaceWith);
      var value = Em.get(configProperty, 'value').replace(toReplace, replaceWith);
      var recommendedValue = Em.get(configProperty, 'recommendedValue').replace(toReplace, replaceWith);
      Em.setProperties(configProperty, {
        value: value,
        recommendedValue: recommendedValue
      });
      return configProperty;
    },
  
    /**
     * Unique initializer for <code>hbase.rootdir</code>
     *
     * @param {configProperty} configProperty
     * @param {extendedTopologyLocalDB} localDB
     * @param {nnHaConfigDependencies} dependencies
     * @param {object} initializer
     * @method _initHbaseRootDir
     * @return {object}
     * @private
     */
    _initHbaseRootDir: function (configProperty, localDB, dependencies, initializer) {
      var fileName = Em.get(configProperty, 'filename');
      var args = [].slice.call(arguments);
      if ('hbase-site' === fileName) {
        return this._initHbaseRootDirForHbase.apply(this, args);
      }
      if('ams-hbase-site' === fileName) {
        return this._initHbaseRootDirForAMS.apply(this, args);
      }
      return configProperty;
    },
  
    /**
     * Unique initializer for <code>hbase.rootdir</code> (HBASE-service)
     *
     * @param {configProperty} configProperty
     * @param {extendedTopologyLocalDB} localDB
     * @param {nnHaConfigDependencies} dependencies
     * @param {object} initializer
     * @method _initHbaseRootDirForHbase
     * @return {object}
     * @private
     */
    _initHbaseRootDirForHbase: function (configProperty, localDB, dependencies, initializer) {
      if (localDB.installedServices.contains('HBASE')) {
        var value = dependencies.serverConfigs.findProperty('type', 'hbase-site').properties['hbase.rootdir'].replace(/\/\/[^\/]*/, '//' + dependencies.namespaceId);
        Em.setProperties(configProperty, {
          value: value,
          recommendedValue: value
        });
      }
      return configProperty;
    },
  
    /**
     * Unique initializer for <code>hbase.rootdir</code> (Ambari Metrics-service)
     *
     * @param {configProperty} configProperty
     * @param {extendedTopologyLocalDB} localDB
     * @param {nnHaConfigDependencies} dependencies
     * @param {object} initializer
     * @method _initHbaseRootDirForAMS
     * @return {object}
     * @private
     */
    _initHbaseRootDirForAMS: function (configProperty, localDB, dependencies, initializer) {
      if (localDB.installedServices.contains('AMBARI_METRICS')) {
        var value = dependencies.serverConfigs.findProperty('type', 'ams-hbase-site').properties['hbase.rootdir'];
        var currentNameNodeHost = localDB.masterComponentHosts.filterProperty('component', 'NAMENODE').findProperty('isInstalled', true).hostName;
        if(value.contains("hdfs://" + currentNameNodeHost)){
          value = value.replace(/\/\/[^\/]*/, '//' + dependencies.namespaceId);
          configProperty.isVisible = true;
        }
        Em.setProperties(configProperty, {
          value: value,
          recommendedValue: value
        });
      }
      return configProperty;
    },
  
    /**
     * Unique initializer for <code>hawq_dfs_url</code> (Hawq service)
     *
     * @param {configProperty} configProperty
     * @param {extendedTopologyLocalDB} localDB
     * @param {nnHaConfigDependencies} dependencies
     * @param {object} initializer
     * @method _initHawqDfsUrl
     * @return {object}
     * @private
     */
    _initHawqDfsUrl: function (configProperty, localDB, dependencies, initializer) {
      if (localDB.installedServices.contains('HAWQ')) {
        var value = dependencies.serverConfigs.findProperty('type', 'hawq-site').properties['hawq_dfs_url'].replace(/(^.*:[0-9]+)(?=\/)/, dependencies.namespaceId);
        Em.setProperties(configProperty, {
          value: value,
          recommendedValue: value
        });
      }
      return configProperty;
    },
  
    /**
     * Unique initializer for <code>instance.volumes</code>
     *
     * @param {configProperty} configProperty
     * @param {extendedTopologyLocalDB} localDB
     * @param {nnHaConfigDependencies} dependencies
     * @param {object} initializer
     * @method _initInstanceVolumes
     * @return {object}
     * @private
     */
    _initInstanceVolumes: function (configProperty, localDB, dependencies, initializer) {
      if (localDB.installedServices.contains('ACCUMULO')) {
        var oldValue = dependencies.serverConfigs.findProperty('type', 'accumulo-site').properties['instance.volumes'];
        var value = oldValue.replace(/\/\/[^\/]*/, '//' + dependencies.namespaceId);
        Em.setProperties(configProperty, {
          value: value,
          recommendedValue: value
        });
      }
      return configProperty;
    },
  
    /**
     * Unique initializer for <code>instance.volumes.replacements</code>
     *
     * @param {configProperty} configProperty
     * @param {extendedTopologyLocalDB} localDB
     * @param {nnHaConfigDependencies} dependencies
     * @param {object} initializer
     * @method _initInstanceVolumesReplacements
     * @return {object}
     * @private
     */
    _initInstanceVolumesReplacements: function (configProperty, localDB, dependencies, initializer) {
      if (localDB.installedServices.contains('ACCUMULO')) {
        var oldValue = dependencies.serverConfigs.findProperty('type', 'accumulo-site').properties['instance.volumes'];
        var value = oldValue.replace(/\/\/[^\/]*/, '//' + dependencies.namespaceId);
        var replacements = oldValue + " " + value;
        Em.setProperties(configProperty, {
          value: replacements,
          recommendedValue: replacements
        });
      }
      return configProperty;
    },
  
    /**
     * Unique initializer for <code>dfs.journalnode.edits.dir</code>
     * Used only for Windows Stacks
     *
     * @param {configProperty} configProperty
     * @param {extendedTopologyLocalDB} localDB
     * @param {nnHaConfigDependencies} dependencies
     * @param {object} initializer
     * @method _initDfsJnEditsDir
     * @return {object}
     * @private
     */
    _initDfsJnEditsDir: function (configProperty, localDB, dependencies, initializer) {
      if (App.get('isHadoopWindowsStack') && localDB.installedServices.contains('HDFS')) {
        var value = dependencies.serverConfigs.findProperty('type', 'hdfs-site').properties['dfs.journalnode.edits.dir'];
        Em.setProperties(configProperty, {
          value: value,
          recommendedValue: value
        });
      }
      return configProperty;
    }
  
  });
  