/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

#ifndef _DECAF_UTIL_UUID_H_
#define _DECAF_UTIL_UUID_H_

#include <decaf/util/Config.h>
#include <decaf/lang/Comparable.h>
#include <string>
#include <vector>

namespace decaf {
namespace util {

    class UUIDImpl;

    /**
     * A class that represents an immutable universally unique identifier (UUID).
     * A UUID represents a 128-bit value.
     *
     * There exist different variants of these global identifiers. The methods of
     * this class are for manipulating the Leach-Salz variant, although the
     * constructors allow the creation of any variant of UUID (described below).
     *
     * The layout of a variant 2 (Leach-Salz) UUID is as follows: The most
     * significant long consists of the following unsigned fields:
     *
     *  0xFFFFFFFF00000000 time_low
     *  0x00000000FFFF0000 time_mid
     *  0x000000000000F000 version
     *  0x0000000000000FFF time_hi
     *
     * The least significant long consists of the following unsigned fields:
     *
     *  0xC000000000000000 variant
     *  0x3FFF000000000000 clock_seq
     *  0x0000FFFFFFFFFFFF node
     *
     * The variant field contains a value which identifies the layout of the UUID.
     * The bit layout described above is valid only for a UUID with a variant value
     * of 2, which indicates the Leach-Salz variant.
     *
     * The version field holds a value that describes the type of this UUID. There
     * are four different basic types of UUIDs: time-based, DCE security, name-based,
     * and randomly generated UUIDs. These types have a version value of 1, 2, 3 and
     * 4, respectively.
     *
     * For more information including algorithms used to create UUIDs, see the
     * Internet-Draft UUIDs and GUIDs or the standards body definition at
     * ISO/IEC 11578:1996.
     */
    class DECAF_API UUID : public lang::Comparable<UUID> {
    private:

        UUIDImpl* uuid;

    public:

        /**
         * Static factory to retrieve a type 4 (pseudo randomly generated) UUID.
         * The UUID is generated using a cryptographically strong pseudo random
         * number generator.
         *
         * @return type 4 UUID
         */
        static UUID randomUUID();

        /**
         * Static factory to retrieve a type 3 (name based) UUID based on the
         * specified byte array.
         *
         * @param name
         *      A byte array to be used to construct a UUID.
         *
         * @return type 3 UUID
         */
        static UUID nameUUIDFromBytes(const std::vector<char>& name);

        /**
         * Static factory to retrieve a type 3 (name based) UUID based on the
         * specified byte array.
         *
         * @param name
         *      A byte array to be used to construct a UUID.
         * @param size
         *      The size of the byte array, or number of bytes to use.
         *
         * @return type 3 UUID
         */
        static UUID nameUUIDFromBytes(const char* name, int size);

        /**
         * Creates a UUID from the string standard representation as described
         * in the toString() method.
         *
         * @param name
         *      A string to be used to construct a UUID.
         *
         * @return type 3 UUID
         *
         * @throws IllegalArgumentException if the UUID string given is invalid.
         */
        static UUID fromString(const std::string& name);

    public:

        /**
         * Constructs a new UUID using the specified data. mostSigBits is used
         * for the most significant 64 bits of the UUID and leastSigBits becomes
         * the least significant 64 bits of the UUID.
         *
         * @param mostSigBits
         * @param leastSigBits
         */
        UUID(long long mostSigBits, long long leastSigBits);

        /**
         * Create a copy of the source UUID
         *
         * @param source
         *      The UUID whose value initializes this UUID
         */
        UUID(const UUID& source);

        /**
         * Copy the source UUID and return a reference to this UUID for chaining.
         *
         * @param source
         *      The UUID whose value replaces the current values in this UUID
         *
         * @return a reference to this UUID
         */
        UUID& operator= (const UUID& source);

        virtual ~UUID();

        /**
         * Compare the given UUID to this one
         * @param value - the UUID to compare to
         */
        virtual int compareTo(const UUID& value) const;

        /**
         * Compares this UUID to the one given, returns true if they are equal.
         *
         * @param value
         *      The UUID to compare to.
         *
         * @return true if UUIDs are the same.
         */
        virtual bool equals(const UUID& value) const;

        /**
         * Returns a Hash Code value for this UUID.
         *
         * @return a Hash Code for this UUID
         */
        int hashCode() const;

