// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.metrics;

import com.hypixel.hytale.codec.codecs.array.ArrayCodec;
import java.util.function.Supplier;
import com.hypixel.hytale.codec.codecs.map.MapCodec;
import java.util.HashMap;
import com.hypixel.hytale.codec.codecs.EnumCodec;
import java.lang.management.MemoryType;
import java.util.function.Function;
import java.lang.management.MemoryManagerMXBean;
import com.hypixel.hytale.codec.Codec;
import java.lang.management.OperatingSystemMXBean;
import java.time.Instant;
import java.time.Duration;
import java.lang.management.RuntimeMXBean;
import java.lang.management.MemoryMXBean;
import java.util.Iterator;
import java.util.Map;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.lang.management.ManagementFactory;
import java.lang.management.ClassLoadingMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.MemoryUsage;
import javax.annotation.Nonnull;

public class JVMMetrics
{
    @Nonnull
    public static final MetricsRegistry<ClassLoader> CLASS_LOADER_METRICS_REGISTRY;
    @Nonnull
    public static final MetricsRegistry<MemoryUsage> MEMORY_USAGE_METRICS_REGISTRY;
    @Nonnull
    public static final MetricsRegistry<GarbageCollectorMXBean> GARBAGE_COLLECTOR_METRICS_REGISTRY;
    @Nonnull
    public static final MetricsRegistry<MemoryPoolMXBean> MEMORY_POOL_METRICS_REGISTRY;
    @Nonnull
    public static final MetricsRegistry<Void> METRICS_REGISTRY;
    
