/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
****************************************************************************/

#pragma once

#include "glmCoreAPI.h"
#include "glmString.h"
#include <cstring>
#include <iostream>

namespace glm
{
	/**
	* \brief Universally Unique Identifier
	*
	* A Universally Unique Identifier (UUID) is an identifier standard used in software construction,
	* standardized by the Open Software Foundation (OSF) as part of the Distributed Computing Environment
	* (DCE). The intent of UUIDs is to enable distributed systems to uniquely identify information without
	* significant central coordination. Thus, anyone can create a UUID and use it to identify something
	* with reasonable confidence that the identifier will never be unintentionally used by anyone for
	* anything else. Information labeled with UUIDs can therefore be later combined into a single database
	* without needing to resolve name conflicts
	*
	* \ingroup inspection
	* \author Golaem <dev@golaem.com>
	*/
	struct GLM_CORE_API Uuid
	{
	public:

		/**
		* \brief default constructor
		*
		* set the uuid to 0
		*/
		Uuid();

		/**
		* \brief constructor
		*
		* Uuid must be generated by an external tool, guidgen.exe on windows and uuidgen on linux
		*/
		Uuid(const char* uuid);

		/**
		* \brief destructor
		*/
		~Uuid();

		/**
		* \brief copy constructor
		*/
		Uuid(const Uuid &uuid);

		/**
		* \brief assignment operator
		*/
		Uuid &operator=(const Uuid& uuid);

		/**
		* \brief equality operator
		*/
		bool operator==(const Uuid& uuid) const;

		/**
		* \brief difference operator
		*/
		bool operator!=(const Uuid& uuid) const;

		/**
		* \brief inferior operator
		*/
		bool operator<(const Uuid& uuid) const;

		/**
		* \brief superior operator
		*/
		bool operator>(const Uuid& uuid) const;

		/**
		* \brief addition operator
		*/
		Uuid operator+(const Uuid& uuid) const;

		/**
		* \brief addition operator
		*/
		Uuid operator+(unsigned int i) const;

		/**
		* \brief create a new Uuid
		*/
		void createUuid();

		/**
		* \brief compare the Uuid to 0
		*/
		bool isNull() const;

		/**
		* \brief get Accessor to the Uuid as a string
		*/
		glm::GlmString getString() const;
	private:

		unsigned int _data0;
		unsigned short _data1;
		unsigned short _data2;
		unsigned char _data3[8];
	};

	/**
	* \brief Insert an uuid into a stream.
	*/
	inline std::ostream & operator<<(std::ostream & stream, const Uuid & uuid)
	{
		stream << uuid.getString();
		return stream;
	}

	//------------------------------------------------------------------------------------------
	// copy constructor
	//------------------------------------------------------------------------------------------
	inline Uuid::Uuid(const Uuid &uuid)
	{
		*this = uuid;
	}

	//------------------------------------------------------------------------------------------
	// operator=
	//------------------------------------------------------------------------------------------
	inline Uuid&
		Uuid::operator=(const Uuid& uuid)
	{
		if (this != &uuid)
		{
			memcpy(this, &uuid, sizeof(Uuid));
		}
		return *this;
	}

	//------------------------------------------------------------------------------------------
	// operator==
	//------------------------------------------------------------------------------------------
	inline bool
		Uuid::operator==(const Uuid& uuid) const
	{
		return !memcmp(this, &uuid, sizeof(Uuid));
	}

	//------------------------------------------------------------------------------------------
	// operator!=
	//------------------------------------------------------------------------------------------
	inline bool
		Uuid::operator!=(const Uuid& orig) const
	{
		return !(*this == orig);
	}

	//------------------------------------------------------------------------------------------
	// operator<
	//------------------------------------------------------------------------------------------
	inline bool
		Uuid::operator<(const Uuid& uuid) const
	{
		return memcmp(this, &uuid, sizeof(Uuid)) > 0;
	}

	//------------------------------------------------------------------------------------------
	// operator>
	//------------------------------------------------------------------------------------------
	inline bool
		Uuid::operator>(const Uuid& uuid) const
	{
		return memcmp(this, &uuid, sizeof(Uuid)) < 0;
	}
}
