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

package io.netty.channel;

import io.netty.util.internal.MacAddressUtil;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLoggerFactory;
import io.netty.buffer.ByteBufUtil;
import java.util.Arrays;
import io.netty.util.internal.EmptyArrays;
import java.lang.reflect.Method;
import io.netty.util.internal.PlatformDependent;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import io.netty.util.internal.logging.InternalLogger;

public final class DefaultChannelId implements ChannelId
{
    private static final long serialVersionUID = 3884076183504074063L;
    private static final InternalLogger logger;
    private static final byte[] MACHINE_ID;
    private static final int PROCESS_ID_LEN = 4;
    private static final int PROCESS_ID;
    private static final int SEQUENCE_LEN = 4;
    private static final int TIMESTAMP_LEN = 8;
    private static final int RANDOM_LEN = 4;
    private static final AtomicInteger nextSequence;
    private final byte[] data;
    private final int hashCode;
    private transient String shortValue;
    private transient String longValue;
    
    public static DefaultChannelId newInstance() {
        return new DefaultChannelId(DefaultChannelId.MACHINE_ID, DefaultChannelId.PROCESS_ID, DefaultChannelId.nextSequence.getAndIncrement(), Long.reverse(System.nanoTime()) ^ System.currentTimeMillis(), ThreadLocalRandom.current().nextInt());
    }
    
    static int processHandlePid(final ClassLoader loader) {
        final int nilValue = -1;
        if (PlatformDependent.javaVersion() < 9) {
            return nilValue;
        }
        Long pid;
        try {
            final Class<?> processHandleImplType = Class.forName("java.lang.ProcessHandle", true, loader);
            final Method processHandleCurrent = processHandleImplType.getMethod("current", (Class<?>[])new Class[0]);
            final Object processHandleInstance = processHandleCurrent.invoke(null, new Object[0]);
            final Method processHandlePid = processHandleImplType.getMethod("pid", (Class<?>[])new Class[0]);
            pid = (Long)processHandlePid.invoke(processHandleInstance, new Object[0]);
        }
        catch (final Exception e) {
            DefaultChannelId.logger.debug("Could not invoke ProcessHandle.current().pid();", e);
            return nilValue;
        }
        if (pid > 2147483647L || pid < -2147483648L) {
            throw new IllegalStateException("Current process ID exceeds int range: " + pid);
        }
        return pid.intValue();
    }
    
    static int jmxPid(final ClassLoader loader) {
        String value;
        try {
            final Class<?> mgmtFactoryType = Class.forName("java.lang.management.ManagementFactory", true, loader);
            final Class<?> runtimeMxBeanType = Class.forName("java.lang.management.RuntimeMXBean", true, loader);
            final Method getRuntimeMXBean = mgmtFactoryType.getMethod("getRuntimeMXBean", EmptyArrays.EMPTY_CLASSES);
            final Object bean = getRuntimeMXBean.invoke(null, EmptyArrays.EMPTY_OBJECTS);
            final Method getName = runtimeMxBeanType.getMethod("getName", EmptyArrays.EMPTY_CLASSES);
            value = (String)getName.invoke(bean, EmptyArrays.EMPTY_OBJECTS);
        }
        catch (final Throwable t) {
            DefaultChannelId.logger.debug("Could not invoke ManagementFactory.getRuntimeMXBean().getName(); Android?", t);
            try {
                final Class<?> processType = Class.forName("android.os.Process", true, loader);
                final Method myPid = processType.getMethod("myPid", EmptyArrays.EMPTY_CLASSES);
                value = myPid.invoke(null, EmptyArrays.EMPTY_OBJECTS).toString();
            }
            catch (final Throwable t2) {
                DefaultChannelId.logger.debug("Could not invoke Process.myPid(); not Android?", t2);
                value = "";
            }
        }
        final int atIndex = value.indexOf(64);
        if (atIndex >= 0) {
            value = value.substring(0, atIndex);
        }
        int pid;
        try {
            pid = Integer.parseInt(value);
        }
        catch (final NumberFormatException e) {
            pid = -1;
        }
        if (pid < 0) {
            pid = ThreadLocalRandom.current().nextInt();
            DefaultChannelId.logger.warn("Failed to find the current process ID from '{}'; using a random value: {}", value, pid);
        }
        return pid;
    }
    
    static int defaultProcessId() {
        final ClassLoader loader = PlatformDependent.getClassLoader(DefaultChannelId.class);
        final int processId = processHandlePid(loader);
        if (processId != -1) {
            return processId;
        }
        return jmxPid(loader);
    }
    
    DefaultChannelId(final byte[] machineId, final int processId, final int sequence, final long timestamp, final int random) {
        final byte[] data = new byte[machineId.length + 4 + 4 + 8 + 4];
        int i = 0;
        System.arraycopy(machineId, 0, data, i, machineId.length);
        i += machineId.length;
        writeInt(data, i, processId);
        i += 4;
        writeInt(data, i, sequence);
        i += 4;
        writeLong(data, i, timestamp);
        i += 8;
        writeInt(data, i, random);
        i += 4;
        assert i == data.length;
        this.data = data;
        this.hashCode = Arrays.hashCode(data);
    }
    
