'use strict';
const Generator = require('yeoman-generator');
var banner = require('./banner')

/**
 * This module buids a Docker Compose template to test
 * Repository and Search Services/Insight Engine with
 * different configurations.
*/
module.exports = class extends Generator {

  // Options to be chosen by the user
  prompting() {

    if (!this.options['skip-install-message']) {
      this.log(banner);
    }

    const prompts = [
      {
        type: 'list',
        name: 'acsVersion',
        message: 'Which ACS version do you want to use?',
        choices: [ '6.1', '6.2', '7.0' ],
        default: '7.0'
      },
      {
        whenFunction: response => response.acsVersion == '6.1',
        type: 'confirm',
        name: 'ags',
        message: 'Would you like to use AGS?',
        default: false
      },
      {
        type: 'list',
        name: 'alfrescoVersion',
        message: 'Would you like to use Alfresco enterprise or community?',
        choices: [ "community", "enterprise" ],
        default: 'community'
      },
      {
        type: 'list',
        name: 'httpMode',
        message: 'Would you like to use HTTP, Shared Secret or mTLS for Alfresco-SOLR communication?',
        choices: [ "http", "https", "secret" ],
        default: 'http'
      },
      {
        type: 'list',
        name: 'httpWebMode',
        message: 'Would you like to use HTTP or HTTPs for Web Proxy?',
        choices: [ "http", "https" ],
        default: 'http'
      },
      {
        type: 'confirm',
        name: 'protectSolr',
        message: 'Would you like to protect the access to SOLR REST API?',
        default: true
      },
      {
        whenFunction: response => response.httpMode == 'http',
        type: 'list',
        name: 'replication',
        message: 'Would you like to use SOLR Replication?',
        choices: [
          { name: "No", value: "" },
          { name: "Yes - two nodes in a master-slave configuration", value: "master-slave" },
          { name: "Yes - two nodes in a master-master configuration", value: "master-master" }
        ]
      },
      {
        whenFunction: response => response.acsVersion == '6.2',
        type: 'confirm',
        name: 'gzip',
        message: 'Would you like to compress Get Content responses?',
        default: false
      },
      // Enterprise only options
      {
        whenFunction: response => response.alfrescoVersion == 'enterprise' && !response.replication,
        type: 'confirm',
        name: 'sharding',
        message: 'Would you like to use dynamic Sharding (2 SOLR nodes)?',
        default: false
      },
      {
        whenFunction: response => response.alfrescoVersion == 'enterprise' && response.sharding,
        type: 'list',
        name: 'shardingMethod',
        message: 'Which Sharding Method do you want to use?',
        choices: [ 
          "DB_ID", 
          "DB_ID_RANGE", 
          "ACL_ID", 
          "MOD_ACL_ID", 
          "DATE", 
          "PROPERTY", 
          "LAST_REGISTERED_INDEXING_SHARD",
          "EXPLICIT_ID_FALLBACK_LRIS",
          "EXPLICIT_ID"
         ],
        default: 'DB_ID'
      },
      {
        type: 'list',
        name: 'searchLogLevel',
        message: 'What log level do you want to use for search?',
        choices: [
          "TRACE",
          "DEBUG",
          "INFO",
          "WARN",
          "ERROR"
        ],
        default: 'WARN'
      },
      {
        whenFunction: response => response.alfrescoVersion == 'enterprise',
        type: 'confirm',
        name: 'insightEngine',
        message: 'Would you like to use Insight Engine instead of Search Services?',
        default: false
      },
      {
        whenFunction: response => response.alfrescoVersion == 'enterprise' && response.insightEngine,
        type: 'confirm',
        name: 'zeppelin',
        message: 'Would you like to deploy Zeppelin?',
        default: false
      }
    ];

    // Create a chain of promises containing the prompts.
    this.promise = Promise.resolve();
    this.props = {};
    prompts.forEach(prompt => {
      // Check if we can answer the prompt via a command line argument.
      const option = this.options[prompt.name];
      if (option === undefined) {
        this.promise = this.promise.then(_ => {
          // Check if the prompt is valid given the existing settings.
          if (!prompt.whenFunction || prompt.whenFunction(this.props)) {
            // Display the prompt and update this.props with the response.
            return this.prompt(prompt).then(props => Object.assign(this.props, props));
          }
        });
      } else {
        this.props[prompt.name] = normalize(option, prompt);
      }
    });
    // Provide Yeoman with the chain of promises so it will wait for answers.
    return this.promise;
  }

  // Generate boilerplate from "templates" folder
  writing() {

    // Set base template directory: 6.1, 6.2, 7.0
    var dockerComposeTemplateDirectory = this.props.acsVersion;

    // Docker Compose environment variables values
    this.fs.copyTpl(
      this.templatePath(dockerComposeTemplateDirectory + '/.env'),
      this.destinationPath('.env'),
      {
        acs: (this.props.ags ? "false" : "true"),
        ags: (this.props.ags ? "true" : "false")
      }
    )

    // Base Docker Compose Template
    const dockerComposeTemplate =
        (this.props.alfrescoVersion == 'community' ?
          dockerComposeTemplateDirectory + '/docker-compose-ce.yml' :
          dockerComposeTemplateDirectory + '/docker-compose-ee.yml');

    // Repository Docker Image name
    const acsImageName =
      (this.props.alfrescoVersion == 'community' ?
        (this.props.ags ? 
          'alfresco/alfresco-governance-repository-community' :
          'alfresco/alfresco-content-repository-community') :
        (this.props.ags ? 
          'quay.io/alfresco/alfresco-governance-repository-enterprise':
          'quay.io/alfresco/alfresco-content-repository'
        )
      );

    // Share Docker Image name
    const shareImageName =
      (this.props.alfrescoVersion == 'community' ?
        (this.props.ags ? 
          'alfresco/alfresco-governance-share-community' :
          'alfresco/alfresco-share') :
        (this.props.ags ? 
          'quay.io/alfresco/alfresco-governance-share-enterprise':
          'quay.io/alfresco/alfresco-share'
        )
      );

    // Search Docker Image
    const searchImageName =
    (this.props.insightEngine ?
      'quay.io/alfresco/insight-engine' :
      'quay.io/alfresco/search-services');

    // Search Docker Image installation base path
    const searchBasePath =
      (this.props.insightEngine ?
        "alfresco-insight-engine" :
        "alfresco-search-services");

    // Copy Docker Compose applying configuration
    this.fs.copyTpl(
      this.templatePath(dockerComposeTemplate),
      this.destinationPath('docker-compose.yml'),
      {
        httpMode: this.props.httpMode,
        httpWebMode: this.props.httpWebMode,
        port: (this.props.httpWebMode == 'http' ? '8080' : '443'),
        secureComms: (this.props.httpMode == 'http' ? 'none' : this.props.httpMode),
        alfrescoPort: (this.props.httpMode == 'https' ? '8443' : '8080'),
        replication: this.props.replication,
        searchSolrHost: (this.props.replication ? "solr6secondary" : "solr6"),
        searchPath: searchBasePath,
        zeppelin: (this.props.zeppelin ? "true" : "false"),
        sharding: (this.props.sharding ? "true" : "false"),
        shardingMethod: (this.props.shardingMethod),
        gzip: (this.props.gzip ? "true" : "false"),
        searchLogLevel: this.props.searchLogLevel
      }
    );

    var imagesDirectory = 'images';

    // Copy Docker Image for Repository applying configuration
    this.fs.copyTpl(
      this.templatePath(imagesDirectory + '/alfresco/Dockerfile'),
      this.destinationPath('alfresco/Dockerfile'),
      {
        acsImage: acsImageName,
        sharding: (this.props.sharding ? "true" : "false")
      }
    );
    // Copy Sharding Content Model or an empty file to allow model deployments
    if (this.props.sharding) {
      this.fs.copy(
        this.templatePath(imagesDirectory + '/alfresco/model/*.xml'),
        this.destinationPath('alfresco/model/')
      )
    } else {
      this.fs.copy(
        this.templatePath(imagesDirectory + '/alfresco/model/empty'),
        this.destinationPath('alfresco/model/empty')
      )
    }

    // Copy Docker Image for Share applying configuration
    this.fs.copyTpl(
      this.templatePath(imagesDirectory + '/share/Dockerfile'),
      this.destinationPath('share/Dockerfile'),
      {
        shareImage: shareImageName,
        httpWebMode: this.props.httpWebMode,
        port: (this.props.httpWebMode == 'http' ? '8080' : '443'),
      }
    );
    // Copy Sharding Content Forms or an empty file to allow forms deployments
    if (this.props.sharding) {
      this.fs.copy(
        this.templatePath(imagesDirectory + '/share/model/sharding-share-config-custom.xml'),
        this.destinationPath('share/model/share-config-custom-dev.xml')
      )
    } else {
      this.fs.copy(
        this.templatePath(imagesDirectory + '/share/model/empty.xml'),
        this.destinationPath('share/model/share-config-custom-dev.xml')
      )
    }

    // Empty addons directories
    ['alfresco', 'share'].forEach(container => {
      ['jars', 'amps'].forEach(addonType => {
        this.fs.copy(
          this.templatePath('empty/empty'),
          this.destinationPath(container + '/modules/' + addonType + '/empty')
        );
      });
    });

    // Copy Docker Image for Search applying configuration
    this.fs.copyTpl(
      this.templatePath(imagesDirectory + '/search'),
      this.destinationPath('search'),
      {
        searchImage: searchImageName,
        searchPath: searchBasePath
      }
    );

    // Copy Docker Image for Zeppelin applying configuration
    if (this.props.zeppelin) {
      this.fs.copy(
        this.templatePath(imagesDirectory + '/zeppelin'),
        this.destinationPath('zeppelin')
      );
    }

    // Add resources for SSL configuration
    if (this.props.httpMode == 'https') {
      // Currently Community 'latest' only supports OLD keystores and trustores format
      var subfolder = (this.props.acsVersion == 'latest' && this.props.alfrescoVersion == 'enterprise') ? '7.x' : '6.x'
      this.fs.copy(
        this.templatePath('keystores/' + subfolder + '/alfresco'),
        this.destinationPath('keystores/alfresco')
      )
      this.fs.copy(
        this.templatePath('keystores/' + subfolder + '/solr'),
        this.destinationPath('keystores/solr')
      )
      this.fs.copy(
        this.templatePath('keystores/' + subfolder + '/client'),
        this.destinationPath('keystores/client')
      )
      if (this.props.zeppelin == true) {
        this.fs.copy(
          this.templatePath('keystores/' + subfolder + '/zeppelin'),
          this.destinationPath('keystores/zeppelin')
        )
      }
    }

    // Copy NGINX Configuration
    this.fs.copyTpl(
      this.templatePath(imagesDirectory + '/config/nginx'),
      this.destinationPath('config'),
      {
        port: (this.props.httpWebMode == 'http' ? '8080' : '443'),
        httpMode: this.props.httpMode,
        httpWebMode: this.props.httpWebMode,
        protectSolr: (this.props.protectSolr ? 'true' : 'false')
      }
    );
    if (this.props.httpWebMode == 'https') {
      this.fs.copy(
        this.templatePath(imagesDirectory + '/config/cert'),
        this.destinationPath('config/cert')
      );
    }

  }

};

// Convert parameter string value to boolean value
function normalize(option, prompt) {

  if (prompt.type === 'confirm' && typeof option === 'string') {
    let lc = option.toLowerCase();
    if (lc === 'true' || lc === 'false') {
      return (lc === 'true');
    } else {
      return option;
    }
  }

  return option;

}

