/****************************************************************************
**
** Implementation of TQUuid class
**
** Copyright (C) 2000-2008 Trolltech ASA.  All rights reserved.
**
** This file is part of the tools module of the TQt GUI Toolkit.
**
** This file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free
** Software Foundation and appearing in the files LICENSE.GPL2
** and LICENSE.GPL3 included in the packaging of this file.
** Alternatively you may (at your option) use any later version
** of the GNU General Public License if such license has been
** publicly approved by Trolltech ASA (or its successors, if any)
** and the KDE Free TQt Foundation.
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
** or contact the sales department at sales@trolltech.com.
**
** This file may be used under the terms of the Q Public License as
** defined by Trolltech ASA and appearing in the file LICENSE.TQPL
** included in the packaging of this file.  Licensees holding valid TQt
** Commercial licenses may use this file in accordance with the TQt
** Commercial License Agreement provided with the Software.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
** herein.
**
**********************************************************************/

#include "tquuid.h"

#include "tqdatastream.h"

/*!
    \class TQUuid tquuid.h
    \brief The TQUuid class defines a Universally Unique Identifier (UUID).

    \reentrant

    For objects or declarations that must be uniquely identified,
    UUIDs (also known as GUIDs) are widely used in order to assign a
    fixed and easy to compare value to the object or declaration. The
    128-bit value of a UUID is generated by an algorithm that
    guarantees that the value is unique.

    In TQt, UUIDs are wrapped by the TQUuid struct which provides
    convenience functions for handling UUIDs. Most platforms provide a
    tool to generate new UUIDs, for example, uuidgen and guidgen.

    UUIDs generated by TQUuid, are based on the \c Random version of the
    \c DCE (Distributed Computing Environment) standard.

    UUIDs can be constructed from numeric values or from strings, or
    using the static createUuid() function. They can be converted to a
    string with toString(). UUIDs have a variant() and a version(),
    and null UUIDs return TRUE from isNull().
*/

/*!
    \fn TQUuid::TQUuid()

    Creates the null UUID {00000000-0000-0000-0000-000000000000}.
*/

/*!
    \fn TQUuid::TQUuid( uint l, ushort w1, ushort w2, uchar b1, uchar b2, uchar b3, uchar b4, uchar b5, uchar b6, uchar b7, uchar b8 )

    Creates a UUID with the value specified by the parameters, \a l,
    \a w1, \a w2, \a b1, \a b2, \a b3, \a b4, \a b5, \a b6, \a b7, \a
    b8.

    Example:
    \code
    // {67C8770B-44F1-410A-AB9A-F9B5446F13EE}
    TQUuid IID_MyInterface( 0x67c8770b, 0x44f1, 0x410a, 0xab, 0x9a, 0xf9, 0xb5, 0x44, 0x6f, 0x13, 0xee )
    \endcode
*/

/*!
    \fn TQUuid::TQUuid( const TQUuid &orig )

    Creates a copy of the TQUuid \a orig.
*/
#ifndef TQT_NO_TQUUID_STRING
/*!
    Creates a TQUuid object from the string \a text. The function can
    only convert a string in the format
    {HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH} (where 'H' stands for a hex
    digit). If the conversion fails a null UUID is created.
*/
TQUuid::TQUuid( const TQString &text )
{
    bool ok;
    if ( text.isEmpty() ) {
	*this = TQUuid();
	return;
    }
    TQString temp = text.upper();
    if ( temp[0] != '{' )
	temp = "{" + text;
    if ( text[(int)text.length()-1] != '}' )
	temp += "}";

    data1 = temp.mid( 1, 8 ).toULong( &ok, 16 );
    if ( !ok ) {
	*this = TQUuid();
	return;
    }

    data2 = temp.mid( 10, 4 ).toUInt( &ok, 16 );
    if ( !ok ) {
	*this = TQUuid();
	return;
    }
    data3 = temp.mid( 15, 4 ).toUInt( &ok, 16 );
    if ( !ok ) {
	*this = TQUuid();
	return;
    }
    data4[0] = temp.mid( 20, 2 ).toUInt( &ok, 16 );
    if ( !ok ) {
	*this = TQUuid();
	return;
    }
    data4[1] = temp.mid( 22, 2 ).toUInt( &ok, 16 );
    if ( !ok ) {
	*this = TQUuid();
	return;
    }
    for ( int i = 2; i<8; i++ ) {
	data4[i] = temp.mid( 25 + (i-2)*2, 2 ).toUShort( &ok, 16 );
	if ( !ok ) {
	    *this = TQUuid();
	    return;
	}
    }
}