        /**
         * Compares equality between this object and the one passed.
         * @param value - the value to be compared to this one.
         * @return true if this object is equal to the one passed.
         */
        virtual bool operator==(const UUID& value) const;

        /**
         * Compares this object to another and returns true if this object
         * is considered to be less than the one passed.  This
         * @param value - the value to be compared to this one.
         * @return true if this object is equal to the one passed.
         */
        virtual bool operator<(const UUID& value) const;

        /**
         * Returns a String object representing this UUID.
         *
         * The UUID string representation is as described by this BNF :
         *
         *    UUID                   = <time_low> "-" <time_mid> "-"
         *                             <time_high_and_version> "-"
         *                             <variant_and_sequence> "-"
         *                             <node>
         *    time_low               = 4*<hexOctet>
         *    time_mid               = 2*<hexOctet>
         *    time_high_and_version  = 2*<hexOctet>
         *    variant_and_sequence   = 2*<hexOctet>
         *    node                   = 6*<hexOctet>
         *    hexOctet               = <hexDigit><hexDigit>
         *    hexDigit               =
         *        "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
         *      | "a" | "b" | "c" | "d" | "e" | "f"
         *      | "A" | "B" | "C" | "D" | "E" | "F"
         *
         * @return formatted string for this UUID
         */
        std::string toString() const;

        /**
         * @return the most significant 64 bits of this UUID's 128 bit value.
         */
        long long getLeastSignificantBits() const;

        /**
         * @return the most significant 64 bits of this UUID's 128 bit value.
         */
        long long getMostSignificantBits() const;

        /**
         * The node value associated with this UUID.
         *
         * The 48 bit node value is constructed from the node field of this UUID.
         * This field is intended to hold the IEEE 802 address of the machine that
         * generated this UUID to guarantee spatial uniqueness.
         *
         * The node value is only meaningful in a time-based UUID, which has
         * version type 1. If this UUID is not a time-based UUID then this method
         * throws UnsupportedOperationException.
         *
         * @return the node value of this UUID
         *
         * @throws UnsupportedOperationException if this UUID version does not support this operation.
         */
        long long node();

        /**
         * The timestamp value associated with this UUID.
         *
         * The 60 bit timestamp value is constructed from the time_low, time_mid,
         * and time_hi fields of this UUID. The resulting timestamp is measured in
         * 100-nanosecond units since midnight, October 15, 1582 UTC.
         *
         * The timestamp value is only meaningful in a time-based UUID, which has
         * version type 1. If this UUID is not a time-based UUID then this method
         * throws UnsupportedOperationException.
         *
         * @return the timestamp associated with a V1 UUID
         *
         * @throws UnsupportedOperationException if this UUID version does not support this operation.
         */
        long long timestamp();

        /**
         * The clock sequence value associated with this UUID.
         *
         * The 14 bit clock sequence value is constructed from the clock sequence
         * field of this UUID. The clock sequence field is used to guarantee temporal
         * uniqueness in a time-based UUID.
         *
         * The clockSequence value is only meaningful in a time-based UUID, which
         * has version type 1. If this UUID is not a time-based UUID then this
         * method throws UnsupportedOperationException.
         *
         * @return the clockSequeunce associated with a V1 UUID
         *
         * @throws UnsupportedOperationException if this UUID version does not support this operation.
         */
        int clockSequence();

        /**
         * The variant number associated with this UUID. The variant number describes
         * the layout of the UUID. The variant number has the following meaning:
         *
         *     * 0 Reserved for NCS backward compatibility
         *     * 2 The Leach-Salz variant (used by this class)
         *     * 6 Reserved, Microsoft Corporation backward compatibility
         *     * 7 Reserved for future definition
         *
         * @return the variant associated with a V1 UUID
         *
         * @throws UnsupportedOperationException if this UUID version does not support this operation.
         */
        int variant();

        /**
         * The version number associated with this UUID. The version number describes
         * how this UUID was generated. The version number has the following meaning:
         *
         *     * 1 Time-based UUID
         *     * 2 DCE security UUID
         *     * 3 Name-based UUID
         *     * 4 Randomly generated UUID
         *
         * @return the version associated with a V1 UUID
         *
         * @throws UnsupportedOperationException if this UUID version does not support this operation.
         */
        int version();

    };

}}

#endif /*_DECAF_UTIL_UUID_H_*/
