/*
	Licensed Material - Property of IBM

	(C) Copyright 2015, 2016 IBM Corp.

	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.
*/


'use strict';

var Q = require('q');
var inquirer = require('inquirer');
var path = require('path');
var nopt = require('nopt');
var serverSupport = require('mdo-server-support');
var strings = require('ibm-strings');
var errors = require('mdo-errors');
var externalizedStrings = require('./externalizedStrings');
var serverRegEx = require('./server-add').serverRegEx;
var urlFormatter = require('url');


module.exports.validate = function(args) {
  var deferred = Q.defer();

  var opts = nopt({
    password: String
  }, {
    p: '--password'
  }, args, 0);

  if (opts.argv.remain.length > 0) {
    if (opts.argv.remain.length === 1) {
      // Check server name
      var serverName = args[0];
      if (!serverName.match(serverRegEx)) {
        var invalidServerName = errors.getError('INVALIDSERVERNAME');
        deferred.reject(invalidServerName);
      }
      else {
        deferred.resolve(opts);
      }
    }
    else { // invalid arguments found
      var badArguments = errors.getError('BADSERVERARGS', 'clean');
      deferred.reject(badArguments);
    }
  }
  else {
    deferred.resolve(opts);
  }
  return deferred.promise;
};

module.exports.run = function(args, profiles) {
  var deferred = Q.defer();
  var ifDirect;
  if (args.argv.remain.length === 0) { // Interactive mode
    ifDirect = false;
    var choices = [];
    for (var i in profiles.servers) {
        choices.push(i);
    }
    if (choices.length === 0) {
      var MISSINGSERVERPROFILES = errors.getError('MISSINGSERVERPROFILES', 'clean');
      deferred.reject(MISSINGSERVERPROFILES);
    }
    else {
      inquirer.prompt([
          {
            name: 'serverName',
            message: externalizedStrings.selectServerToClean,
            type: 'list',
            choices: choices
          }], function (answers) {
            // clean server
            cleanServer(args, profiles, answers.serverName, ifDirect)
              .then(function () {
                deferred.resolve();
              }).fail(function (error) {
                deferred.reject(error);
            });
        }
      );

    }
  }
  else { // Direct mode
    // clean server
    var serverName = args.argv.remain.shift();
    ifDirect = true;
    cleanServer(args, profiles, serverName, ifDirect)
      .then(function () {
        deferred.resolve();
      }).fail(function (error) {
      deferred.reject(error);
    });
  }
  return deferred.promise;
};

// return the help object for the main mdo help command to show
module.exports.getMainHelp = function() {
  var help = {
    "SERVERS" : [
      {"server clean" : externalizedStrings.serverCleanDescription}
    ]
  };
  return help;
};

module.exports.getHelpFilePath = function(basePath) {
  return path.join(basePath, 'mdo-cmd-server', 'doc', 'clean.txt');
};

