package de.ivu.elect.business.system.control;

import java.io.IOException;
import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.util.Set;

import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.ReflectionException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import static java.lang.Boolean.TRUE;

/**
 *  on 24.05.2017.
 */
public class WildFlyServer implements Serializable {

  private static final Logger LOG = LoggerFactory.getLogger(WildFlyServer.class);
  private static final String IS_THORNTAIL_PROPERTY_KEY = "application.is-thorntail";

  private static final long serialVersionUID = 1L;

  public static final String HTTP_LISTENER = "jboss.as:subsystem=undertow,server=default-server,http-listener=default";

  public static final String HTTPS_LISTENER = "jboss.as:subsystem=undertow,server=default-server,https-listener=https";


  public static final String AJP_LISTENER = "jboss.as:subsystem=undertow,server=default-server,ajp-listener=default-ajp";

  @Inject
  transient DatasourceJndiResolver datasourceJndiResolver;

  public static boolean isThorntail() {
    // HINT, any thorntail application should set this property in its project-defaults.yml
    return TRUE.toString().equalsIgnoreCase(System.getProperty(IS_THORNTAIL_PROPERTY_KEY));
  }

  public int getDefaultTransactionTimeout() {
    // listWildFlyMBeans();
    Object value = getAttribut("jboss.as:subsystem=transactions", "defaultTimeout");
    if (value == null) {
      return 0;
    }
    return (Integer) value;
  }

  public long getHttpMaxPostSize() {
    Object value = getAttribut(HTTP_LISTENER, "maxPostSize");
    if (value == null) {
      return 0;
    }
    return (long) value;
  }

  public int getHttpMaxParameters() {
    Object value = getAttribut(HTTP_LISTENER, "maxParameters");
    if (value == null) {
      return 0;
    }
    return (int) value;
  }

  public long getHttpsMaxPostSize() {
    Object value = getAttribut(HTTPS_LISTENER, "maxPostSize");
    if (value == null) {
      return 0;
    }
    return (long) value;
  }

  public int getHttpsMaxParameters() {
    Object value = getAttribut(HTTPS_LISTENER, "maxParameters");
    if (value == null) {
      return 0;
    }
    return (int) value;
  }

  public boolean isHttpsHttp2Enabled() {
    Object value = getAttribut(HTTPS_LISTENER, "enable-http2");
    if (value == null) {
      return false;
    }
    return Boolean.TRUE.equals(value);
  }

  public boolean isHttpsHttp2PushEnabled() {
    Object value = getAttribut(HTTPS_LISTENER, "http2-enable-push");
    if (value == null) {
      return false;
    }
    return Boolean.TRUE.equals(value);
  }

  public boolean isHttpHttp2Enabled() {
    Object value = getAttribut(HTTP_LISTENER, "enable-http2");
    if (value == null) {
      return false;
    }
    return Boolean.TRUE.equals(value);
  }

  public boolean isHttpHttp2PushEnabled() {
    Object value = getAttribut(HTTP_LISTENER, "http2-enable-push");
    if (value == null) {
      return false;
    }
    return Boolean.TRUE.equals(value);
  }


  public long getAjpHttpMaxPostSize() {
    Object value = getAttribut(AJP_LISTENER, "maxPostSize");
    if (value == null) {
      return 0;
    }
    return (long) value;
  }

  public int getAjpHttpMaxParameters() {
    Object value = getAttribut(AJP_LISTENER, "maxParameters");
    if (value == null) {
      return 0;
    }
    return (int) value;
  }

  @Nullable
  private Object getAttribut(String objectName, String attributName) {
    MBeanServerConnection mbeanServerConnection = ManagementFactory.getPlatformMBeanServer();
    try {
      return getAttribute(attributName, mbeanServerConnection, new ObjectName(objectName));
    } catch (Exception e) {
      // ELECT-7903
      LOG.warn("Keine HTTP-Connector defunden: " + objectName + ", " + attributName + ", " + e.getMessage());
      return null;
    }
  }

  public int getMaxPoolSize() {
    Object value = getDatasourceAttribute("maxPoolSize");
    if (value == null) {
      return 0;
    }
    return (int) value;
  }

  @Nullable
  protected Object getDatasourceAttribute(String attributName) {
    String dsJndiName = datasourceJndiResolver.getJndiName();
    try {
      MBeanServerConnection mbeanServerConnection = ManagementFactory.getPlatformMBeanServer();

      ObjectName serviceRef = new ObjectName("jboss.as:subsystem=datasources,data-source=*");
      Set<ObjectName> mbeans = mbeanServerConnection.queryNames(serviceRef, null);
      for (ObjectName on : mbeans) {
        if (dsJndiName.equals(gatDatasourceJndiName(mbeanServerConnection, on))) {
          return getAttribute(attributName, mbeanServerConnection, on);
        }
      }
      // ELECT-7903
      LOG.warn("Keine Datenbank gefunden: " + dsJndiName);
    } catch (Exception e) {
      // ELECT-7903
      LOG.warn("Keine Datenbank gefunden: " + dsJndiName + ", " + e.getMessage());
    }
    // ELECT-7903
    return null;
  }

  @Nullable
  private Object gatDatasourceJndiName(MBeanServerConnection mbeanServerConnection, ObjectName on) throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException, IOException {
    return getAttribute("jndiName", mbeanServerConnection, on);
  }

  @Nullable
  private Object getAttribute(String attributName, MBeanServerConnection mbeanServerConnection, ObjectName on) throws ReflectionException, MBeanException, InstanceNotFoundException, IOException {
    try {
      return mbeanServerConnection.getAttribute(on, attributName);
    } catch (AttributeNotFoundException e) {
      LOG.warn("Attribut nicht gefunden: '" + attributName + "', " + on);
      // WASDE-1062 Attribut nicht vorhanden? => null
      return null;
    }
  }

}
