/* JUG Java Uuid Generator
 *
 * Copyright (c) 2002- Tatu Saloranta, tatu.saloranta@iki.fi
 *
 * Licensed under the License specified in the file LICENSE which is
 * included with the source code.
 * You may not use this file except in compliance with the License.
 *
 * 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 org.safehaus.uuid;

import java.io.Serializable;

/**
 * UUID represents Universally Unique Identifiers (aka Global UID in
 * Windows world). UUIDs are usually generated via UUIDGenerator (or in
 * case of 'Null UUID', 16 zero bytes, via static method getNullUUID()),
 * or received from external systems.
 *
 * By default class caches the string presentations of UUIDs so that
 * description is only created the first time it's needed. For memory
 * stingy applications this caching can be turned off (note though
 * that if uuid.toString() is never called, desc is never calculated
 * so only loss is the space allocated for the desc pointer... which
 * can of course be commented out to save memory).
 *
 * Similarly, hash code is calculated when it's needed for the first
 * time, and from thereon that value is just returned. This means
 * that using UUIDs as keys should be reasonably efficient.
 *
 * UUIDs can be compared for equality, serialized, cloned and even sorted.
 * Equality is a simple bit-wise comparison. Ordering (for sorting) is done by
 * first ordering based on type (in the order of numeric values of
 * types), secondarily by time stamp (only for time-based time stamps),
 * and finally by straight numeric byte-by-byte comparison (from
 * most to least significant bytes).
 */

