/*
 * 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.
 */

package net.jini.id;

import java.io.Externalizable;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.Serializable;

/**
 * A 128-bit value to serve as a universally unique identifier.  Two
 * <code>Uuid</code>s are equal if they have the same 128-bit value.
 * <code>Uuid</code> instances can be created using the static methods
 * of the {@link UuidFactory} class.
 *
 * <p>The design of this class is intended to support the use of
 * universally unique identifiers that
 *
 * <ol>
 * <li>have a high likelihood of uniqueness over space and time and
 * <li>are computationally difficult to guess.
 * </ol>
 *
 * The second goal is intended to support the treatment of data
 * containing a <code>Uuid</code> as a capability.  Note that not all
 * defined <code>Uuid</code> values imply a generation algorithm that
 * supports this goal.
 *
 * <p>The most significant 64 bits of the value can be decomposed into
 * unsigned integer fields according to the following bit masks:
 *
 * <pre>
 * 0xFFFFFFFF00000000	time_low
 * 0x00000000FFFF0000	time_mid
 * 0x000000000000F000	version
 * 0x0000000000000FFF	time_hi
 * </pre>
 *
 * <p>The least significant 64 bits of the value can be decomposed
 * into unsigned integer fields according to the following bit masks:
 *
 * <pre>
 * 0xC000000000000000	variant
 * 0x3FFF000000000000	clock_seq
 * 0x0000FFFFFFFFFFFF	node
 * </pre>
 *
 * <p>This specification defines the meaning (and implies aspects of
 * the generation algorithm) of <code>Uuid</code> values if the
 * variant field is <code>0x2</code> and the <code>version</code>
 * field is either <code>0x1</code> or <code>0x4</code>.
 *
 * <p>If the <code>version</code> field is <code>0x1</code>, then
 *
 * <ul>
 *
 * <li>the <code>time_low</code>, <code>time_mid</code>, and
 * <code>time_hi</code> fields are the least, middle, and most
 * significant bits (respectively) of a 60-bit timestamp of
 * 100-nanosecond intervals since midnight, October 15, 1582 UTC,
 *
 * <li>the <code>clock_seq</code> field is a 14-bit number chosen to
 * help avoid duplicate <code>Uuid</code> values in the event of a
 * changed node address or a backward system clock adjustment (such as
 * a random number when in doubt, or the previously used number
 * incremented by one if just a backward clock adjustment is
 * detected), and
 *
 * <li>the <code>node</code> field is an IEEE 802 address (a 48-bit
 * value).
 *
 * <p>As an alternative to an IEEE 802 address (such as if one is not
 * available to the generation algorithm), the <code>node</code> field
 * may also be a 48-bit number for which the most significant bit is
 * set to <code>1</code> and the remaining bits were produced from a
 * cryptographically strong random sequence.
 *
 * </ul>
 *
 * <p>If the <code>version</code> field is <code>0x4</code>, then the
 * <code>time_low</code>, <code>time_mid</code>, <code>time_hi</code>,
 * <code>clock_seq</code>, and <code>node</code> fields are values
 * that were produced from a cryptographically strong random sequence.
 *
 * <p>Only <code>Uuid</code> values with a <code>version</code> field
 * of <code>0x4</code> are considered computationally difficult to
 * guess.  A <code>Uuid</code> value with a <code>version</code> field
 * of <code>0x1</code> should not be treated as a capability.
 *
 * <p>A subclass of <code>Uuid</code> must not implement {@link
 * Externalizable}; this restriction is enforced by this class's
 * constructor and <code>readObject</code> methods.
 *
 * 
 * @since 2.0
 **/
public class Uuid implements Serializable {

    private static final long serialVersionUID = -106268922535833151L;

    /**
     * The most significant 64 bits of the 128-bit value.
     *
     * @serial
     **/
    private final long bits0;

    /**
     * The least significant 64 bits of the 128-bit value.
     *
     * @serial
     **/
    private final long bits1;

    /**
     * Creates a new <code>Uuid</code> with the specified 128-bit
     * value.
     *
     * @param bits0 the most significant 64 bits of the 128-bit value
     *
     * @param bits1 the least significant 64 bits of the 128-bit value
     *
     * @throws SecurityException if the class of this object
     * implements <code>Externalizable</code>
     **/
    protected Uuid(long bits0, long bits1) {
	if (!isValid()) {
	    throw new SecurityException("invalid class: " +
					this.getClass().getName());
	}
	this.bits0 = bits0;
	this.bits1 = bits1;
    }

    /**
     * Returns the most significant 64 bits of this
     * <code>Uuid</code>'s 128-bit value.
     *
     * @return the most significant 64 bits of the 128-bit value
     **/
    public final long getMostSignificantBits() {
	return bits0;
    }

    /**
     * Returns the least significant 64 bits of this
     * <code>Uuid</code>'s 128-bit value.
     *
     * @return the least significant 64 bits of the 128-bit value
     **/
    public final long getLeastSignificantBits() {
	return bits1;
    }

    /**
     * Returns the hash code value for this <code>Uuid</code>.
     *
     * @return the hash code value for this <code>Uuid</code>
     **/
    public final int hashCode() {
	return (int) ((bits0 >>> 32) ^ bits0 ^ (bits1 >>> 32) ^ bits1);
    }

