XMIO = {};

var WEB_SERVICE_URL;
var INITIATOR;
var PASSWORD;

(function(){
  var javaPkgs = new JavaImporter(
      java.io.File,
      java.io.FileReader,
      com.alarmpoint.integrationagent.script.api,
      com.alarmpoint.integrationagent.security,
      com.alarmpoint.integrationagent.exceptions.retriable,
      com.alarmpoint.integrationagent.config.IAConfigImpl,
      com.alarmpoint.integrationagent.config.xml.IAConfigFileImpl
  );

  /**
  * Path to IA configuration file
  */
  XMIO.IA_CONFIG_FILE_PATH = "conf/IAConfig.xml";
  
  /**
  * If true, will automatically use the proxy configuration (if any) defined in the IAConfig.xml.
  * Requires an Integration Agent version that supports proxy configuration through IAConfig.xml.
  */
  XMIO.AUTOCONFIGURE_PROXY = true;

  with (javaPkgs) {
    var httpClient = new IntegrationServiceHttpClient();
    XMIO.http = httpClient;

    XMIO.decryptFile = function(path) {
      return EncryptionUtils.decrypt(new java.io.File(path));
    }

    XMIO.post = function(jsonStr, url, username, password, headers) {
      return execute('POST', jsonStr, url, username, password, headers);
    }

    XMIO.put = function(jsonStr, url, username, password, headers) {
      if (url === undefined) {
        throw 'The parameter "url" needs to be defined for the function "put".';
      }
      return execute('PUT', jsonStr, url, username, password, headers);
    }

    XMIO.patch = function(jsonStr, url, username, password, headers) {
      if (url === undefined) {
        throw 'The parameter "url" needs to be defined for the function "patch".';
      }
      return execute('PATCH', jsonStr, url, username, password, headers);
    }

    XMIO.get = function(url, username, password, headers) {
      if (url === undefined) {
        throw 'The parameter "url" needs to be defined for the function "get".';
      }
      return execute('GET', null, url, username, password, headers);
    }

    XMIO.delete = function(url, username, password, headers) {
      if (url === undefined) {
        throw 'The parameter "url" needs to be defined for the function "delete".';
      }
      return execute('DELETE', null, url, username, password, headers);
    }

    function execute(method, jsonStr, url, username, password, headers) {
      IALOG.debug("\tEntering XMIO.execute with method: {0}, jsonStr: {1}, and url: {2}", method, JSON.stringify(jsonStr), url );
      var urL = url === undefined ? WEB_SERVICE_URL : url,
            user = username === undefined ? INITIATOR : username,
            pwd = password === undefined ? XMIO.decryptFile(PASSWORD) : password;

      if ( XMIO.AUTOCONFIGURE_PROXY && XMIO.iaConfig == null )  {
        IALOG.debug("Reading configuration file: " + XMIO.IA_CONFIG_FILE_PATH);
        var configFile = new File(XMIO.IA_CONFIG_FILE_PATH);
        var iaConfigFile = new IAConfigFileImpl(new FileReader(configFile));
        XMIO.iaConfig = new IAConfigImpl(iaConfigFile, configFile.getParentFile(), configFile.toURI());
      }

      XMIO.http.setUrl(urL);

      if (user != null) {
        XMIO.http.setCredentials(user, pwd);
      }
      
      // Note: Proxy must be configured after credentials in order to support keeping the connection open
      // (See IntegrationServiceHttpClient setProxy)
      if (XMIO.AUTOCONFIGURE_PROXY && XMIO.iaConfig.getProxyConfig().isProxyEnabled()) {
        if (XMIO.proxyConfig == null) {
          IALOG.debug("Reading proxy configuration...");
          XMIO.proxyConfig = XMIO.iaConfig.getProxyConfig();
        }
        var proxyHost = XMIO.proxyConfig.getHost();
        var proxyPort = XMIO.proxyConfig.getPort(); 
        var proxyUsername = XMIO.proxyConfig.getUsername();
        var proxyPassword = XMIO.proxyConfig.getPassword(); 
        var proxyNtlmDomain = XMIO.proxyConfig.getNtlmDomain();
        IALOG.debug("Adding the following proxy parameters: {0}:{1} {2}/--masked-- {3}", proxyHost, proxyPort, proxyUsername, proxyNtlmDomain);
        XMIO.http.setProxy(proxyHost, proxyPort, proxyUsername, proxyPassword, proxyNtlmDomain);
      }

      if (headers === undefined) {
        if (method !== 'GET') {
          IALOG.debug("\t\tAdding default header {0}={1}", 'Content-Type', 'application/json');
          XMIO.http.addHeader('Content-Type', 'application/json');
        }
      } else if (headers != null) {
        for (header in headers) {
          IALOG.debug("\t\tAdding header {0}={1}", header, headers[header]);
          XMIO.http.addHeader(header, headers[header]);
        }
      }

      var resp;
      if (method === 'POST') {
        IALOG.debug("\t\tPOST to: {0} with payload: {1}", urL, JSON.stringify(jsonStr) );
        resp = XMIO.http.post(jsonStr);
      }
      else if (method === 'PUT') {
        IALOG.debug("\t\tPUT to: {0} with payload: {1}", urL, JSON.stringify(jsonStr) );
        resp = XMIO.http.put(jsonStr);
      }
      else if (method === 'GET') {
        IALOG.debug("\t\tGET from: {0}", urL);
        resp = XMIO.http.get();
      }
      else if (method === 'PATCH') {
        IALOG.debug("\t\tPATCH to: {0} with payload: {1}", urL, JSON.stringify(jsonStr) );
        resp = XMIO.http.patch(jsonStr);
      }
      else if (method === 'DELETE') {
        IALOG.debug("\t\tDELETE from: {0}", urL);
        resp = XMIO.http.delete();
      }

      var response = {};
      response.status = resp.getStatusLine().getStatusCode();
      response.body = XMIO.http.getResponseAsString(resp);
      XMIO.http.releaseConnection(resp);
      IALOG.info("\t\tReceived response code: {0} and payload: {1}", response.status, response.body);
      return response;
    }
  }
})();