//
function cleanServer(args, profiles, serverName, ifDirect) {
  var deferred = Q.defer();
  //Verify server to be cleaned exists in server_profiles.json
  if (profiles.servers[serverName] === undefined) {
    var serverDoesNotExists = errors.getError('SVRDOESNOTEXISTS', serverName);
    deferred.reject(serverDoesNotExists);
  }
  else {
      console.log(externalizedStrings.serverCreateContactingServer);
      var serverinfo = profiles.servers[serverName];
      //get server details
      inquirer.prompt([
        {
            name: 'password',
            message: externalizedStrings.whatServerPassword,
            type: 'password',
            when: function () {
              return (args.password === undefined &&
              (!serverinfo.hasOwnProperty('password') || serverinfo.password === ''));
            }
        }],
        function (answers) {
            var password;
            if (answers.password !== undefined) {
              password = answers.password;
            }
            else {
              password = args.password || new Buffer(serverinfo.password, 'base64');
            }
            var options = {
                protocol: serverinfo.protocol,
                host: serverinfo.host,
                port: serverinfo.port,
                path: serverinfo.path,
                userName: serverinfo.login,
                userPassword: password,
                contextRoot: serverinfo.contextRoot,
                timeout: serverinfo.timeout
            };

            //get runtimes on the server
            serverSupport.getRuntimes(options).then(function (results){
                var runtimes = [];
                for (var i = 0; i < results.projects.length; ++i) {
                    runtimes.push(results.projects[i].name);
                }
                if (runtimes.length === 0) {
                    strings.info(externalizedStrings.serverRuntimeMessage);
                }
                else {
                    console.log(externalizedStrings.serverRuntimeList [strings.theme.info], runtimes.toString());
                }
                return runtimes;
            })
            .then(function (result){
                var promises = [];
                for(var r in result){
                    var runtime = result[r];
                    //get applications and adapters in each runtime and delete it
                    promises.push(getAppsAndAdapters(options, runtime));
                }
                Q.all(promises).then(function (result){
                  var applications = [];
                  var adapters = [];
                  for(var i in result){
                    if(result[i][0] !== null || result[i][1] !== null){
                      applications.push(result[i][0]);
                      adapters.push(result[i][1]);
                    }
                  }
                  if(!(applications.length === 0 && adapters.length === 0)){
                    if(!ifDirect){
                      inquirer.prompt([
                          {
                            name: 'confirmation',
                            message: externalizedStrings.confirmCleanServer,
                            type: 'confirm',
                            default: true
                          }], function (answers) {
                          // if confirmation equals true, clean server
                          if (answers.confirmation) {
                              deleteAppsAndAdapters(options, applications, adapters)
                                .then(function () {
                                  deferred.resolve();
                                }).fail(function (error) {
                                  deferred.reject(error);
                                });
                          }
                          else {
                            deferred.resolve();
                          }
                        }
                      );
                    }
                    else {
                      deleteAppsAndAdapters(options, applications, adapters)
                        .then(function () {
                          deferred.resolve();
                        }).fail(function (error) {
                          deferred.reject(error);
                        });
                    }
                  }
                  else {
                    deferred.resolve();
                  }
                });
            })
            .fail(function (err){
                var url;
                if(typeof options.path !== 'undefined' && options.path.length > 1)
                  url = urlFormatter.format({protocol:(options.protocol || 'http') , hostname: options.host, port: options.port, pathname:options.path});
                else
                  url = urlFormatter.format({protocol:(options.protocol || 'http') , hostname: options.host, port: options.port});
                var runtimeFail = errors.getError('SVRUNREACHABLE', serverName, url);
                err.errno = runtimeFail.errno;
                err.description = runtimeFail.description + '\n' + 'Reason: ' + err.message;
                deferred.reject(err);
            });
        }
      );
  }
  return deferred.promise;
}

function getAppsAndAdapters(options, runtime){
  var deferred = Q.defer();
  var promises = [];
  var serverDetails =  {
      protocol: options.protocol,
      host: options.host,
      port: options.port,
      path: options.path,
      userName: options.userName,
      userPassword: options.userPassword,
      contextRoot: options.contextRoot,
      timeout: options.timeout,
      runtime: runtime
  };

  var applicationsList = serverSupport.getApplications(serverDetails).then(function (results){
    var applications = [];

    for (var i = 0; i < results.totalListSize; ++i) {
      var environments = results.items[i].envs;
      for(var j=0; j<environments.length;++j){
         var versions = environments[j].versions;
         for(var k=0; k<versions.length;++k){
            var application = versions[k].resourceName.replace(/\$/g,'\/');
            applications.push(application);
         }
      }

    }
    if (applications.length === 0) {
      strings.info(strings.format(externalizedStrings.serverApplicationsMessage, runtime));
      return null;
    }
    else {
      console.log(strings.format(externalizedStrings.serverApplicationList [strings.theme.info], runtime), applications.toString());
      applications.unshift(runtime);
      return applications;
    }

  })
  .fail(function (err){
     deferred.reject(err);
  });

  var adaptersList = serverSupport.getAdapters(serverDetails).then(function (results){
      var adapters = [];
      for (var i = 0; i < results.totalListSize; i++) {
          adapters.push(results.items[i].resourceName);
      }
      if (adapters.length === 0) {
          strings.info(strings.format(externalizedStrings.serverAdaptersMessage, runtime));
          return null;
      }
      else {
          console.log(strings.format(externalizedStrings.serverAdapterList [strings.theme.info],runtime), adapters.toString());
          adapters.unshift(runtime);
          return adapters;
      }

  })
  .fail(function (err){
      deferred.reject(err);
  });

  promises.push(applicationsList);
  promises.push(adaptersList);
  Q.all(promises).then(function (result){
      deferred.resolve(result);
  })
  .fail(function (err){

      deferred.reject(err);
  });

  return deferred.promise;
}

