/*
 * Project: e-Dec Example Code
 * (C) 2017 Bundesamt fuer Informatik und Telekommunikation, CH
 */
package ch.admin.bit.edec.examples.ws;

import ch.admin.bit.edec.examples.PropertyProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

/**
 * This class represents a custom soap request.<p/>
 * NOTE: The SOAP Message is sent via a raw HTTP AbstractRequest. No additional XML- Support is used because
 * this sampler has to be able to send invalid and malformed messages!<br>
 */
public class SOAPRequest {
  private static final long serialVersionUID = 99887733;
  private static final Log log = LogFactory.getLog(HttpsRequest.class);

  // Variables for connection, request, response
  private Writer wr = null;
  private BufferedReader rd = null;
  private HttpURLConnection connection = null;
  private HttpsURLConnection sslConnection = null;

  private String formatedResponse = "";
  private URLConnection uc = null;

  /**
   * This class provides functionality to send a SOAP request to a webservice. It does not distinguish between
   * HTTP and HTTPS.
   * @param params The connection parameters used for the request
   * @return A response as text or <i>null</i> if an error occurred.
   */
  public String sendRequest(ConnectionParams params) {
    String response = null;

    try {
      // construct URL form parameters
      URL url = null;
      try {
        url = getUrl(params);
      }
      catch (MalformedURLException e) {
        log.error("Couldn't open a connection! " + e.getMessage());
      }
      params.setUrl(url);

      // select protocol
      if (params.getProtocol().toLowerCase().equals("http")) {
        // we are doing HTTP
        log.info("HTTP");
        HttpRequest.doRequest(params);
      }
      else {
        // we are doing HTTPS
        log.info("HTTPS");

        // set additional parameters needed for SSL/HTTPS
        SslConnectionParams sslConnectionParams = new SslConnectionParams(params);
        sslConnectionParams.setKeystorePath(PropertyProvider.getProperty(PropertyProvider.PROP_KEYSTORE_PATH));
        sslConnectionParams.setKeystorePassword(PropertyProvider.getProperty(PropertyProvider.PROP_KEYSTORE_PASSWORD));
        sslConnectionParams.setTruststorePath(PropertyProvider.getProperty(PropertyProvider.PROP_TRUSTSTORE_PATH));
        sslConnectionParams
            .setTruststorePassword(PropertyProvider.getProperty(PropertyProvider.PROP_TRUSTSTORE_PASSWORD));
        sslConnectionParams.setIdentityPassword(PropertyProvider.getProperty(PropertyProvider.PROP_IDENTITY_PASSWORD));

        // do the request
        response = HttpsRequest.doRequest(sslConnectionParams);
      }

      if (null != response) {
        log.debug("Response received [size=" + response.length() + "]");
      }
      else {
        log.debug("No response received!");
      }
    }
    catch (IOException ioe) {
      log.error("AbstractRequest failed! " + ioe.getMessage());
      log.debug("Received IOException:" + AbstractRequest.SEP + "Exception Message: " + ioe.getMessage());
    }

    return response;
  }

  /**
   * Get the URL, built from its component parts.
   *
   * @return The URL to be requested by this sampler.
   * @throws MalformedURLException
   */
  private static URL getUrl(ConnectionParams params) throws MalformedURLException {
    StringBuilder pathAndQuery = new StringBuilder();
    String path = params.getPath();
    if (!path.startsWith("/")) {
      pathAndQuery.append("/");
    }
    pathAndQuery.append(path);

    String protocol = params.getProtocol();
    String server = params.getHost();
    int port = 0;
    try {
      port = params.getPort();
    }
    catch (NumberFormatException e) {
      log.error("invalid port argument: " + e.getMessage() + AbstractRequest.SEP + " Using default port 80.");
      port = 80;
    }

    return new URL(protocol, server, port, pathAndQuery.toString());
  }
}