/*!
    \internal
*/
TQUuid::TQUuid( const char *text )
{
    *this = TQUuid( TQString(text) );
}
#endif
/*!
    \fn TQUuid TQUuid::operator=(const TQUuid &uuid )

    Assigns the value of \a uuid to this TQUuid object.
*/

/*!
    \fn bool TQUuid::operator==(const TQUuid &other) const

    Returns TRUE if this TQUuid and the \a other TQUuid are identical;
    otherwise returns FALSE.
*/

/*!
    \fn bool TQUuid::operator!=(const TQUuid &other) const

    Returns TRUE if this TQUuid and the \a other TQUuid are different;
    otherwise returns FALSE.
*/
#ifndef TQT_NO_TQUUID_STRING
/*!
    \fn TQUuid::operator TQString() const

    Returns the string representation of the uuid.

    \sa toString()
*/

/*!
    TQString TQUuid::toString() const

    Returns the string representation of the uuid.
*/
TQString TQUuid::toString() const
{
    TQString result;

    result = "{" + TQT_TQSTRING(TQString::number( data1, 16 )).rightJustify( 8, '0' ) + "-";
    result += TQT_TQSTRING(TQString::number( (int)data2, 16 )).rightJustify( 4, '0' ) + "-";
    result += TQT_TQSTRING(TQString::number( (int)data3, 16 )).rightJustify( 4, '0' ) + "-";
    result += TQT_TQSTRING(TQString::number( (int)data4[0], 16 )).rightJustify( 2, '0' );
    result += TQT_TQSTRING(TQString::number( (int)data4[1], 16 )).rightJustify( 2, '0' ) + "-";
    for ( int i = 2; i < 8; i++ )
	result += TQT_TQSTRING(TQString::number( (int)data4[i], 16 )).rightJustify( 2, '0' );

    return result + "}";
}
#endif

#ifndef TQT_NO_DATASTREAM
/*!
    \relates TQUuid
    Writes the uuid \a id to the datastream \a s.
*/
TQDataStream &operator<<( TQDataStream &s, const TQUuid &id )
{
    s << (TQ_UINT32)id.data1;
    s << (TQ_UINT16)id.data2;
    s << (TQ_UINT16)id.data3;
    for (int i = 0; i < 8; i++ )
	s << (TQ_UINT8)id.data4[i];
    return s;
}

/*!
    \relates TQUuid
    Reads uuid from from the stream \a s into \a id.
*/
TQDataStream &operator>>( TQDataStream &s, TQUuid &id )
{
    TQ_UINT32 u32;
    TQ_UINT16 u16;
    TQ_UINT8 u8;
    s >> u32;
    id.data1 = u32;
    s >> u16;
    id.data2 = u16;
    s >> u16;
    id.data3 = u16;
    for (int i = 0; i < 8; i++ ) {
	s >> u8;
	id.data4[i] = u8;
    }
    return s;
}
#endif

/*!
    Returns TRUE if this is the null UUID
    {00000000-0000-0000-0000-000000000000}; otherwise returns FALSE.
*/
bool TQUuid::isNull() const
{
    return data4[0] == 0 && data4[1] == 0 && data4[2] == 0 && data4[3] == 0 &&
	   data4[4] == 0 && data4[5] == 0 && data4[6] == 0 && data4[7] == 0 &&
	   data1 == 0 && data2 == 0 && data3 == 0;
}

/*!
    \enum TQUuid::Variant

    This enum defines the variant of the UUID, which is the scheme
    which defines the tqlayout of the 128-bits value.

    \value VarUnknown Variant is unknown
    \value NCS Reserved for NCS (Network Computing System) backward compatibility
    \value DCE Distributed Computing Environment, the scheme used by TQUuid
    \value Microsoft Reserved for Microsoft backward compatibility (GUID)
    \value Reserved Reserved for future definition
*/

/*!
    \enum TQUuid::Version

    This enum defines the version of the UUID.

    \value VerUnknown Version is unknown
    \value Time Time-based, by using timestamp, clock sequence, and
    MAC network card address (if available) for the node sections
    \value EmbeddedPOSIX DCE Security version, with embedded POSIX UUIDs
    \value Name Name-based, by using values from a name for all sections
    \value Random Random-based, by using random numbers for all sections
*/