    /**
     * Compares the specified object with this <code>Uuid</code> for
     * equality.
     *
     * This method returns <code>true</code> if and only if the
     * specified object is a <code>Uuid</code> instance with the same
     * 128-bit value as this one.
     *
     * @param obj the object to compare this <code>Uuid</code> to
     *
     * @return <code>true</code> if the given object is equivalent to
     * this one, and <code>false</code> otherwise
     **/
    public final boolean equals(Object obj) {
	if (obj instanceof Uuid) {
	    Uuid other = (Uuid) obj;
	    return bits0 == other.bits0 && bits1 == other.bits1;
	} else {
	    return false;
	}
    }

    /**
     * Returns a string representation of this <code>Uuid</code>.
     *
     * <p>The string representation is 36 characters long, with five
     * fields of zero-filled, lowercase hexadecimal numbers separated
     * by hyphens.  The fields of the string representation are
     * derived from the components of the 128-bit value in the
     * following order:
     *
     * <ul>
     *
     * <li><code>time_low</code> (8 hexadecimal digits)
     *
     * <li><code>time_mid</code> (4 hexadecimal digits)
     *
     * <li><code>version</code> and <code>time_hi</code> treated as a
     * single field (4 hexadecimal digits)
     *
     * <li><code>variant</code> and <code>clock_seq</code> treated as
     * a single field (4 hexadecimal digits)
     *
     * <li><code>node</code> (12 hexadecimal digits)
     *
     * </ul>
     *
     * <p>As an example, a <code>Uuid</code> with the 128-bit value
     *
     * <pre>0x0123456789ABCDEF0123456789ABCDEF</pre>
     *
     * would have the following string representation:
     *
     * <pre>01234567-89ab-cdef-0123-456789abcdef</pre>
     * 
     * @return a string representation of this <code>Uuid</code>
     **/
    public final String toString() {
	return
	    toHexString(bits0 >>> 32, 8) + "-" +
	    toHexString(bits0 >>> 16, 4) + "-" +
	    toHexString(bits0 >>>  0, 4) + "-" +
	    toHexString(bits1 >>> 48, 4) + "-" +
	    toHexString(bits1 >>>  0, 12);
    }

    /**
     * Returns the specified number of the least significant digits of
     * the hexadecimal representation of the given value, discarding
     * more significant digits or padding with zeros as necessary.
     * Only lowercase letters are used in the returned hexadecimal
     * representation.
     **/
    private String toHexString(long value, int digits) {
	long cutoff = 1L << (digits * 4);
	return Long.toHexString(cutoff | (value & (cutoff - 1))).substring(1);
    }

    /**
     * Marshals a binary representation of this <code>Uuid</code> to
     * an <code>OutputStream</code>.
     *
     * <p>Specifically, this method writes the 128-bit value to the
     * stream as 16 bytes in network (big-endian) byte order.
     *
     * @param out the <code>OutputStream</code> to write this
     * <code>Uuid</code> to
     *
     * @throws IOException if an I/O exception occurs while performing
     * this operation
     *
     * @throws NullPointerException if <code>out</code> is
     * <code>null</code>
     **/
    public final void write(OutputStream out) throws IOException {
	writeLong(bits0, out);
	writeLong(bits1, out);
    }

    /**
     * Write a long value to an OutputStream in big-endian byte order.
     **/
    private static void writeLong(long value, OutputStream out)
	throws IOException
    {
	out.write((int) (value >>> 56) & 0xFF);
	out.write((int) (value >>> 48) & 0xFF);
	out.write((int) (value >>> 40) & 0xFF);
	out.write((int) (value >>> 32) & 0xFF);
	out.write((int) (value >>> 24) & 0xFF);
	out.write((int) (value >>> 16) & 0xFF);
	out.write((int) (value >>>  8) & 0xFF);
	out.write((int) (value >>>  0) & 0xFF);
    }

    /**
     * Delegates to the superclass's {@link Object#finalize finalize}
     * method.  This method prevents a subclass from declaring an
     * overriding <code>finalize</code> method.
     *
     * @throws Throwable if the superclass's <code>finalize</code>
     * method throws a <code>Throwable</code>
     **/
    protected final void finalize() throws Throwable { }

    /**
     * Returns this object.  This method prevents a subclass from
     * declaring a <code>writeReplace</code> method with an alternate
     * implementation.
     *
     * @return this object
     **/
    protected final Object writeReplace() {
	return this;
    }

    /**
     * Returns this object.  This method prevents a subclass from
     * declaring a <code>readResolve</code> method with an alternate
     * implementation.
     *
     * @return this object
     **/
    protected final Object readResolve() {
	return this;
    }

    /**
     * @throws InvalidObjectException if the class of this object
     * implements <code>Externalizable</code>
     **/
    private void readObject(ObjectInputStream in)
	throws IOException, ClassNotFoundException
    {
	if (!isValid()) {
	    throw new InvalidObjectException("invalid class: " +
					     this.getClass().getName());
	}
	in.defaultReadObject();
    }

    /**
     * @throws InvalidObjectException unconditionally
     **/
    private void readObjectNoData() throws InvalidObjectException {
	throw new InvalidObjectException("no data in stream; class: " +
					 this.getClass().getName());
    }

    private boolean isValid() {
	return !(this instanceof Externalizable);
    }
}