    static {
        (CLASS_LOADER_METRICS_REGISTRY = new MetricsRegistry<ClassLoader>()).register("Name", ClassLoader::getName, Codec.STRING);
        JVMMetrics.CLASS_LOADER_METRICS_REGISTRY.register("Parent", ClassLoader::getParent, JVMMetrics.CLASS_LOADER_METRICS_REGISTRY);
        (MEMORY_USAGE_METRICS_REGISTRY = new MetricsRegistry<MemoryUsage>()).register("Init", MemoryUsage::getInit, Codec.LONG);
        JVMMetrics.MEMORY_USAGE_METRICS_REGISTRY.register("Used", MemoryUsage::getUsed, Codec.LONG);
        JVMMetrics.MEMORY_USAGE_METRICS_REGISTRY.register("Committed", MemoryUsage::getCommitted, Codec.LONG);
        JVMMetrics.MEMORY_USAGE_METRICS_REGISTRY.register("Max", MemoryUsage::getMax, Codec.LONG);
        (GARBAGE_COLLECTOR_METRICS_REGISTRY = new MetricsRegistry<GarbageCollectorMXBean>()).register("Name", MemoryManagerMXBean::getName, Codec.STRING);
        JVMMetrics.GARBAGE_COLLECTOR_METRICS_REGISTRY.register("MemoryPoolNames", (Function<GarbageCollectorMXBean, Object>)MemoryManagerMXBean::getMemoryPoolNames, (Codec<Object>)Codec.STRING_ARRAY);
        JVMMetrics.GARBAGE_COLLECTOR_METRICS_REGISTRY.register("CollectionCount", GarbageCollectorMXBean::getCollectionCount, Codec.LONG);
        JVMMetrics.GARBAGE_COLLECTOR_METRICS_REGISTRY.register("CollectionTime", GarbageCollectorMXBean::getCollectionTime, Codec.LONG);
        (MEMORY_POOL_METRICS_REGISTRY = new MetricsRegistry<MemoryPoolMXBean>()).register("Name", MemoryPoolMXBean::getName, Codec.STRING);
        JVMMetrics.MEMORY_POOL_METRICS_REGISTRY.register("Type", (Function<MemoryPoolMXBean, Object>)MemoryPoolMXBean::getType, new EnumCodec<Object>((Class<Object>)MemoryType.class));
        JVMMetrics.MEMORY_POOL_METRICS_REGISTRY.register("PeakUsage", MemoryPoolMXBean::getPeakUsage, JVMMetrics.MEMORY_USAGE_METRICS_REGISTRY);
        JVMMetrics.MEMORY_POOL_METRICS_REGISTRY.register("Usage", MemoryPoolMXBean::getUsage, JVMMetrics.MEMORY_USAGE_METRICS_REGISTRY);
        JVMMetrics.MEMORY_POOL_METRICS_REGISTRY.register("CollectionUsage", MemoryPoolMXBean::getCollectionUsage, JVMMetrics.MEMORY_USAGE_METRICS_REGISTRY);
        final MetricsRegistry<MemoryPoolMXBean> usageThreshold = new MetricsRegistry<MemoryPoolMXBean>();
        usageThreshold.register("Threshold", MemoryPoolMXBean::getUsageThreshold, Codec.LONG);
        usageThreshold.register("ThresholdCount", MemoryPoolMXBean::getUsageThresholdCount, Codec.LONG);
        usageThreshold.register("ThresholdExceeded", MemoryPoolMXBean::isUsageThresholdExceeded, Codec.BOOLEAN);
        JVMMetrics.MEMORY_POOL_METRICS_REGISTRY.register("UsageThreshold", memoryPoolMXBean -> {
            if (!memoryPoolMXBean.isUsageThresholdSupported()) {
                return null;
            }
            else {
                return memoryPoolMXBean;
            }
        }, usageThreshold);
        final MetricsRegistry<MemoryPoolMXBean> collectionUsageThreshold = new MetricsRegistry<MemoryPoolMXBean>();
        collectionUsageThreshold.register("Threshold", MemoryPoolMXBean::getCollectionUsageThreshold, Codec.LONG);
        collectionUsageThreshold.register("ThresholdCount", MemoryPoolMXBean::getCollectionUsageThresholdCount, Codec.LONG);
        collectionUsageThreshold.register("ThresholdExceeded", MemoryPoolMXBean::isCollectionUsageThresholdExceeded, Codec.BOOLEAN);
        JVMMetrics.MEMORY_POOL_METRICS_REGISTRY.register("CollectionUsageThreshold", memoryPoolMXBean -> {
            if (!memoryPoolMXBean.isCollectionUsageThresholdSupported()) {
                return null;
            }
            else {
                return memoryPoolMXBean;
            }
        }, collectionUsageThreshold);
        METRICS_REGISTRY = new MetricsRegistry<Void>();
        final MetricsRegistry<OperatingSystemMXBean> operatingSystem = new MetricsRegistry<OperatingSystemMXBean>();
        JVMMetrics.METRICS_REGISTRY.register("PROCESSOR", unused -> System.getenv("PROCESSOR_IDENTIFIER"), (Codec<String>)Codec.STRING);
        JVMMetrics.METRICS_REGISTRY.register("PROCESSOR_ARCHITECTURE", unused -> System.getenv("PROCESSOR_ARCHITECTURE"), (Codec<String>)Codec.STRING);
        JVMMetrics.METRICS_REGISTRY.register("PROCESSOR_ARCHITEW6432", unused -> System.getenv("PROCESSOR_ARCHITEW6432"), (Codec<String>)Codec.STRING);
        operatingSystem.register("OSName", OperatingSystemMXBean::getName, Codec.STRING);
        operatingSystem.register("OSArch", OperatingSystemMXBean::getArch, Codec.STRING);
        operatingSystem.register("OSVersion", OperatingSystemMXBean::getVersion, Codec.STRING);
        operatingSystem.register("AvailableProcessors", unused -> Runtime.getRuntime().availableProcessors(), (Codec<Integer>)Codec.INTEGER);
        operatingSystem.register("SystemLoadAverage", OperatingSystemMXBean::getSystemLoadAverage, Codec.DOUBLE);
        if (ManagementFactory.getOperatingSystemMXBean() instanceof com.sun.management.OperatingSystemMXBean) {
            operatingSystem.register("CpuLoad", operatingSystemMXBean -> ((com.sun.management.OperatingSystemMXBean)operatingSystemMXBean).getCpuLoad(), (Codec<Double>)Codec.DOUBLE);
            operatingSystem.register("ProcessCpuLoad", operatingSystemMXBean -> ((com.sun.management.OperatingSystemMXBean)operatingSystemMXBean).getProcessCpuLoad(), (Codec<Double>)Codec.DOUBLE);
            operatingSystem.register("TotalMemorySize", operatingSystemMXBean -> ((com.sun.management.OperatingSystemMXBean)operatingSystemMXBean).getTotalMemorySize(), (Codec<Long>)Codec.LONG);
            operatingSystem.register("FreeMemorySize", operatingSystemMXBean -> ((com.sun.management.OperatingSystemMXBean)operatingSystemMXBean).getFreeMemorySize(), (Codec<Long>)Codec.LONG);
            operatingSystem.register("TotalSwapSpaceSize", operatingSystemMXBean -> ((com.sun.management.OperatingSystemMXBean)operatingSystemMXBean).getTotalSwapSpaceSize(), (Codec<Long>)Codec.LONG);
            operatingSystem.register("FreeSwapSpaceSize", operatingSystemMXBean -> ((com.sun.management.OperatingSystemMXBean)operatingSystemMXBean).getFreeSwapSpaceSize(), (Codec<Long>)Codec.LONG);
        }
        JVMMetrics.METRICS_REGISTRY.register("System", aVoid -> ManagementFactory.getOperatingSystemMXBean(), (Codec<OperatingSystemMXBean>)operatingSystem);
        final MetricsRegistry<RuntimeMXBean> runtimeBean = new MetricsRegistry<RuntimeMXBean>();
        runtimeBean.register("StartTime", runtimeMXBean -> Instant.ofEpochMilli(runtimeMXBean.getStartTime()), (Codec<Instant>)Codec.INSTANT);
        runtimeBean.register("Uptime", runtimeMXBean -> Duration.ofMillis(runtimeMXBean.getUptime()), (Codec<Duration>)Codec.DURATION);
        runtimeBean.register("RuntimeName", RuntimeMXBean::getName, Codec.STRING);
        runtimeBean.register("SpecName", RuntimeMXBean::getSpecName, Codec.STRING);
        runtimeBean.register("SpecVendor", RuntimeMXBean::getSpecVendor, Codec.STRING);
        runtimeBean.register("SpecVersion", RuntimeMXBean::getSpecVersion, Codec.STRING);
        runtimeBean.register("ManagementSpecVersion", RuntimeMXBean::getManagementSpecVersion, Codec.STRING);
        runtimeBean.register("VMName", RuntimeMXBean::getVmName, Codec.STRING);
        runtimeBean.register("VMVendor", RuntimeMXBean::getVmVendor, Codec.STRING);
        runtimeBean.register("VMVersion", RuntimeMXBean::getVmVersion, Codec.STRING);
        runtimeBean.register("LibraryPath", RuntimeMXBean::getLibraryPath, Codec.STRING);
        try {
            ManagementFactory.getRuntimeMXBean().getBootClassPath();
            runtimeBean.register("BootClassPath", RuntimeMXBean::getBootClassPath, Codec.STRING);
        }
        catch (final UnsupportedOperationException ex) {}
        runtimeBean.register("ClassPath", RuntimeMXBean::getClassPath, Codec.STRING);
        runtimeBean.register("InputArguments", runtimeMXBean -> runtimeMXBean.getInputArguments().toArray(String[]::new), (Codec<Object>)Codec.STRING_ARRAY);
        runtimeBean.register("SystemProperties", RuntimeMXBean::getSystemProperties, (Codec<Map>)new MapCodec((Codec<Object>)Codec.STRING, (Supplier<Map>)HashMap::new));
        JVMMetrics.METRICS_REGISTRY.register("Runtime", aVoid -> ManagementFactory.getRuntimeMXBean(), (Codec<RuntimeMXBean>)runtimeBean);
        final MetricsRegistry<MemoryMXBean> memoryBean = new MetricsRegistry<MemoryMXBean>();
        memoryBean.register("ObjectPendingFinalizationCount", memoryMXBean -> memoryMXBean.getObjectPendingFinalizationCount(), (Codec<Integer>)Codec.INTEGER);
        memoryBean.register("HeapMemoryUsage", memoryMXBean -> memoryMXBean.getHeapMemoryUsage(), (Codec<MemoryUsage>)JVMMetrics.MEMORY_USAGE_METRICS_REGISTRY);
        memoryBean.register("NonHeapMemoryUsage", memoryMXBean -> memoryMXBean.getNonHeapMemoryUsage(), (Codec<MemoryUsage>)JVMMetrics.MEMORY_USAGE_METRICS_REGISTRY);
        JVMMetrics.METRICS_REGISTRY.register("Memory", aVoid -> ManagementFactory.getMemoryMXBean(), (Codec<MemoryMXBean>)memoryBean);
        JVMMetrics.METRICS_REGISTRY.register("GarbageCollectors", memoryMXBean -> ManagementFactory.getGarbageCollectorMXBeans().toArray(GarbageCollectorMXBean[]::new), (Codec<Object>)new ArrayCodec((Codec<Object>)JVMMetrics.GARBAGE_COLLECTOR_METRICS_REGISTRY, GarbageCollectorMXBean[]::new));
        JVMMetrics.METRICS_REGISTRY.register("MemoryPools", memoryMXBean -> ManagementFactory.getMemoryPoolMXBeans().toArray(MemoryPoolMXBean[]::new), (Codec<Object>)new ArrayCodec((Codec<Object>)JVMMetrics.MEMORY_POOL_METRICS_REGISTRY, MemoryPoolMXBean[]::new));
        JVMMetrics.METRICS_REGISTRY.register("Threads", aVoid -> {
            final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
            final ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
            final Map<Thread, StackTraceElement[]> stackTraces = Thread.getAllStackTraces();
            final Long2ObjectOpenHashMap<Thread> threadIdMap = new Long2ObjectOpenHashMap<Thread>();
            for (final Thread thread : stackTraces.keySet()) {
                threadIdMap.put(thread.getId(), thread);
            }
            final ThreadMetricData[] data = new ThreadMetricData[threadInfos.length];
            for (int i = 0; i < threadInfos.length; ++i) {
                final ThreadInfo threadInfo = threadInfos[i];
                data[i] = new ThreadMetricData(threadInfo, threadIdMap.get(threadInfo.getThreadId()), threadMXBean);
            }
            return data;
        }, (Codec<Object>)new ArrayCodec((Codec<Object>)ThreadMetricData.METRICS_REGISTRY, ThreadMetricData[]::new));
        JVMMetrics.METRICS_REGISTRY.register("SecurityManager", aVoid -> {
            final SecurityManager securityManager = System.getSecurityManager();
            return (securityManager == null) ? null : securityManager.getClass().getName();
        }, (Codec<String>)Codec.STRING);
        final MetricsRegistry<ClassLoadingMXBean> classLoading = new MetricsRegistry<ClassLoadingMXBean>();
        classLoading.register("LoadedClassCount", ClassLoadingMXBean::getLoadedClassCount, Codec.INTEGER);
        classLoading.register("UnloadedClassCount", ClassLoadingMXBean::getUnloadedClassCount, Codec.LONG);
        classLoading.register("TotalLoadedClassCount", ClassLoadingMXBean::getTotalLoadedClassCount, Codec.LONG);
        classLoading.register("SystemClassloader", unused -> ClassLoader.getSystemClassLoader(), (Codec<ClassLoader>)JVMMetrics.CLASS_LOADER_METRICS_REGISTRY);
        classLoading.register("JVMMetricsClassloader", unused -> JVMMetrics.class.getClassLoader(), (Codec<ClassLoader>)JVMMetrics.CLASS_LOADER_METRICS_REGISTRY);
        JVMMetrics.METRICS_REGISTRY.register("ClassLoading", aVoid -> ManagementFactory.getClassLoadingMXBean(), (Codec<ClassLoadingMXBean>)classLoading);
    }
    