/*!
    \fn TQUuid::Variant TQUuid::variant() const

    Returns the variant of the UUID.
    The null UUID is considered to be of an unknown variant.

    \sa version()
*/
TQUuid::Variant TQUuid::variant() const
{
    if ( isNull() )
	return VarUnknown;
    // Check the 3 MSB of data4[0]
    if ( (data4[0] & 0x80) == 0x00 ) return NCS;
    else if ( (data4[0] & 0xC0) == 0x80 ) return DCE;
    else if ( (data4[0] & 0xE0) == 0xC0 ) return Microsoft;
    else if ( (data4[0] & 0xE0) == 0xE0 ) return Reserved;
    return VarUnknown;
}

/*!
    \fn TQUuid::Version TQUuid::version() const

    Returns the version of the UUID, if the UUID is of the DCE
    variant; otherwise returns VerUnknown.

    \sa variant()
*/
TQUuid::Version TQUuid::version() const
{
    // Check the 4 MSB of data3
    Version ver = (Version)(data3>>12);
    if ( isNull() 
	 || (variant() != DCE)
	 || ver < Time 
	 || ver > Random )
	return VerUnknown;
    return ver;
}

/*!
    \fn bool TQUuid::operator<(const TQUuid &other) const

    Returns TRUE if this TQUuid is of the same variant,
    and lexicographically before the \a other TQUuid;
    otherwise returns FALSE.

    \sa variant()
*/
#define ISLESS(f1, f2) if (f1!=f2) return (f1<f2);
bool TQUuid::operator<(const TQUuid &other ) const
{
    if ( variant() != other.variant() )
	return FALSE;

    ISLESS( data1, other.data1 );
    ISLESS( data2, other.data2 );
    ISLESS( data3, other.data3 );
    for ( int n = 0; n < 8; n++ ) {
	ISLESS( data4[n], other.data4[n] );
    }
    return FALSE;
}

/*!
    \fn bool TQUuid::operator>(const TQUuid &other) const

    Returns TRUE if this TQUuid is of the same variant,
    and lexicographically after the \a other TQUuid;
    otherwise returns FALSE.

    \sa variant()
*/
#define ISMORE(f1, f2) if (f1!=f2) return (f1>f2);
bool TQUuid::operator>(const TQUuid &other ) const
{
    if ( variant() != other.variant() )
	return FALSE;

    ISMORE( data1, other.data1 );
    ISMORE( data2, other.data2 );
    ISMORE( data3, other.data3 );
    for ( int n = 0; n < 8; n++ ) {
	ISMORE( data4[n], other.data4[n] );
    }
    return FALSE;
}

/*!
    \fn TQUuid TQUuid::createUuid()

    Returns a new UUID of \c DCE variant, and \c Random type. The
    UUIDs generated are based on the platform specific pseudo-random
    generator, which is usually not a cryptographic-quality random
    number generator. Therefore, a UUID is not guaranteed to be unique
    cross application instances.

    On Windows, the new UUID is extremely likely to be unique on the
    same or any other system, networked or not.

    \sa variant(), version()
*/
#if defined(TQ_OS_WIN32)
#include <objbase.h> // For CoCreateGuid
TQUuid TQUuid::createUuid()
{
    GUID guid;
    CoCreateGuid( &guid );
    TQUuid result = guid;
    return result;
}
#else // !TQ_OS_WIN32
#include "tqdatetime.h"
#include "stdlib.h" // For srand/rand
TQUuid TQUuid::createUuid()
{
    static const int intbits = sizeof(int)*8;
    static int randbits = 0;
    if ( !randbits ) {
	int max = RAND_MAX;
	do { ++randbits; } while ( (max=max>>1) );
	srand( (uint)TQDateTime::tqcurrentDateTime().toTime_t() );
	rand(); // Skip first
    }

    TQUuid result;
    uint *data = &(result.data1);
    int chunks = 16 / sizeof(uint);
    while ( chunks-- ) {
	uint randNumber = 0;
	for ( int filled = 0; filled < intbits; filled += randbits )
	    randNumber |= rand()<<filled;
	 *(data+chunks) = randNumber;
    }

    result.data4[0] = (result.data4[0] & 0x3F) | 0x80;	// UV_DCE
    result.data3 = (result.data3 & 0x0FFF) | 0x4000;	// UV_Random

    return result;
}
#endif // !TQ_OS_WIN32

