/*
	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';

// public modules
var Q = require('q');
var log = require('npmlog');

// private modules
var getServerAndRuntime = require('./getServerAndRuntime.js');
var getRuntimes = require('./rest-client-api/rest-client-api.js').getRuntimes;
var getApplications = require('./rest-client-api/rest-client-api.js').getApplications;
var getAdapters = require('./rest-client-api/rest-client-api.js').getAdapters;
var getAdapter = require('./rest-client-api/rest-client-api.js').getAdapter;
var getApplicationDescriptor = require('./rest-client-api/rest-client-api.js').getApplicationDescriptor;
var getRuntimeConfiguration = require('./rest-client-api/rest-client-api.js').getRuntimeConfiguration;
var setApplicationDescriptor = require('./rest-client-api/rest-client-api.js').setApplicationDescriptor;
var setRuntimeConfiguration = require('./rest-client-api/rest-client-api.js').setRuntimeConfiguration;
var registerApplication = require('./rest-client-api/rest-client-api.js').registerApplication;
var deployWebupdate = require('./rest-client-api/rest-client-api.js').deployWebupdate;
var moduleName = 'getServerDetails'; // - name for clarification during logging

/**
 * Obtains the default server profile, or a given profile if specified, and checks if a runtime is
 * available on the server.  If multiple runtimes are found the user will be prompted to select one.
 * It will also convert any hostname with the name localhost to a static ip.  If multiple ip addresses
 * are found the user will be prompted to select one.  See parameters below to change the default
 * behavior.
 *
 * Parameters:
 *
 *  serverProfile  // Optional String.  If specified will get the server profile with this name.  If
 *                    one is not found an error is returned.  Default is to use the default profile.
 *  runtime        // Optional String.  If specified will validate that the given runtime is available.
 *                    If it is not available an error is returned.  Default is to use the available runtime.
 *                    If more than one runtime is available user will be prompted to select one.
 *  password       // Optional String.  If specified will use the given password. Default is to use the
 *                    password found in the server profile.  If no password is found in the profile the
 *                    user will be prompted for one.
 *  useLocalHost   // Optional Boolean. If true, does not convert localhost to a static ip.  Default is false
 *                    and localhost will be converted to a static ip.  User will be prompted to select an ip
 *                    if multiple are found.
 *  neverPrompt    // Optional Boolean.  If true, will not prompt for runtime, password or static ip.  Will just
 *                    choose the first found if multiple ip addresses are found.  For password it simply uses
 *                    whatever is specified in the profile.  For runtime it uses the value in config.xml if multiple
 *                    are found.  Default is false.
 *
 *  Q.deferred.promise.
 *   On success, a JSON object containing the server and runtime details is returned
 *   On failure, an error is returned
 *
 * Example JSON output
 *
 *  {
 *      "runtime": "TestProject",
 *      "protocol": "http",
 *      "host": "server1.raleigh.ibm.com",
 *      "port": "9080",
 *      "login": "admin",
 *      "password": "admin",
 *      "contextRoot": "worklightadmin",
 *      "timeout": "30",
 *
 *      "getApplications": getApplications,
 *      "getAdapter": getApplications,
 *      "getApplicationDescriptor": getApplicationDescriptor,
 *      "getRuntimes": getRuntimes,
 *      "getRuntimeConfiguration": getRuntimeConfiguration,
 *      "registerApplication": registerApplication,
 *      "setApplicationDescriptor": setApplicationDescriptor,
 *      "setRuntimeConfiguration": setRuntimeConfiguration
 *  }
 */
