package lc.mecha.util;

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

import javax.management.*;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.text.DecimalFormat;

/**
 * Provide system resource logging.
 *
 * @author Alex Leigh
 */
public class RuntimeMonitor implements Runnable {
    private static final Logger logger = LoggerFactory.getLogger(RuntimeMonitor.class);
    private int SLEEP_INTERVAL_MS = 60 * 1000;
    private Runtime r = Runtime.getRuntime();
    private OperatingSystemMXBean osMBean;
    private AttributeList list;
    DecimalFormat df = new DecimalFormat("#.##");

    public RuntimeMonitor() throws IOException, MalformedObjectNameException, ReflectionException, InstanceNotFoundException {
        MBeanServerConnection mbsc = ManagementFactory.getPlatformMBeanServer();
        osMBean = ManagementFactory.newPlatformMXBeanProxy(mbsc,
                ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME,
                OperatingSystemMXBean.class);
        ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
        list = mbsc.getAttributes(name, new String[]{"ProcessCpuLoad"});
    }

    @Override
    public void run() {
        logger.debug("Runtime Monitor starting...");
        while (!Thread.currentThread().isInterrupted()) {
            try {
                log();
                Thread.sleep(SLEEP_INTERVAL_MS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
        }
    }

    public double getCpuPct() {
        if (list.isEmpty()) return Double.NaN;
        Attribute att = (Attribute) list.get(0);
        Double value = (Double) att.getValue();
        if (value == -1.0) return Double.NaN;
        return ((int) (value * 1000) / 10.0);
    }

    public void log() {
        // We don't use freeMemory() because it does not include the max size the VM can grow to, it reports
        // against its current size.

        logger.info("health: [mem_total: {}] [mem_max: {}] [mem_used: {}] [mem_free: {}] [cpus: {}] [os_load: {}] [cpu_pct: {}]",
                NumberUtil.humanByteSize(r.totalMemory()),
                NumberUtil.humanByteSize(r.maxMemory()),
                NumberUtil.humanByteSize(r.totalMemory() - r.freeMemory()),
                NumberUtil.humanByteSize(r.freeMemory()),
                r.availableProcessors(),
                df.format(osMBean.getSystemLoadAverage()),
                getCpuPct());
    }
}