    private static void writeInt(final byte[] data, final int i, final int value) {
        if (PlatformDependent.isUnaligned()) {
            PlatformDependent.putInt(data, i, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? value : Integer.reverseBytes(value));
            return;
        }
        data[i] = (byte)(value >>> 24);
        data[i + 1] = (byte)(value >>> 16);
        data[i + 2] = (byte)(value >>> 8);
        data[i + 3] = (byte)value;
    }
    
    private static void writeLong(final byte[] data, final int i, final long value) {
        if (PlatformDependent.isUnaligned()) {
            PlatformDependent.putLong(data, i, PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? value : Long.reverseBytes(value));
            return;
        }
        data[i] = (byte)(value >>> 56);
        data[i + 1] = (byte)(value >>> 48);
        data[i + 2] = (byte)(value >>> 40);
        data[i + 3] = (byte)(value >>> 32);
        data[i + 4] = (byte)(value >>> 24);
        data[i + 5] = (byte)(value >>> 16);
        data[i + 6] = (byte)(value >>> 8);
        data[i + 7] = (byte)value;
    }
    
    @Override
    public String asShortText() {
        String shortValue = this.shortValue;
        if (shortValue == null) {
            shortValue = (this.shortValue = ByteBufUtil.hexDump(this.data, this.data.length - 4, 4));
        }
        return shortValue;
    }
    
    @Override
    public String asLongText() {
        String longValue = this.longValue;
        if (longValue == null) {
            longValue = (this.longValue = this.newLongValue());
        }
        return longValue;
    }
    
    private String newLongValue() {
        final StringBuilder buf = new StringBuilder(2 * this.data.length + 5);
        final int machineIdLen = this.data.length - 4 - 4 - 8 - 4;
        int i = 0;
        i = this.appendHexDumpField(buf, i, machineIdLen);
        i = this.appendHexDumpField(buf, i, 4);
        i = this.appendHexDumpField(buf, i, 4);
        i = this.appendHexDumpField(buf, i, 8);
        i = this.appendHexDumpField(buf, i, 4);
        assert i == this.data.length;
        return buf.substring();
    }
    
    private int appendHexDumpField(final StringBuilder buf, int i, final int length) {
        buf.append(ByteBufUtil.hexDump(this.data, i, length));
        buf.append('-');
        i += length;
        return i;
    }
    
    @Override
    public int hashCode() {
        return this.hashCode;
    }
    
    @Override
    public int compareTo(final ChannelId o) {
        if (this == o) {
            return 0;
        }
        if (o instanceof DefaultChannelId) {
            final byte[] otherData = ((DefaultChannelId)o).data;
            final int len1 = this.data.length;
            final int len2 = otherData.length;
            for (int len3 = Math.min(len1, len2), k = 0; k < len3; ++k) {
                final byte x = this.data[k];
                final byte y = otherData[k];
                if (x != y) {
                    return (x & 0xFF) - (y & 0xFF);
                }
            }
            return len1 - len2;
        }
        return this.asLongText().compareTo(o.asLongText());
    }
    
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof DefaultChannelId)) {
            return false;
        }
        final DefaultChannelId other = (DefaultChannelId)obj;
        return this.hashCode == other.hashCode && Arrays.equals(this.data, other.data);
    }
    
    @Override
    public String toString() {
        return this.asShortText();
    }
    
    static {
        logger = InternalLoggerFactory.getInstance(DefaultChannelId.class);
        nextSequence = new AtomicInteger();
        int processId = -1;
        final String customProcessId = SystemPropertyUtil.get("io.netty.processId");
        if (customProcessId != null) {
            try {
                processId = Integer.parseInt(customProcessId);
            }
            catch (final NumberFormatException ex) {}
            if (processId < 0) {
                processId = -1;
                DefaultChannelId.logger.warn("-Dio.netty.processId: {} (malformed)", customProcessId);
            }
            else if (DefaultChannelId.logger.isDebugEnabled()) {
                DefaultChannelId.logger.debug("-Dio.netty.processId: {} (user-set)", (Object)processId);
            }
        }
        if (processId < 0) {
            processId = defaultProcessId();
            if (DefaultChannelId.logger.isDebugEnabled()) {
                DefaultChannelId.logger.debug("-Dio.netty.processId: {} (auto-detected)", (Object)processId);
            }
        }
        PROCESS_ID = processId;
        byte[] machineId = null;
        final String customMachineId = SystemPropertyUtil.get("io.netty.machineId");
        if (customMachineId != null) {
            try {
                machineId = MacAddressUtil.parseMAC(customMachineId);
            }
            catch (final Exception e) {
                DefaultChannelId.logger.warn("-Dio.netty.machineId: {} (malformed)", customMachineId, e);
            }
            if (machineId != null) {
                DefaultChannelId.logger.debug("-Dio.netty.machineId: {} (user-set)", customMachineId);
            }
        }
        if (machineId == null) {
            machineId = MacAddressUtil.defaultMachineId();
            if (DefaultChannelId.logger.isDebugEnabled()) {
                DefaultChannelId.logger.debug("-Dio.netty.machineId: {} (auto-detected)", MacAddressUtil.formatAddress(machineId));
            }
        }
        MACHINE_ID = machineId;
    }
}
