/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 * In particular this file is part of the Framework Core Library
 *
 * The iWear Framework is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by the
 * Free Software Foundation as in version 2 of the License.

 * 
 * The iWear Framework is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWEAR_UID_H
#define __IWEAR_UID_H


#ifndef __IWEAR_UTILITY_H
#include <iwear/utility.h>
#endif

#include <iosfwd>
#include <string>

namespace iwear {

//template <unsigned int> class HashCode;
/**
 * This class encasulates a unique id object.
 *
 * The uids are alwas unique to the whole application, unless you explicitly
 * copy a unique id. Therefore you should make sure that when copying things,
 * that you do not copy the uid but create a new one.
 */
class uid
{    
protected:
    template<size_t> friend class HashCode;
public:
   /**
    * This will output the id similar to an IPv6 IP, but with 8Bit instead of 16Bit fields
    */
    friend std::ostream& operator << (std::ostream& o, const uid& u);
   /**
    * This will create a new uid object with a random unique id
    */
    uid( );
    uid( const uid& );
    ~uid( );

   /**
    * @warning THIS IS FOR TESTING PURPOSES ONLY AND WILL BE REMOVED IN THE
    * FUTURE
    */
    explicit uid( const std::string& );

    uid( uint64_t, uint64_t );
    
   /**
    * We want to be able to generate a uid from an MD5 checksum so the user can
    * generate it from unique device settings.
    */
//    uid( const HashCode<16>& );
   /**
    * For Systems that have their unique IPv6 Adress this should be used so we
    * can identify it over networks.
    */
//    uid( const net::IPv6Address& );

    /**
     * @name Comparison Operators
     * @note These use memcmp, since the sizeof argument is constant at
     * compile time, so the compiler can maximize the optimization here.
     * For 128 Bit it could even use inline mmx instructions.
     * @{
     */
    inline bool operator <   ( const uid& u) const
	{
//	    cout << "Comparing " << (void*) this << " with " << (void*) &u << endl;
//	    return (the_id[0] < u.the_id[0]) || ( the_id[0] == u.the_id[0] && the_id[1] < u.the_id[1]);
	    return ( memcmp(&the_id,&(u.the_id),sizeof(the_id)) < 0); 
	}
    inline bool operator >   ( const uid& u) const
	{ return ( memcmp(&the_id,&(u.the_id),sizeof(the_id)) > 0); }
    inline bool operator ==  ( const uid& u) const
	{ return ( memcmp(&the_id,&(u.the_id),sizeof(the_id)) == 0); }
    inline bool operator !=  ( const uid& u) const
	{ return !( *this == u); }

    uid& operator=( const uid& );
    /**
     * @}
     */

    const uint64_t& get_the_id( uint32_t i ) const { if ( i < 2 ) return the_id[i]; else return the_id[0]; }
protected:
    
   /**
    * A static mapping of known ids, to keep them really unique
    */
//    static set<uid*,deref_less<uid*> > wehave;
//    static Mutex Mutex;

   /**
    * The ID needs to be 128Bit long in order to be representable by an IPv6
    * Adress or an MD5 Checksum
    */
    uint64_t the_id[2];

private:

   /**
    * Internally checking a uid for its uniqueness. Throws an exception if its
    * not unique
    */
//    void check_me_uniq( void );

};

std::ostream& operator << (std::ostream& o, const uid& u);
std::istream& operator >> (std::istream& i, uid& u );

}
#endif