    private static class ThreadMetricData
    {
        @Nonnull
        public static final MetricsRegistry<StackTraceElement> STACK_TRACE_ELEMENT_METRICS_REGISTRY;
        @Nonnull
        public static final MetricsRegistry<ThreadMetricData> METRICS_REGISTRY;
        private final ThreadInfo threadInfo;
        private final Thread thread;
        private final ThreadMXBean threadMXBean;
        
        public ThreadMetricData(final ThreadInfo threadInfo, final Thread thread, final ThreadMXBean threadMXBean) {
            this.threadInfo = threadInfo;
            this.thread = thread;
            this.threadMXBean = threadMXBean;
        }
        
        static {
            (STACK_TRACE_ELEMENT_METRICS_REGISTRY = new MetricsRegistry<StackTraceElement>()).register("FileName", StackTraceElement::getFileName, Codec.STRING);
            ThreadMetricData.STACK_TRACE_ELEMENT_METRICS_REGISTRY.register("LineNumber", StackTraceElement::getLineNumber, Codec.INTEGER);
            ThreadMetricData.STACK_TRACE_ELEMENT_METRICS_REGISTRY.register("ModuleName", StackTraceElement::getModuleName, Codec.STRING);
            ThreadMetricData.STACK_TRACE_ELEMENT_METRICS_REGISTRY.register("ModuleVersion", StackTraceElement::getModuleVersion, Codec.STRING);
            ThreadMetricData.STACK_TRACE_ELEMENT_METRICS_REGISTRY.register("ClassLoaderName", StackTraceElement::getClassLoaderName, Codec.STRING);
            ThreadMetricData.STACK_TRACE_ELEMENT_METRICS_REGISTRY.register("ClassName", StackTraceElement::getClassName, Codec.STRING);
            ThreadMetricData.STACK_TRACE_ELEMENT_METRICS_REGISTRY.register("MethodName", StackTraceElement::getMethodName, Codec.STRING);
            (METRICS_REGISTRY = new MetricsRegistry<ThreadMetricData>()).register("Id", threadMetricData -> threadMetricData.threadInfo.getThreadId(), Codec.LONG);
            ThreadMetricData.METRICS_REGISTRY.register("Name", threadMetricData -> threadMetricData.threadInfo.getThreadName(), (Codec<String>)Codec.STRING);
            ThreadMetricData.METRICS_REGISTRY.register("State", threadMetricData -> threadMetricData.threadInfo.getThreadState(), (Codec<Object>)new EnumCodec<Object>((Class<Object>)Thread.State.class));
            ThreadMetricData.METRICS_REGISTRY.register("Priority", threadMetricData -> threadMetricData.threadInfo.getPriority(), (Codec<Integer>)Codec.INTEGER);
            ThreadMetricData.METRICS_REGISTRY.register("Daemon", threadMetricData -> threadMetricData.threadInfo.isDaemon(), (Codec<Boolean>)Codec.BOOLEAN);
            ThreadMetricData.METRICS_REGISTRY.register("CPUTime", threadMetricData -> threadMetricData.threadMXBean.getThreadCpuTime(threadMetricData.threadInfo.getThreadId()), (Codec<Long>)Codec.LONG);
            ThreadMetricData.METRICS_REGISTRY.register("WaitedTime", threadMetricData -> threadMetricData.threadInfo.getWaitedTime(), (Codec<Long>)Codec.LONG);
            ThreadMetricData.METRICS_REGISTRY.register("WaitedCount", threadMetricData -> threadMetricData.threadInfo.getWaitedCount(), (Codec<Long>)Codec.LONG);
            ThreadMetricData.METRICS_REGISTRY.register("BlockedTime", threadMetricData -> threadMetricData.threadInfo.getBlockedTime(), (Codec<Long>)Codec.LONG);
            ThreadMetricData.METRICS_REGISTRY.register("BlockedCount", threadMetricData -> threadMetricData.threadInfo.getBlockedCount(), (Codec<Long>)Codec.LONG);
            ThreadMetricData.METRICS_REGISTRY.register("LockName", threadMetricData -> threadMetricData.threadInfo.getLockName(), (Codec<String>)Codec.STRING);
            ThreadMetricData.METRICS_REGISTRY.register("LockOwnerId", threadMetricData -> threadMetricData.threadInfo.getLockOwnerId(), (Codec<Long>)Codec.LONG);
            ThreadMetricData.METRICS_REGISTRY.register("LockOwnerName", threadMetricData -> threadMetricData.threadInfo.getLockOwnerName(), (Codec<String>)Codec.STRING);
            ThreadMetricData.METRICS_REGISTRY.register("StackTrace", threadMetricData -> threadMetricData.threadInfo.getStackTrace(), (Codec<Object>)new ArrayCodec((Codec<Object>)ThreadMetricData.STACK_TRACE_ELEMENT_METRICS_REGISTRY, StackTraceElement[]::new));
            ThreadMetricData.METRICS_REGISTRY.register("InitStackTrace", threadMetricData -> (threadMetricData.thread instanceof InitStackThread) ? ((InitStackThread)threadMetricData.thread).getInitStack() : null, (Codec<Object>)new ArrayCodec((Codec<Object>)ThreadMetricData.STACK_TRACE_ELEMENT_METRICS_REGISTRY, StackTraceElement[]::new));
            ThreadMetricData.METRICS_REGISTRY.register("Interrupted", threadMetricData -> (threadMetricData.thread != null) ? Boolean.valueOf(threadMetricData.thread.isInterrupted()) : null, (Codec<Boolean>)Codec.BOOLEAN);
            ThreadMetricData.METRICS_REGISTRY.register("ThreadClass", threadMetricData -> (threadMetricData.thread != null) ? threadMetricData.thread.getClass().getName() : null, (Codec<String>)Codec.STRING);
            final MetricsRegistry<ThreadGroup> threadGroup = new MetricsRegistry<ThreadGroup>();
            threadGroup.register("Name", ThreadGroup::getName, Codec.STRING);
            threadGroup.register("Parent", ThreadGroup::getParent, threadGroup);
            threadGroup.register("MaxPriority", ThreadGroup::getMaxPriority, Codec.INTEGER);
            threadGroup.register("Destroyed", ThreadGroup::isDestroyed, Codec.BOOLEAN);
            threadGroup.register("Daemon", ThreadGroup::isDaemon, Codec.BOOLEAN);
            threadGroup.register("ActiveCount", ThreadGroup::activeCount, Codec.INTEGER);
            threadGroup.register("ActiveGroupCount", ThreadGroup::activeGroupCount, Codec.INTEGER);
            ThreadMetricData.METRICS_REGISTRY.register("ThreadGroup", threadMetricData -> (threadMetricData.thread != null) ? threadMetricData.thread.getThreadGroup() : null, (Codec<ThreadGroup>)threadGroup);
            ThreadMetricData.METRICS_REGISTRY.register("UncaughtExceptionHandler", threadMetricData -> (threadMetricData.thread != null) ? threadMetricData.thread.getUncaughtExceptionHandler().getClass().getName() : null, (Codec<String>)Codec.STRING);
        }
    }
}
