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.
   */
  
  // import _ from 'lodash';
  import { EmptyBean, Bean } from './Beans';
  
  export default ['JavaTypes', 'igniteClusterPlatformDefaults', 'igniteCachePlatformDefaults', (JavaTypes, clusterDflts, cacheDflts) => {
      class PlatformGenerator {
          static igniteConfigurationBean(cluster) {
              return new Bean('Apache.Ignite.Core.IgniteConfiguration', 'cfg', cluster, clusterDflts);
          }
  
          static cacheConfigurationBean(cache) {
              return new Bean('Apache.Ignite.Core.Cache.Configuration.CacheConfiguration', 'ccfg', cache, cacheDflts);
          }
  
          /**
           * Function to generate ignite configuration.
           *
           * @param {Object} cluster Cluster to process.
           * @return {String} Generated ignite configuration.
           */
          static igniteConfiguration(cluster) {
              const cfg = this.igniteConfigurationBean(cluster);
  
              this.clusterAtomics(cluster.atomics, cfg);
  
              return cfg;
          }
  
          // Generate general section.
          static clusterGeneral(cluster, cfg = this.igniteConfigurationBean(cluster)) {
              cfg.stringProperty('name', 'GridName')
                  .stringProperty('localHost', 'Localhost');
  
              if (_.isNil(cluster.discovery))
                  return cfg;
  
              const discovery = new Bean('Apache.Ignite.Core.Discovery.Tcp.TcpDiscoverySpi', 'discovery',
                  cluster.discovery, clusterDflts.discovery);
  
              let ipFinder;
  
              switch (discovery.valueOf('kind')) {
                  case 'Vm':
                      ipFinder = new Bean('Apache.Ignite.Core.Discovery.Tcp.Static.TcpDiscoveryStaticIpFinder',
                          'ipFinder', cluster.discovery.Vm, clusterDflts.discovery.Vm);
  
                      ipFinder.collectionProperty('addrs', 'addresses', cluster.discovery.Vm.addresses, 'ICollection');
  
                      break;
                  case 'Multicast':
                      ipFinder = new Bean('Apache.Ignite.Core.Discovery.Tcp.Multicast.TcpDiscoveryMulticastIpFinder',
                          'ipFinder', cluster.discovery.Multicast, clusterDflts.discovery.Multicast);
  
                      ipFinder.stringProperty('MulticastGroup')
                          .intProperty('multicastPort', 'MulticastPort')
                          .intProperty('responseWaitTime', 'ResponseTimeout')
                          .intProperty('addressRequestAttempts', 'AddressRequestAttempts')
                          .stringProperty('localAddress', 'LocalAddress')
                          .collectionProperty('addrs', 'Endpoints', cluster.discovery.Multicast.addresses, 'ICollection');
  
                      break;
                  default:
              }
  
              if (ipFinder)
                  discovery.beanProperty('IpFinder', ipFinder);
  
              cfg.beanProperty('DiscoverySpi', discovery);
  
  
              return cfg;
          }
  
          static clusterAtomics(atomics, cfg = this.igniteConfigurationBean()) {
              const acfg = new Bean('Apache.Ignite.Core.DataStructures.Configuration.AtomicConfiguration', 'atomicCfg',
                  atomics, clusterDflts.atomics);
  
              acfg.enumProperty('cacheMode', 'CacheMode')
                  .intProperty('atomicSequenceReserveSize', 'AtomicSequenceReserveSize');
  
              if (acfg.valueOf('cacheMode') === 'PARTITIONED')
                  acfg.intProperty('backups', 'Backups');
  
              if (acfg.isEmpty())
                  return cfg;
  
              cfg.beanProperty('AtomicConfiguration', acfg);
  
              return cfg;
          }
  
          // Generate binary group.
          static clusterBinary(binary, cfg = this.igniteConfigurationBean()) {
              const binaryCfg = new Bean('Apache.Ignite.Core.Binary.BinaryConfiguration', 'binaryCfg',
                  binary, clusterDflts.binary);
  
              binaryCfg.emptyBeanProperty('idMapper', 'DefaultIdMapper')
                  .emptyBeanProperty('nameMapper', 'DefaultNameMapper')
                  .emptyBeanProperty('serializer', 'DefaultSerializer');
  
              // const typeCfgs = [];
              //
              // _.forEach(binary.typeConfigurations, (type) => {
              //     const typeCfg = new MethodBean('Apache.Ignite.Core.Binary.BinaryTypeConfiguration',
              //         JavaTypes.toJavaName('binaryType', type.typeName), type, clusterDflts.binary.typeConfigurations);
              //
              //     typeCfg.stringProperty('typeName', 'TypeName')
              //         .emptyBeanProperty('idMapper', 'IdMapper')
              //         .emptyBeanProperty('nameMapper', 'NameMapper')
              //         .emptyBeanProperty('serializer', 'Serializer')
              //         .intProperty('enum', 'IsEnum');
              //
              //     if (typeCfg.nonEmpty())
              //         typeCfgs.push(typeCfg);
              // });
              //
              // binaryCfg.collectionProperty('types', 'TypeConfigurations', typeCfgs, 'ICollection',
              //     'Apache.Ignite.Core.Binary.BinaryTypeConfiguration');
              //
              // binaryCfg.boolProperty('compactFooter', 'CompactFooter');
              //
              // if (binaryCfg.isEmpty())
              //     return cfg;
              //
              // cfg.beanProperty('binaryConfiguration', binaryCfg);
  
              return cfg;
          }
  
          // Generate communication group.
          static clusterCommunication(cluster, cfg = this.igniteConfigurationBean(cluster)) {
              const commSpi = new Bean('Apache.Ignite.Core.Communication.Tcp.TcpCommunicationSpi', 'communicationSpi',
                  cluster.communication, clusterDflts.communication);
  
              commSpi.emptyBeanProperty('listener')
                  .stringProperty('localAddress')
                  .intProperty('localPort')
                  .intProperty('localPortRange')
                  // .intProperty('sharedMemoryPort')
                  .intProperty('directBuffer')
                  .intProperty('directSendBuffer')
                  .intProperty('idleConnectionTimeout')
                  .intProperty('connectTimeout')
                  .intProperty('maxConnectTimeout')
                  .intProperty('reconnectCount')
                  .intProperty('socketSendBuffer')
                  .intProperty('socketReceiveBuffer')
                  .intProperty('messageQueueLimit')
                  .intProperty('slowClientQueueLimit')
                  .intProperty('tcpNoDelay')
                  .intProperty('ackSendThreshold')
                  .intProperty('unacknowledgedMessagesBufferSize')
                  // .intProperty('socketWriteTimeout')
                  .intProperty('selectorsCount');
              // .emptyBeanProperty('addressResolver');
  
              if (commSpi.nonEmpty())
                  cfg.beanProperty('CommunicationSpi', commSpi);
  
              cfg.intProperty('networkTimeout', 'NetworkTimeout')
                  .intProperty('networkSendRetryDelay')
                  .intProperty('networkSendRetryCount');
              // .intProperty('discoveryStartupDelay');
  
              return cfg;
          }
  
          // Generate discovery group.
          static clusterDiscovery(discovery, cfg = this.igniteConfigurationBean()) {
              if (discovery) {
                  let discoveryCfg = cfg.findProperty('discovery');
  
                  if (_.isNil(discoveryCfg)) {
                      discoveryCfg = new Bean('Apache.Ignite.Core.Discovery.Tcp.TcpDiscoverySpi', 'discovery',
                          discovery, clusterDflts.discovery);
                  }
  
                  discoveryCfg.stringProperty('localAddress')
                      .intProperty('localPort')
                      .intProperty('localPortRange')
                      .intProperty('socketTimeout')
                      .intProperty('ackTimeout')
                      .intProperty('maxAckTimeout')
                      .intProperty('networkTimeout')
                      .intProperty('joinTimeout')
                      .intProperty('threadPriority')
                      .intProperty('heartbeatFrequency')
                      .intProperty('maxMissedHeartbeats')
                      .intProperty('maxMissedClientHeartbeats')
                      .intProperty('topHistorySize')
                      .intProperty('reconnectCount')
                      .intProperty('statisticsPrintFrequency')
                      .intProperty('ipFinderCleanFrequency')
                      .intProperty('forceServerMode')
                      .intProperty('clientReconnectDisabled');
  
                  if (discoveryCfg.nonEmpty())
                      cfg.beanProperty('discoverySpi', discoveryCfg);
              }
  
              return cfg;
          }
  
          // Generate events group.
          static clusterEvents(cluster, cfg = this.igniteConfigurationBean(cluster)) {
              if (_.nonEmpty(cluster.includeEventTypes))
                  cfg.eventTypes('events', 'includeEventTypes', cluster.includeEventTypes);
  
              return cfg;
          }
  
          // Generate metrics group.
          static clusterMetrics(cluster, cfg = this.igniteConfigurationBean(cluster)) {
              cfg.intProperty('metricsExpireTime')
                  .intProperty('metricsHistorySize')
                  .intProperty('metricsLogFrequency')
                  .intProperty('metricsUpdateFrequency');
  
              return cfg;
          }
  
          // Generate transactions group.
          static clusterTransactions(transactionConfiguration, cfg = this.igniteConfigurationBean()) {
              const bean = new Bean('Apache.Ignite.Core.Transactions.TransactionConfiguration', 'TransactionConfiguration',
                  transactionConfiguration, clusterDflts.transactionConfiguration);
  
              bean.enumProperty('defaultTxConcurrency', 'DefaultTransactionConcurrency')
                  .enumProperty('defaultTxIsolation', 'DefaultTransactionIsolation')
                  .intProperty('defaultTxTimeout', 'DefaultTimeout')
                  .intProperty('pessimisticTxLogLinger', 'PessimisticTransactionLogLinger')
                  .intProperty('pessimisticTxLogSize', 'PessimisticTransactionLogSize');
  
              if (bean.nonEmpty())
                  cfg.beanProperty('transactionConfiguration', bean);
  
              return cfg;
          }
  
          // Generate user attributes group.
          static clusterUserAttributes(cluster, cfg = this.igniteConfigurationBean(cluster)) {
              cfg.mapProperty('attributes', 'attributes', 'UserAttributes');
  
              return cfg;
          }
  
          static clusterCaches(cluster, caches, igfss, isSrvCfg, cfg = this.igniteConfigurationBean(cluster)) {
              // const cfg = this.clusterGeneral(cluster, cfg);
              //
              // if (_.nonEmpty(caches)) {
              //     const ccfgs = _.map(caches, (cache) => this.cacheConfiguration(cache));
              //
              //     cfg.collectionProperty('', '', ccfgs, );
              // }
  
              return this.clusterGeneral(cluster, cfg);
          }
  
          // Generate cache general group.
          static cacheGeneral(cache, ccfg = this.cacheConfigurationBean(cache)) {
              ccfg.stringProperty('name')
                  .enumProperty('cacheMode')
                  .enumProperty('atomicityMode');
  
              if (ccfg.valueOf('cacheMode') === 'PARTITIONED' && ccfg.valueOf('backups')) {
                  ccfg.intProperty('backups')
                      .intProperty('readFromBackup');
              }
  
              ccfg.intProperty('copyOnRead');
  
              if (ccfg.valueOf('cacheMode') === 'PARTITIONED' && ccfg.valueOf('atomicityMode') === 'TRANSACTIONAL')
                  ccfg.intProperty('invalidate');
  
              return ccfg;
          }
  
          // Generate cache memory group.
          static cacheMemory(cache, available, ccfg = this.cacheConfigurationBean(cache)) {
              ccfg.enumProperty('memoryMode');
  
              if (ccfg.valueOf('memoryMode') !== 'OFFHEAP_VALUES')
                  ccfg.intProperty('offHeapMaxMemory');
  
              // this._evictionPolicy(ccfg, available, false, cache.evictionPolicy, cacheDflts.evictionPolicy);
  
              ccfg.intProperty('startSize')
                  .boolProperty('swapEnabled', 'EnableSwap');
  
              return ccfg;
          }
  
          // Generate cache queries & Indexing group.
          static cacheQuery(cache, domains, ccfg = this.cacheConfigurationBean(cache)) {
              ccfg.intProperty('sqlOnheapRowCacheSize')
                  .intProperty('longQueryWarningTimeout');
  
              return ccfg;
          }
  
          // Generate cache store group.
          static cacheStore(cache, domains, ccfg = this.cacheConfigurationBean(cache)) {
              const kind = _.get(cache, 'cacheStoreFactory.kind');
  
              if (kind && cache.cacheStoreFactory[kind]) {
                  let bean = null;
  
                  const storeFactory = cache.cacheStoreFactory[kind];
  
                  switch (kind) {
                      case 'CacheJdbcPojoStoreFactory':
                          bean = new Bean('org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory', 'cacheStoreFactory',
                              storeFactory);
  
                          const id = bean.valueOf('dataSourceBean');
  
                          bean.dataSource(id, 'dataSourceBean', this.dataSourceBean(id, storeFactory.dialect))
                              .beanProperty('dialect', new EmptyBean(this.dialectClsName(storeFactory.dialect)));
  
                          const setType = (typeBean, propName) => {
                              if (JavaTypes.nonBuiltInClass(typeBean.valueOf(propName)))
                                  typeBean.stringProperty(propName);
                              else
                                  typeBean.classProperty(propName);
                          };
  
                          const types = _.reduce(domains, (acc, domain) => {
                              if (_.isNil(domain.databaseTable))
                                  return acc;
  
                              const typeBean = new Bean('org.apache.ignite.cache.store.jdbc.JdbcType', 'type',
                                  _.merge({}, domain, {cacheName: cache.name}))
                                  .stringProperty('cacheName');
  
                              setType(typeBean, 'keyType');
                              setType(typeBean, 'valueType');
  
                              this.domainStore(domain, typeBean);
  
                              acc.push(typeBean);
  
                              return acc;
                          }, []);
  
                          bean.arrayProperty('types', 'types', types, 'org.apache.ignite.cache.store.jdbc.JdbcType');
  
                          break;
                      case 'CacheJdbcBlobStoreFactory':
                          bean = new Bean('org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactory', 'cacheStoreFactory',
                              storeFactory);
  
                          if (bean.valueOf('connectVia') === 'DataSource')
                              bean.dataSource(bean.valueOf('dataSourceBean'), 'dataSourceBean', this.dialectClsName(storeFactory.dialect));
                          else {
                              ccfg.stringProperty('connectionUrl')
                                  .stringProperty('user')
                                  .property('password', `ds.${storeFactory.user}.password`, 'YOUR_PASSWORD');
                          }
  
                          bean.boolProperty('initSchema')
                              .stringProperty('createTableQuery')
                              .stringProperty('loadQuery')
                              .stringProperty('insertQuery')
                              .stringProperty('updateQuery')
                              .stringProperty('deleteQuery');
  
                          break;
                      case 'CacheHibernateBlobStoreFactory':
                          bean = new Bean('org.apache.ignite.cache.store.hibernate.CacheHibernateBlobStoreFactory',
                              'cacheStoreFactory', storeFactory);
  
                          bean.propsProperty('props', 'hibernateProperties');
  
                          break;
                      default:
                  }
  
                  if (bean)
                      ccfg.beanProperty('cacheStoreFactory', bean);
              }
  
              ccfg.boolProperty('storeKeepBinary')
                  .boolProperty('loadPreviousValue')
                  .boolProperty('readThrough')
                  .boolProperty('writeThrough');
  
              if (ccfg.valueOf('writeBehindEnabled')) {
                  ccfg.boolProperty('writeBehindEnabled')
                      .intProperty('writeBehindBatchSize')
                      .intProperty('writeBehindFlushSize')
                      .intProperty('writeBehindFlushFrequency')
                      .intProperty('writeBehindFlushThreadCount');
              }
  
              return ccfg;
          }
  
          // Generate cache concurrency control group.
          static cacheConcurrency(cache, ccfg = this.cacheConfigurationBean(cache)) {
              ccfg.intProperty('maxConcurrentAsyncOperations')
                  .intProperty('defaultLockTimeout')
                  .enumProperty('atomicWriteOrderMode')
                  .enumProperty('writeSynchronizationMode');
  
              return ccfg;
          }
  
          // Generate cache node filter group.
          static cacheNodeFilter(cache, igfss, ccfg = this.cacheConfigurationBean(cache)) {
              const kind = _.get(cache, 'nodeFilter.kind');
  
              if (kind && cache.nodeFilter[kind]) {
                  let bean = null;
  
                  switch (kind) {
                      case 'IGFS':
                          const foundIgfs = _.find(igfss, (igfs) => igfs._id === cache.nodeFilter.IGFS.igfs);
  
                          if (foundIgfs) {
                              bean = new Bean('org.apache.ignite.internal.processors.igfs.IgfsNodePredicate', 'nodeFilter', foundIgfs)
                                  .stringConstructorArgument('name');
                          }
  
                          break;
                      case 'Custom':
                          bean = new Bean(cache.nodeFilter.Custom.className, 'nodeFilter');
  
                          break;
                      default:
                          return ccfg;
                  }
  
                  if (bean)
                      ccfg.beanProperty('nodeFilter', bean);
              }
  
              return ccfg;
          }
  
          // Generate cache rebalance group.
          static cacheRebalance(cache, ccfg = this.cacheConfigurationBean(cache)) {
              if (ccfg.valueOf('cacheMode') !== 'LOCAL') {
                  ccfg.enumProperty('rebalanceMode')
                      .intProperty('rebalanceThreadPoolSize')
                      .intProperty('rebalanceBatchSize')
                      .intProperty('rebalanceBatchesPrefetchCount')
                      .intProperty('rebalanceOrder')
                      .intProperty('rebalanceDelay')
                      .intProperty('rebalanceTimeout')
                      .intProperty('rebalanceThrottle');
              }
  
              if (ccfg.includes('igfsAffinnityGroupSize')) {
                  const bean = new Bean('org.apache.ignite.igfs.IgfsGroupDataBlocksKeyMapper', 'affinityMapper', cache)
                      .intConstructorArgument('igfsAffinnityGroupSize');
  
                  ccfg.beanProperty('affinityMapper', bean);
              }
  
              return ccfg;
          }
  
          // Generate server near cache group.
          static cacheServerNearCache(cache, ccfg = this.cacheConfigurationBean(cache)) {
              if (cache.cacheMode === 'PARTITIONED' && cache.nearCacheEnabled) {
                  const bean = new Bean('org.apache.ignite.configuration.NearCacheConfiguration', 'nearConfiguration',
                      cache.nearConfiguration, {nearStartSize: 375000});
  
                  bean.intProperty('nearStartSize');
  
                  this._evictionPolicy(bean, true,
                      bean.valueOf('nearEvictionPolicy'), cacheDflts.evictionPolicy);
  
                  ccfg.beanProperty('nearConfiguration', bean);
              }
  
              return ccfg;
          }
  
          // Generate cache statistics group.
          static cacheStatistics(cache, ccfg = this.cacheConfigurationBean(cache)) {
              ccfg.boolProperty('statisticsEnabled')
                  .boolProperty('managementEnabled');
  
              return ccfg;
          }
  
          static cacheConfiguration(cache, ccfg = this.cacheConfigurationBean(cache)) {
              this.cacheGeneral(cache, ccfg);
              this.cacheMemory(cache, ccfg);
              this.cacheQuery(cache, cache.domains, ccfg);
              this.cacheStore(cache, cache.domains, ccfg);
  
              const igfs = _.get(cache, 'nodeFilter.IGFS.instance');
              this.cacheNodeFilter(cache, igfs ? [igfs] : [], ccfg);
              this.cacheConcurrency(cache, ccfg);
              this.cacheRebalance(cache, ccfg);
              this.cacheServerNearCache(cache, ccfg);
              this.cacheStatistics(cache, ccfg);
              // this.cacheDomains(cache.domains, cfg);
  
              return ccfg;
          }
      }
  
      return PlatformGenerator;
  }];
  