/*
	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 nopt = require('nopt');
var fs = require('fs');
var path = require('path');
var et = require('elementtree');

var externalizedStrings = require('./externalizedStrings');
var errors = require('mdo-errors');
var strings = require('ibm-strings');
var exec = require('mdo-exec').run;
var urlFormatter = require('url');
//var profileIO = require('mdo-server-support').profileIO;
var serverSupport = require('mdo-server-support');

/* as of the current specification, due to consistency across other commands interactive prompt has been put on hold for future planning
  var promptParameters = function () {
  var deferred = Q.defer();

  var prompts = [
    {
      name: 'serverURL',
      message: externalizedStrings.enterServerURL,
      validate: function(input) {
        var err = validateServerURL(input);
        if (err === null) {
          return true;
        }
        else {
          console.log();
          strings.fatal(err.description);
          return false;
        }
      },
      default: defaultURL
    },
    {
      name: 'username',
      message: externalizedStrings.enterUsername,
      validate: function(input) {
        var err = validateUsername(input);
        if (err === null) {
          return true;
        }
        else {
          console.log();
          strings.fatal(err.description);
          return false;
        }
      },
      default: defaultUsername
    },
    {
      name: 'password',
      message: externalizedStrings.enterPassword,
      validate: function(input) {
        var err = validatePassword(input);
        if (err === null) {
          return true;
        }
        else {
          console.log();
          strings.fatal(err.description);
          return false;
        }
      },
      default: defaultPassword
    }
  ];

  inquirer.prompt(prompts, function (answers) {
    deferred.resolve(answers);
  });

  return deferred.promise;
};*/

/*var processProfiles = function(profiles, opts) {
  var deferred = Q.defer();

  if (!profiles.defaultServer) {
    // no server definitions
    deferred.reject(errors.getError('MISSINGSERVERPROFILES', externalizedStrings.deployTo));
  }
  else {
    // console.log(profiles);
    var profile;

    if (opts.argv.remain.length === 0) profile = profiles.defaultServer;    // use default server profile
    else profile = opts.argv.remain[0];                                     // use indicated server profile

    if (!profiles.servers[profile]) {
      // profile doesn't exist
      deferred.reject(errors.getError('SVRDOESNOTEXISTS', profile));
    }
    else {
      var serverProfile = {
        serverURL : profiles.servers[profile].protocol + '://' + profiles.servers[profile].host + ':' + profiles.servers[profile].port + '/' + profiles.servers[profile].contextRoot,
        username : profiles.servers[profile].login,
        password : new Buffer(profiles.servers[profile].password, 'base64').toString('utf8')
      };
      deferred.resolve(serverProfile);
    }
  }
  return deferred.promise;
};*/

var deployAdapter = function(serverURL, username, password, runtime, directory) {
  var deferred = Q.defer();

  var mavenParams = [
    'adapter:deploy',
    '-DmfpfUrl=' + serverURL,
    '-DmfpfUser=' + username,
    '-DmfpfPassword=' + password,
    '-DmfpfRuntime=' + runtime
  ];

  exec('mvn', mavenParams, directory).then(function() {
    deferred.resolve(directory);
  }, function(err) {
    console.log('\n' + err.stdOut);
    deferred.reject({"err":err, "directory": directory});
  });
  return deferred.promise;
};