//delete apps and adapters
function deleteAppsAndAdapters(options, applications, adapters){
  var deferred = Q.defer();
  var deletePromises = [];

  for(var app in applications){
    if(applications[app] !== null){
      var appRuntime = applications[app][0];
      for(var i = 1; i < applications[app].length; i++){
        var deleteAppDetails = {
          protocol: options.protocol,
          host: options.host,
          port: options.port,
          path: options.path,
          userName: options.userName,
          userPassword: options.userPassword,
          contextRoot: options.contextRoot,
          timeout: options.timeout,
          runtime: appRuntime,
          application: applications[app][i]
        };
        //delete applications
        deletePromises.push(deleteApplication(deleteAppDetails));
      }
    }

  }

  for(var ada in adapters){
    if(adapters[ada] !== null){
      var adaRuntime = applications[ada][0];
      for(var j = 1; j < adapters[ada].length; j++){
        var deleteAdaDetails = {
            protocol: options.protocol,
            host: options.host,
            port: options.port,
            path: options.path,
            userName: options.userName,
            userPassword: options.userPassword,
            contextRoot: options.contextRoot,
            timeout: options.timeout,
            runtime: adaRuntime,
            adapter: adapters[ada][j]
        };
        //delete adapters
        deletePromises.push(deleteAdapter(deleteAdaDetails));
      }
    }

  }

  Q.all(deletePromises).then(function (){
      deferred.resolve("all apps and adapters has been cleaned");
    }
  ).fail(function (err){
      deferred.reject(err);
  });
  return deferred.promise;
}

//delete Application
function deleteApplication(deleteDetails){
    var deferred = Q.defer();
    serverSupport.deleteApplication(deleteDetails).then(function (results){
        if(results.ok){
            strings.info(strings.format(externalizedStrings.successAppDeleted, deleteDetails.application));
            deferred.resolve(deleteDetails.application+ " cleaned");
        }else {
            strings.fatal(strings.format(externalizedStrings.successAppDeleted, deleteDetails.application));
            deferred.reject(deleteDetails.application+ " failed");
        }
    })
    .fail(function (err){
        strings.fatal(strings.format(externalizedStrings.failedDeleteApp, deleteDetails.application));
        deferred.reject(err);
    });
    return deferred.promise;
}

//delete Adapter
function deleteAdapter(deleteDetails){
    var deferred = Q.defer();
    serverSupport.deleteAdapter(deleteDetails).then(function (results){
        if(results.ok){
            strings.info(strings.format(externalizedStrings.successAdapterDeleted, deleteDetails.adapter));
            deferred.resolve(deleteDetails.adapter+" cleaned");
        }else {
            strings.fatal(strings.format(externalizedStrings.successAppDeleted, deleteDetails.application));
            deferred.reject(deleteDetails.application+ " failed");
        }
    })
    .fail(function (err){
        strings.fatal(strings.format(externalizedStrings.failedDeleteAdapter, deleteDetails.adapter));
        deferred.reject(err);
    });
    return deferred.promise;
}