public class UUID
    implements Serializable, Cloneable, Comparable
{
    private final static String kHexChars = "0123456789abcdefABCDEF";

    public final static byte INDEX_CLOCK_HI = 6;
    public final static byte INDEX_CLOCK_MID = 4;
    public final static byte INDEX_CLOCK_LO = 0;

    public final static byte INDEX_TYPE = 6;
    // Clock seq. & variant are multiplexed...
    public final static byte INDEX_CLOCK_SEQUENCE = 8;
    public final static byte INDEX_VARIATION = 8;

    public final static byte TYPE_NULL = 0;
    public final static byte TYPE_TIME_BASED = 1;
    public final static byte TYPE_DCE = 2; // Not used
    public final static byte TYPE_NAME_BASED = 3;
    public final static byte TYPE_RANDOM_BASED = 4;

    /* 'Standard' namespaces defined (suggested) by UUID specs:
     */
    public final static String NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
    public final static String NAMESPACE_URL = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
    public final static String NAMESPACE_OID = "6ba7b812-9dad-11d1-80b4-00c04fd430c8";
    public final static String NAMESPACE_X500 = "6ba7b814-9dad-11d1-80b4-00c04fd430c8";

    /* By default let's cache desc, can be turned off. For hash code
     * there's no point in turning it off (since the int is already
     * part of the instance memory allocation); if you want to save
     * those 4 bytes (or possibly bit more if alignment is bad) just
     * comment out hash caching.
     */
    private static boolean sDescCaching = true;

    /**
     * The shared null UUID. Would be nice to do lazy instantiation, but
     * if the instance really has to be a singleton, that would mean
     * class-level locking (synchronized getNullUUID()), which would
     * be some overhead... So let's just bite the bullet the first time
     * assuming creation of the null UUID (plus wasted space if it's
     * not needed) can be ignored.
     */
    private final static UUID sNullUUID = new UUID();

    private final byte[] mId = new byte[16];
    // Both string presentation and hash value may be cached...
    private transient String mDesc = null;
    private transient int mHashCode = 0;

    /* *** Object creation: *** */

    /**
     * Default constructor creates a NIL UUID, one that contains all
     * zeroes
     *
     * Note that the clearing of array is actually unnecessary as
     * JVMs are required to clear up the allocated arrays by default.
     */
    public UUID()
    {
        /*
          for (int i = 0; i < 16; ++i) {
          mId[i] = (byte)0;
          }
        */
    }

    /**
     * Constructor for cases where you already have the 16-byte binary
     * representation of the UUID (for example if you save UUIDs binary
     * takes less than half of space string representation takes).
     *
     * @param data array that contains the binary representation of UUID
     */
    public UUID(byte[] data)
    {
        /* Could call the other constructor... and/or use System.arraycopy.
         * However, it's likely that those would make this slower to use,
         * and initialization is really simple as is in any case.
         */
        for (int i = 0; i < 16; ++i) {
            mId[i] = data[i];
        }
    }

    /**
     * Constructor for cases where you already have the binary
     * representation of the UUID (for example if you save UUIDs binary
     * takes less than half of space string representation takes) in
     * a byte array
     *
     * @param data array that contains the binary representation of UUID
     * @param start byte offset where UUID starts
     */
    public UUID(byte[] data, int start)
    {
        for (int i = 0; i < 16; ++i) {
            mId[i] = data[start + i];
        }
    }

    /**
     * Protected constructor used by UUIDGenerator
     *
     * @param type UUID type
     * @param data 16 byte UUID contents
     */
    UUID(int type, byte[] data)
    {
        for (int i = 0; i < 16; ++i) {
            mId[i] = data[i];
        }
        // Type is multiplexed with time_hi:
        mId[INDEX_TYPE] &= (byte) 0x0F;
        mId[INDEX_TYPE] |= (byte) (type << 4);
        // Variant masks first two bits of the clock_seq_hi:
        mId[INDEX_VARIATION] &= (byte) 0x3F;
        mId[INDEX_VARIATION] |= (byte) 0x80;
    }

    /**
     * Constructor for creating UUIDs from the canonical string
     * representation
     *
     * Note that implementation is optimized for speed, not necessarily
     * code clarity... Also, since what we get might not be 100% canonical
     * (see below), let's not yet populate mDesc here.
     *
     * @param id String that contains the canonical representation of
     *   the UUID to build; 36-char string (see UUID specs for details).
     *   Hex-chars may be in upper-case too; UUID class will always output
     *   them in lowercase.
     */
    public UUID(String id)
        throws NumberFormatException
    {
        if (id == null) {
            throw new NullPointerException();
        }
        if (id.length() != 36) {
            throw new NumberFormatException("UUID has to be represented by the standard 36-char representation");
        }

        for (int i = 0, j = 0; i < 36; ++j) {
            // Need to bypass hyphens:
            switch (i) {
            case 8:
            case 13:
            case 18:
            case 23:
                if (id.charAt(i) != '-') {
                    throw new NumberFormatException("UUID has to be represented by the standard 36-char representation");
                }
                ++i;
            }
            int index;
            char c = id.charAt(i);

            if (c >= '0' && c <= '9') {
                mId[j] = (byte) ((c - '0') << 4);
            } else if (c >= 'a' && c <= 'f') {
                mId[j] = (byte) ((c - 'a' + 10) << 4);
            } else if (c >= 'A' && c <= 'F') {
                mId[j] = (byte) ((c - 'A' + 10) << 4);
            } else {
                throw new NumberFormatException("Non-hex character '"+c+"'");
            }

            c = id.charAt(++i);

            if (c >= '0' && c <= '9') {
                mId[j] |= (byte) (c - '0');
            } else if (c >= 'a' && c <= 'f') {
                mId[j] |= (byte) (c - 'a' + 10);
            } else if (c >= 'A' && c <= 'F') {
                mId[j] |= (byte) (c - 'A' + 10);
            } else {
                throw new NumberFormatException("Non-hex character '"+c+"'");
            }
            ++i;
        }
    }

    /**
     * Default cloning behaviour (bitwise copy) is just fine...
     *
     * Could clear out cached string presentation, but there's
     * probably no point in doing that.
     */
    public Object clone()
    {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            // shouldn't happen
            return null;
        }
    }

    /* *** Configuration: *** */
    public static void setDescCaching(boolean state)
    {
        sDescCaching = state;
    }

    /* *** Accessors: *** */

    /**
     * Accessor for getting the shared null UUID
     *
     * @return the shared null UUID
     */
    public static UUID getNullUUID()
    {
        return sNullUUID;
    }

    public boolean isNullUUID()
    {
        // Assuming null uuid is usually used for nulls:
        if (this == sNullUUID) {
            return true;
        }
        // Could also check hash code; null uuid has -1 as hash?
        byte[] data = mId;
        int i = mId.length;
        byte zero = (byte) 0;
        while (--i >= 0) {
            if (data[i] != zero) {
                return false;
            }
        }

        return true;
    }

    /**
     * Returns the UUID type code
     *
     * @return UUID type
     */
    public int getType()
    {
        return (mId[INDEX_TYPE] & 0xFF) >> 4;
    }

    /**
     * Returns the UUID as a 16-byte byte array
     *
     * @return 16-byte byte array that contains UUID bytes in the network
     *   byte order
     */
    public byte[] asByteArray()
    {
        byte[] result = new byte[16];
        toByteArray(result);
        return result;
    }

    /**
     * Fills in the 16 bytes (from index pos) of the specified byte array
     * with the UUID contents.
     *
     * @param dst Byte array to fill
     * @param pos Offset in the array
     */
    public void toByteArray(byte[] dst, int pos)
    {
        byte[] src = mId;
        for (int i = 0; i < 16; ++i) {
            dst[pos+i] = src[i];
        }
    }

    public void toByteArray(byte[] dst) { toByteArray(dst, 0); }

    /**
     * 'Synonym' for 'asByteArray'
     */
    public byte[] toByteArray() { return asByteArray(); }
    
    /* *** Standard methods from Object overridden: *** */

    /**
     * Could use just the default hash code, but we can probably create
     * a better identity hash (ie. same contents generate same hash)
     * manually, without sacrificing speed too much. Although multiplications
     * with modulos would generate better hashing, let's use just shifts,
     * and do 2 bytes at a time.
     *<p>
     * Of course, assuming UUIDs are randomized enough, even simpler
     * approach might be good enough?
     *<p>
     * Is this a good hash? ... one of these days I better read more about
     * basic hashing techniques I swear!
     */
    private final static int[] kShifts = {
        3, 7, 17, 21, 29, 4, 9
    };

    public int hashCode()
    {
        if (mHashCode == 0) {
            // Let's handle first and last byte separately:
            int result = mId[0] & 0xFF;
	    
            result |= (result << 16);
            result |= (result << 8);
	    
            for (int i = 1; i < 15; i += 2) {
                int curr = (mId[i] & 0xFF) << 8 | (mId[i+1] & 0xFF);
                int shift = kShifts[i >> 1];
		
                if (shift > 16) {
                    result ^= (curr << shift) | (curr >>> (32 - shift));
                } else {
                    result ^= (curr << shift);
                }
            }

            // and then the last byte:
            int last = mId[15] & 0xFF;
            result ^= (last << 3);
            result ^= (last << 13);

            result ^= (last << 27);
            // Let's not accept hash 0 as it indicates 'not hashed yet':
            if (result == 0) {
                mHashCode = -1;
            } else {
                mHashCode = result;
            }
        }
        return mHashCode;
    }

    public String toString()
    {
        /* Could be synchronized, but there isn't much harm in just taking
         * our chances (ie. in the worst case we'll form the string more
         * than once... but result is the same)
         */

        if (mDesc == null) {
            StringBuffer b = new StringBuffer(36);
	    
            for (int i = 0; i < 16; ++i) {
                // Need to bypass hyphens:
                switch (i) {
                case 4:
                case 6:
                case 8:
                case 10:
                    b.append('-');
                }
                int hex = mId[i] & 0xFF;
                b.append(kHexChars.charAt(hex >> 4));
                b.append(kHexChars.charAt(hex & 0x0f));
            }
            if (!sDescCaching) {
                return b.toString();
            }
            mDesc = b.toString();
        }
        return mDesc;
    }

    /* *** Comparison methods: *** */

    private final static int[] sTimeCompare = new int[] {
        INDEX_CLOCK_HI, INDEX_CLOCK_HI + 1,
        INDEX_CLOCK_MID, INDEX_CLOCK_MID + 1,
        INDEX_CLOCK_LO, INDEX_CLOCK_LO + 1,
        INDEX_CLOCK_LO + 2, INDEX_CLOCK_LO + 3,
    };

    /**
     * Let's also make UUIDs sortable. This will mostly/only be useful with
     * time-based UUIDs; they will sorted by time of creation. The order
     * will be strictly correct with UUIDs produced over one JVM's lifetime;
     * that is, if more than one JVMs create UUIDs and/or system is rebooted
     * the order may not be 100% accurate between UUIDs created under
     * different JVMs.
     *
     * For all UUIDs, type is first compared, and UUIDs of different types
     * are sorted together (ie. null UUID is before all other UUIDs, then
     * time-based UUIDs etc). If types are the same, time-based UUIDs'
     * time stamps (including additional clock counter) are compared, so
     * UUIDs created first are ordered first. For all other types (and for
     * time-based UUIDs with same time stamp, which should only occur
     * when comparing a UUID with itself, or with UUIDs created on
     * different JVMs or external systems) binary comparison is done
     * over all 16 bytes.
     *
     * @param o Object to compare this UUID to; should be a UUID
     *
     * @return -1 if this UUID should be ordered before the one passed,
     *   1 if after, and 0 if they are the same
     *
     * @throws ClassCastException if o is not a UUID.
     */
    public int compareTo(Object o)
    {
        UUID other = (UUID) o;

        int thisType = getType();
        int thatType = other.getType();

        /* Let's first order by type:
         */
        if (thisType > thatType) {
            return 1;
        } else if (thisType < thatType) {
            return -1;
        }

        /* And for time-based UUIDs let's compare time stamps first,
         * then the rest... For all other types, we'll just do straight
         * byte-by-byte comparison.
         */
        byte[] thisId = mId;
        byte[] thatId = other.mId;
        int i = 0;
        if (thisType == TYPE_TIME_BASED) {
            for (; i < 8; ++i) {
                int index = sTimeCompare[i];
                int cmp = (((int) thisId[index]) & 0xFF)
                    - (((int) thatId[index]) & 0xFF);
                if (cmp != 0) {
                    return cmp;
                }
            }
            // Let's fall down to full comparison otherwise
        }

        for (; i < 16; ++i) {
            int cmp = (((int) thisId[i]) & 0xFF) - (((int) thatId[i]) & 0xFF);
            if (cmp != 0) {
                return cmp;
            }
        }

        return 0;
    }

    /**
     * Checking equality of UUIDs is easy; just compare the 128-bit
     * number.
     */
    public boolean equals(Object o)
    {
        if (!(o instanceof UUID)) {
            return false;
        }
        byte[] otherId = ((UUID) o).mId;
        byte[] thisId = mId;
        for (int i = 0; i < 16; ++i) {
            if (otherId[i] != thisId[i]) {
                return false;
            }
        }
        return true;
    }

    /**
     * Constructs a new UUID instance given the canonical string
     * representation of an UUID.
     *
     * Note that calling this method returns the same result as would
     * using the matching (1 string arg) constructor.
     *
     * @param id Canonical string representation used for constructing
     *  an UUID instance
     *
     * @throws NumberFormatException if 'id' is invalid UUID
     */
    public static UUID valueOf(String id)
        throws NumberFormatException
    {
        return new UUID(id);
    }

    /**
     * Constructs a new UUID instance given a byte array that contains
     * the (16 byte) binary representation.
     *
     * Note that calling this method returns the same result as would
     * using the matching constructor
     *
     * @param src Byte array that contains the UUID definition
     * @param start Offset in the array where the UUID starts
     */
    public static UUID valueOf(byte[] src, int start)
    {
        return new UUID(src, start);
    }

    /**
     * Constructs a new UUID instance given a byte array that contains
     * the (16 byte) binary representation.
     *
     * Note that calling this method returns the same result as would
     * using the matching constructor
     *
     * @param src Byte array that contains the UUID definition
     */
    public static UUID valueOf(byte[] src)
    {
        return new UUID(src);
    }
    
    private void copyFrom(UUID src)
    {
        byte[] srcB = src.mId;
        byte[] dstB = mId;
	
        for (int i = 0; i < 16; ++i) {
            dstB[i] = srcB[i];
        }

        mDesc = sDescCaching ? src.mDesc : null;
    }

    public static void main(String[] args)
    {
    }
}