// Recursively search to find if there are nested adapters
var search = function(serverURL, username, password, runtime, directory, xml) {
  var pass = 0;
  var fail = 0;
  var promises = [];
  var deferred = Q.defer();
  fs.readdir(directory, function(err, directoryUnfiltered) {

    // Empty Folder
    if(directoryUnfiltered === undefined) {
      deferred.resolve({"pass": pass, "fail": fail});
    } else {
      // filter out all hidden directories/files that start with a '.'
      var directoryContent = [];
      directoryUnfiltered.forEach(function(item) {
        if(!item.startsWith('.')) {
          directoryContent.push(item);
        }
      });
      // Check if it's an adapter folder
      if(directoryContent.indexOf('pom.xml') !== -1) {
        // Adapter Folder
        fs.stat(path.join(directory, 'src', 'main', 'adapter-resources', 'adapter.xml'), function(err) {
          if(!err) {
            if (xml) {
              fs.readFile(path.join(directory, 'pom.xml'), function(err, data) {
                console.log(strings.format(externalizedStrings.readingConfigurations, path.basename(directory)));
                data = data.toString();
                var etree = et.parse(data);
                
                serverURL = etree.findtext('.//mfpfUrl');
                username = etree.findtext('.//mfpfUser');
                password = etree.findtext('.//mfpfPassword');
                runtime = etree.findtext('.//mfpfRuntime');
                
                // override with default values in pom.xml
                console.log(strings.format(externalizedStrings.defaultServerURL, serverURL));
                console.log(strings.format(externalizedStrings.defaultUsername, username));
                console.log(externalizedStrings.defaultPassword);
                console.log(strings.format(externalizedStrings.defaultRuntime, runtime));
                
                console.log(strings.format(externalizedStrings.deployingAdapterName, path.basename(directory), runtime, serverURL) + '\n');
                deployAdapter(serverURL, username, password, runtime, directory).then(function(resolve) {
                  pass++;
                  console.log(strings.format(externalizedStrings.successfulDeployName, path.basename(resolve)));
                  deferred.resolve({"pass": pass, "fail": fail});
                }).fail(function(err) {
                  fail++;
                  console.log(strings.format(externalizedStrings.errorDeployName, path.basename(err.directory)));
                  deferred.resolve({"pass": pass, "fail": fail});
                });
              });
              
            } else {
              console.log(strings.format(externalizedStrings.deployingAdapterName, path.basename(directory), runtime, serverURL));
              deployAdapter(serverURL, username, password, runtime, directory).then(function(resolve) {
                pass++;
                console.log(strings.format(externalizedStrings.successfulDeployName, path.basename(resolve)));
                deferred.resolve({"pass": pass, "fail": fail});
              }).fail(function(err) {
                fail++;
                console.log(strings.format(externalizedStrings.errorDeployName, path.basename(err.directory)));
                deferred.resolve({"pass": pass, "fail": fail});
              });
            }
          } else {
            // Otherwise continue looking for more adapters
            directoryContent.forEach(function(item) {
              var itemPath = path.join(directory, item);
              var check = fs.statSync(itemPath);
              if(check.isDirectory()) {
                promises.push(search(serverURL, username, password, runtime, path.join(directory, item), xml));
              }
              Q.all(promises).then(function(resolves) {
                resolves.forEach(function(resolve) {
                  pass += resolve.pass;
                  fail += resolve.fail;
                });
                deferred.resolve({"pass": pass, "fail": fail});
              });
            });
          }
        });
      } else {
        if(directoryContent.length === 0) {
          deferred.resolve({"pass": pass, "fail": fail});
        }
        directoryContent.forEach(function(item) {
          var itemPath = path.join(directory, item);
          var check = fs.statSync(itemPath);
          if(check.isDirectory()) {
            promises.push(search(serverURL, username, password, runtime, path.join(directory, item), xml));
          }
          Q.all(promises).then(function(resolves) {
            resolves.forEach(function(resolve) {
              pass += resolve.pass;
              fail += resolve.fail;
            });
            deferred.resolve({"pass": pass, "fail": fail});
          });
        });
      }
    }
  });
  return deferred.promise;
};

/**
 * actually do the work of the command
 */