module.exports = function (serverProfile, runtime, userPassword, useLocalHost, neverPrompt) {

  var deferred = Q.defer();

  var getServerAndRuntimePromise = getServerAndRuntime(serverProfile, runtime, userPassword, useLocalHost, neverPrompt);
  getServerAndRuntimePromise.then(function (rsp) {

    var serverDetails,
        runtime,
        serverDetailsAndMethods;

    runtime = (rsp && rsp.runtime ? rsp.runtime : 'mfp');
    serverDetails = (rsp && rsp.serverProfile ? rsp.serverProfile : {});

    log.silly(moduleName, 'Arguments: '+ (serverDetails ? JSON.stringify(serverDetails,null,' ') : serverDetails));

    var protocol     = (serverDetails && serverDetails.protocol ? serverDetails.protocol : 'http');  //jshint ignore:line
    var host         = (serverDetails && serverDetails.host ? serverDetails.host : 'localhost');
    var port         = (serverDetails && serverDetails.port ? serverDetails.port : 9080);
    var contextRoot  = (serverDetails && serverDetails.contextRoot ? serverDetails.contextRoot : 'mfpadmin');
    var userName     = (serverDetails && serverDetails.login ? serverDetails.login : 'admin');
    var userPassword = (serverDetails && serverDetails.password ? serverDetails.password : 'admin');
    var timeout      = (serverDetails && serverDetails.timeout ? parseInt(serverDetails.timeout)*1000 : 30000);
    var details      = (serverDetails && serverDetails.details ? serverDetails.details : false);

    serverDetails.runtime = runtime;
    serverDetails.protocol = protocol;
    serverDetails.host = host;
    serverDetails.port = port;
    serverDetails.contextRoot = contextRoot;
    serverDetails.userName = userName;
    serverDetails.userPassword = userPassword;
    serverDetails.timeout = timeout;
    serverDetails.details = details;

    //console.log(serverDetails);
    var restClientManager = new RestClientManager(serverDetails);

    // including server profile is overkill, but needed to support
    // some mdo commands still looking for it.
    serverDetailsAndMethods = {

      serverProfile: serverDetails,

      runtime: runtime,
      protocol: protocol,
      host: host,
      port: port,
      contextRoot: contextRoot,
      userName: userName,
      userPassword: userPassword,
      timeout: timeout,
      details: details,

      getRuntimes: restClientManager.getRuntimes,
      getApplications: restClientManager.getApplications,
      getAdapters: restClientManager.getAdapters,
      getAdapter: restClientManager.getAdapter,
      getApplicationDescriptor: restClientManager.getApplicationDescriptor,
      getRuntimeConfiguration: restClientManager.getRuntimeConfiguration,
      setApplicationDescriptor: restClientManager.setApplicationDescriptor,
      setRuntimeConfiguration: restClientManager.setRuntimeConfiguration,
      registerApplication: restClientManager.registerApplication,
      deployWebupdate: restClientManager.deployWebupdate

    };

    deferred.resolve(serverDetailsAndMethods);

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

  return deferred.promise;

};

var RestClientManager = function (sDetails) {

  var that = this;
  this.sDetails = sDetails;

  this.getRuntimes = function () {
    return getRuntimes(that.sDetails);
  };

  this.getApplications = function () {
    return getApplications(that.sDetails);
  };

  this.getAdapters = function () {
    return getAdapters(that.sDetails);
  };

  this.getAdapter = function (adapterName) {
    that.sDetails.adapter = adapterName;
    return getAdapter(that.sDetails);
  };

  this.getApplicationDescriptor = function (applicationDetails, appDescFilePath) {
    return getApplicationDescriptor(that.sDetails, applicationDetails, appDescFilePath);
  };

  this.getRuntimeConfiguration = function () {
    return getRuntimeConfiguration(that.sDetails);
  };

  this.setApplicationDescriptor = function (appDescFilePath, applicationDetails) {
    return setApplicationDescriptor(that.sDetails, appDescFilePath, applicationDetails);
  };

  this.setRuntimeConfiguration = function (runtimeConfig) {
    return setRuntimeConfiguration(that.sDetails, runtimeConfig);
  };

  this.registerApplication = function (payload) {
    return registerApplication(that.sDetails, payload);
  };

  this.deployWebupdate = function (applicationKey, webResourceFilePath) {
    return deployWebupdate(that.sDetails, applicationKey, webResourceFilePath);
  };

};
