public class SnowcastMaxLogicalNodeIdOutOfBoundsException
        extends SnowcastException {

    /**
     * Basic exception constructor
     *
     * @param message message to be used
     */
    public SnowcastMaxLogicalNodeIdOutOfBoundsException(@Nonnull String message) {
        super(message);
    }
} @ThreadSafe
public final class SnowcastSequenceComparator
        implements Comparator<Long> {

    private final int maxLogicalNodeCount;

    /**
     * This constructor creates a new SnowcastSequenceComparator instance bound to the given
     * maximal logical node count.<br>
     * There is also a convenience method in {@link com.noctarius.snowcast.SnowcastSequenceUtils}
     * to easy the creation process when a {@link com.noctarius.snowcast.SnowcastSequencer} is
     * available:
     * <pre>
     *     SnowcastSequencer sequencer = getSnowcastSequencer();
     *     Comparator&lt;Long&gt; comparator = SnowcastSequenceUtils.snowcastSequenceComparator( sequencer );
     * </pre>
     *
     * @param maxLogicalNodeCount the maximal logical node count
     */
    public SnowcastSequenceComparator(@Min(128) @Max(8192) int maxLogicalNodeCount) {
        this.maxLogicalNodeCount = maxLogicalNodeCount;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int compare(@Nonnull Long sequenceId1, @Nonnull Long sequenceId2) {
        return SnowcastSequenceUtils.compareSequence(sequenceId1, sequenceId2, maxLogicalNodeCount);
    }
} @ThreadSafe
public interface SnowcastSequencer {

    /**
     * Returns the reference name of the sequencer. This name is shared in the Hazelcast
     * cluster. Whenever the same sequencer name is referenced when creating a
     * SnowcastSequencer the same internal sequencer instance is returned (unless destroyed).
     *
     * @return the sequencers reference name
     */
    @Nonnull
    String getSequencerName();

    /**
     * <p>Generates and returns the next snowcast sequence ID. This call blocks until a ID is
     * free to be generated. The call blocks whenever a millisecond on the current node runs
     * out of possible IDs by exceeding the maximum counter value.</p>
     * <p>This method is fully thread-safe and expected to be used in multi-threading
     * environments.</p>
     *
     * @return the next available snowcast sequence ID
     * @throws InterruptedException if the blocking wait is interrupted
     */
    long next()
            throws InterruptedException;

    /**
     * Returns the current {@link com.noctarius.snowcast.SnowcastSequenceState} of this
     * sequencer. It might be attached, detached or destroyed. Please refer to the state
     * documentations to find out more about their meanings.
     *
     * @return the sequencers current state
     */
    @Nonnull
    SnowcastSequenceState getSequencerState();

    /**
     * Attaches the current SnowcastSequencer instance to a logical node ID. This is
     * a cluster operation and blocks until the owner of the reference name assigns
     * a logical node ID and returns it back to the current node or client.
     *
     * @return the current SnowcastSequencer instance for chaining of method calls
     */
    @Nonnull
    SnowcastSequencer attachLogicalNode();

    /**
     * Detaches the current SnowcastSequencer instance from the currently assigned
     * logical node ID. This is a cluster operation and blocks until the owner of
     * the reference name removed the logical node ID assignment and returns back
     * to the current node or client.
     *
     * @return the current SnowcastSequencer instance for chaining of method calls
     */
    @Nonnull
    SnowcastSequencer detachLogicalNode();

    /**
     * Extracts the timestamp value of the given snowcast sequence ID based on the
     * current configuration. Extracted timestamps are based on the configured
     * {@link com.noctarius.snowcast.SnowcastEpoch}. To get the real world point in
     * time the epoch value plus this returned timestamp must be summed together.
     *
     * @param sequenceId the sequence ID to extract the timestamp from
     * @return the extracted timestamp based on the configured epoch
     */
    @Nonnegative
    long timestampValue(long sequenceId);

    /**
     * Extracts the logical node ID of the given snowcast sequence ID based on the
     * current configuration. The extracted logical node ID is based no the configured
     * maximal logical node ID (number of bits used).
     *
     * @param sequenceId the sequence ID to extract the logical node ID from
     * @return the extracted logical node ID based on the configured maximal logical node ID
     */
    @Nonnegative
    int logicalNodeId(long sequenceId);

    /**
     * Extracts the counter value of the given snowcast sequence ID based on the
     * current configuration. The extracted counter value is based no the configured
     * maximal logical node ID (number of bits used).
     *
     * @param sequenceId the sequence ID to extract the counter value from
     * @return the extracted counter value based on the configured maximal logical node ID
     */
    @Nonnegative
    int counterValue(long sequenceId);
} public static SnowcastException exception(ExceptionMessages exceptionMessage, Object... exceptionParameters) {
    return exception(SnowcastException::new, exceptionMessage, exceptionParameters);
} public static final long ID_TIMESTAMP_READ_MASK = 0xFFFFFFFFFF800000L; public static final int MAX_LOGICAL_NODE_COUNT_1024 = 1023; public static final int MAX_LOGICAL_NODE_COUNT_128 = 127; public static final int MAX_LOGICAL_NODE_COUNT_2048 = 2047; public static final int MAX_LOGICAL_NODE_COUNT_256 = 255; public static final int MAX_LOGICAL_NODE_COUNT_4096 = 4095; public static final int MAX_LOGICAL_NODE_COUNT_512 = 511; public static final int MAX_LOGICAL_NODE_COUNT_8192 = 8191; public static final int NODE_ID_LOWER_BOUND = 128; public static final int NODE_ID_UPPER_BOUND = 8192; public static final int SHIFT_LOGICAL_NODE_ID_1024 = 13; public static final int SHIFT_LOGICAL_NODE_ID_128 = 16; public static final int SHIFT_LOGICAL_NODE_ID_2048 = 12; public static final int SHIFT_LOGICAL_NODE_ID_256 = 15; public static final int SHIFT_LOGICAL_NODE_ID_4096 = 11; public static final int SHIFT_LOGICAL_NODE_ID_512 = 14; public static final int SHIFT_LOGICAL_NODE_ID_8192 = 10; public static final int SHIFT_TIMESTAMP = 23;
import com.hazelcast.instance.BuildInfo;
import com.hazelcast.instance.BuildInfoProvider;
import com.hazelcast.util.QuickMath;
import com.noctarius.snowcast.SnowcastMaxLogicalNodeIdOutOfBoundsException;
import com.noctarius.snowcast.SnowcastSequenceComparator;
import com.noctarius.snowcast.SnowcastSequencer;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import java.util.Comparator;
import static com.noctarius.snowcast.impl.ExceptionMessages.ILLEGAL_MAX_LOGICAL_NODE_COUNT;
import static com.noctarius.snowcast.impl.ExceptionMessages.ILLEGAL_MAX_LOGICAL_NODE_ID_BOUNDARY;
import static com.noctarius.snowcast.impl.ExceptionMessages.NEXT_ID_LARGER_THAN_ALLOWED_MAX_COUNTER;
import static com.noctarius.snowcast.impl.ExceptionUtils.exception;
import static com.noctarius.snowcast.impl.SnowcastConstants.ID_TIMESTAMP_READ_MASK;
import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_1024;
import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_128;
import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_2048;
import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_256;
import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_4096;
import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_512;
import static com.noctarius.snowcast.impl.SnowcastConstants.MAX_LOGICAL_NODE_COUNT_8192;
import static com.noctarius.snowcast.impl.SnowcastConstants.NODE_ID_LOWER_BOUND;
import static com.noctarius.snowcast.impl.SnowcastConstants.NODE_ID_UPPER_BOUND;
import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_1024;
import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_128;
import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_2048;
import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_256;
import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_4096;
import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_512;
import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_LOGICAL_NODE_ID_8192;
import static com.noctarius.snowcast.impl.SnowcastConstants.SHIFT_TIMESTAMP;
/*
 * Copyright (c) 2015-2017, Christoph Engelbert (aka noctarius) and
 * contributors. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.noctarius.snowcast.impl;




public final class InternalSequencerUtils {

    private InternalSequencerUtils() {
    }

    @Nonnull
    public static Comparator<Long> snowcastSequenceComparator(@Nonnull SnowcastSequencer sequencer) {
        SequencerDefinition definition = ((InternalSequencer) sequencer).getSequencerDefinition();
        return new SnowcastSequenceComparator(definition.getMaxLogicalNodeCount());
    }

    @Nonnegative
    public static int calculateBoundedMaxLogicalNodeCount(int maxLogicalNodeCount) {
        if (maxLogicalNodeCount < NODE_ID_LOWER_BOUND) {
            throw exception(SnowcastMaxLogicalNodeIdOutOfBoundsException::new, //
                    ILLEGAL_MAX_LOGICAL_NODE_ID_BOUNDARY, "smaller", NODE_ID_LOWER_BOUND);
        }
        if (maxLogicalNodeCount > NODE_ID_UPPER_BOUND) {
            throw exception(SnowcastMaxLogicalNodeIdOutOfBoundsException::new, //
                    ILLEGAL_MAX_LOGICAL_NODE_ID_BOUNDARY, "larger", NODE_ID_UPPER_BOUND);
        }
        return QuickMath.nextPowerOfTwo(maxLogicalNodeCount) - 1;
    }

    @Nonnegative
    public static int calculateMaxMillisCounter(@Nonnegative int shiftLogicalNodeId) {
        return (int) Math.pow(2, shiftLogicalNodeId);
    }

    @Nonnegative
    public static int calculateLogicalNodeShifting(@Min(128) @Max(8192) int maxLogicalNodeCount) {
        switch (maxLogicalNodeCount) {
            case MAX_LOGICAL_NODE_COUNT_128:
                return SHIFT_LOGICAL_NODE_ID_128;
            case MAX_LOGICAL_NODE_COUNT_256:
                return SHIFT_LOGICAL_NODE_ID_256;