module.exports.run = function(argv) {
  var deferred = Q.defer();
  //var startingDir = process.cwd();
  
  var all = false;
  if(argv && argv[0] === 'all') {
    all = true;
    argv.shift();
  }
  
  var opts = nopt({
    xml: Boolean,
    password: String
  }, {
    x: '--xml',
    p: '--password'
  }, argv, 0);
  
  var serverURL;
  var username;
  var password;
  var runtime;
  var directory = process.cwd();
  
  // direct mode  
  if (opts.xml) {
    if(all) {
      search(serverURL, username, password, runtime, directory, opts.xml).then(function (response) {
        if(response.pass === 0 && response.fail === 0) {
          console.log(strings.format(externalizedStrings.noAdaptersFound));
          deferred.resolve();
        } else {
          console.log(strings.format(externalizedStrings.numberAdaptersDeployed, response.pass, response.fail));
          deferred.resolve();
        }
      }, function (err) {
        console.log(externalizedStrings.errorDeploy);
        console.log(err.stdOut);
        var errorDeploy = errors.getError('ADAPTERDEPLOYERROR');
        strings.fatal(errorDeploy.description);
        deferred.reject(errorDeploy);
      });
    } else{
      fs.readFile(path.join(directory, 'pom.xml'), function(err, data) {
        data = data.toString();
        var etree = et.parse(data);
        
        serverURL = etree.findtext('.//mfpfUrl');
        username = etree.findtext('.//mfpfUser');
        password = etree.findtext('.//mfpfPassword');
        runtime = etree.findtext('.//mfpfRuntime');
        
        // override with default values in pom.xml
        console.log(strings.format(externalizedStrings.defaultServerURL, serverURL));
        console.log(strings.format(externalizedStrings.defaultUsername, username));
        console.log(externalizedStrings.defaultPassword);
        console.log(strings.format(externalizedStrings.defaultRuntime, runtime));
          
        console.log(strings.format(externalizedStrings.deployingAdapterName, path.basename(directory), runtime, serverURL));
        deployAdapter(serverURL, username, password, runtime, directory).then(function () {
          console.log(strings.format(externalizedStrings.successfulDeployName, path.basename(directory)));
          deferred.resolve();
        }, function (err) {
          console.log(strings.format(externalizedStrings.errorDeployName, path.basename(directory)));
          console.log(err.stdOut);
          var errorDeploy = errors.getError('ADAPTERDEPLOYERROR');
          strings.fatal(errorDeploy.description);
          deferred.reject(errorDeploy);
        });
      });
    }
  } else if (opts.argv.remain.length <= 2) {
  serverSupport.getServerDetails(opts.argv.remain[0], opts.argv.remain[1], opts.password, true).then(function(serverProfile) {
    if(typeof serverProfile.path !== 'undefined' && serverProfile.path.length > 1)
      serverURL = urlFormatter.resolve(urlFormatter.format({protocol:(serverProfile.protocol || 'http'), hostname: serverProfile.host, port: serverProfile.port}), serverProfile.path+"/"+serverProfile.contextRoot);
    else
      serverURL = urlFormatter.resolve(urlFormatter.format({protocol:(serverProfile.protocol || 'http'), hostname: serverProfile.host, port: serverProfile.port}), serverProfile.contextRoot);
    username = serverProfile.userName;
    password = serverProfile.userPassword;
    runtime = serverProfile.runtime;
    if(all) {
      search(serverURL, username, password, runtime, directory, false).then(function (response) {
        if(response.pass === 0 && response.fail === 0) {
          console.log(strings.format(externalizedStrings.noAdaptersFound));
          deferred.resolve();
        } else {
          console.log(strings.format(externalizedStrings.numberAdaptersDeployed, response.pass, response.fail));
          deferred.resolve();
        }
      }, function (err) {
        console.log(externalizedStrings.errorDeploy);
        console.log(err.stdOut);
        var errorDeploy = errors.getError('ADAPTERDEPLOYERROR');
        strings.fatal(errorDeploy.description);
        deferred.reject(errorDeploy);
      });
    } else{
      console.log(strings.format(externalizedStrings.deployingAdapter, runtime, serverURL));
      deployAdapter(serverURL, username, password, runtime, process.cwd()).then(function () {
        console.log(externalizedStrings.successfulDeploy);
        deferred.resolve();
      }, function (err) {
        console.log(externalizedStrings.errorDeploy);
        console.log(err.stdOut);
        var errorDeploy = errors.getError('ADAPTERDEPLOYERROR');
        strings.fatal(errorDeploy.description);
        deferred.reject(errorDeploy);
      });
    }
  }, function(err) {
    strings.fatal(err.description);
    deferred.reject(err);
  });
/*
    // create local server profle if local server already running and no default server profile exists rather than erroring out
    profileIO.getServerProfiles(true,true).then(function(profiles) {
      processProfiles(profiles, opts).then(function(serverProfile) {
        deployAdapter(serverProfile.serverURL, serverProfile.username, serverProfile.password).then(function () {
          console.log(externalizedStrings.successfulDeploy);
          deferred.resolve();
        }, function (err) {
          console.log(externalizedStrings.errorDeploy);
          console.log(err.stdOut);
          var errorDeploy = errors.getError('ADAPTERDEPLOYERROR');
          strings.fatal(errorDeploy.description);
          deferred.reject(errorDeploy);
        });
      }, function(err) {
        strings.fatal(err.description);
        deferred.reject(err);
      });
    });
*/
  } else {
    // invalid params
    var invalidParams = errors.getError('INVALIDADAPTERPARAMS');
    strings.fatal(invalidParams.description);
    deferred.reject(invalidParams);
  }
  return deferred.promise;
};

// return the path to the md file (relative to basePath) for the specific command
module.exports.getHelpFilePath = function(basePath) {
  return path.join(basePath, 'mdo-adapter-actions', 'doc', 'deploy.txt');
};

/* as of the current specification, due to consistency across other commands interactive prompt has been put on hold for future planning
function validateParams (serverURL, username, password, remain) {
  var deferred = Q.defer();

  var validationList = [];

  if (serverURL) validationList.push(validateServerURL(serverURL));
  if (username) validationList.push(validateUsername(username));
  if (password) validationList.push(validatePassword(password));

  var noError = true;

  validationList.forEach(function(error) {
    if (error) {
      noError = false;
      strings.fatal(error.description);
    }
  });

  if (noError) {
    if (remain.length > 0) {
      deferred.reject(errors.getError('INVALIDADAPTERPARAMS'));
    }
    else deferred.resolve();
  }
  else {
    deferred.reject(errors.getError('ADAPTERDEPLOYERROR'));
  }

  return deferred.promise;
}

function validateServerURL (server) {
  var error = null;

  if (typeof server === 'undefined' || server === null || server.trim().length === 0) {
//    error = errors.getError('MISSINGURL');
  }

  return error;
}

function validateUsername (username) {
  var error = null;

  if (typeof username === 'undefined' || username === null || username.trim().length === 0) {
//    error = errors.getError('MISSINGUSERNAME');
  }

  return error;
}

function validatePassword (password) {
  var error = null;

  if (typeof password === 'undefined' || password === null || password.trim().length === 0) {
//    error = errors.getError('MISSINGPASSWORD');
  }

  return error;
}

module.exports.validateServerURL = validateServerURL;
module.exports.validateUsername = validateUsername;
module.exports.validatePassword = validatePassword;
*/
// module.exports.processProfiles = processProfiles;
