Newer
Older
Import / projects / Gameloft / glwebtools / source / glwebtools / glwebtools_glwebtools.cpp
#include <glwebtools/internal/glwebtools_default_config.h>
#include <glwebtools/internal/glwebtools_version.h>

#include <glwebtools/internal/glwebtools_glwebtoolscore.h>

#include <glwebtools/internal/glwebtools_macro.h>

#include <glwebtools/internal/glwebtools_handlemanager.h>

#include <glwebtools/os/glwebtools_thread.h>

#include <glwebtools/os/glwebtools_systemclock.h>

#include <glwebtools/glwebtools_error.h>


#include <list>
#include <sstream>
#include <limits>
//
//#define GLWEBTOOLS_URL_CONNECTION_HANDLE_TYPE		1
//#define GLWEBTOOLS_URL_REQUEST_HANDLE_TYPE		2

namespace glwebtools
{
	unsigned int GlWebToolsCore::s_urlConnectionHandleTypeId = 0;
	unsigned int GlWebToolsCore::s_urlRequestHandleTypeId = 0;

//error function
bool IsOperationSuccess(glwebtools::Error code)
{
	// may want to add extra processing if defined GLWEBTOOLS_DEBUG
	return code == glwebtools::E_SUCCESS;
}

extern bool GetAppInfo(glwebtools::String& appIdentifier, glwebtools::String& appVersion, glwebtools::String& osIdentifier, glwebtools::String& osVersion, glwebtools::String& deviceIdentifier);

GlWebTools::CreationSettings::CreationSettings()
:m_isThreadedUpdate(GLWEBTOOLS_WEBTOOLS_THREADED_UPDATE)
,m_threadedUpdatePeriod(GLWEBTOOLS_WEBTOOLS_THREADED_UPDATE_PERIOD)
,m_updateThreadPriority(GLWEBTOOLS_WEBTOOLS_THREADED_UPDATE_PRIORITY)
,m_connectionMinThreadCount(GLWEBTOOLS_DEFAULT_TASKGROUP_MIN_THREADS)
,m_connectionMaxThreadCount(GLWEBTOOLS_DEFAULT_TASKGROUP_MAX_THREADS)
,m_connectionThreadPriority(GLWEBTOOLS_DEFAULT_TASKGROUP_THREAD_PRIORITY)
,m_connectionHysteresis_ms(GLWEBTOOLS_DEFAULT_TASKGROUP_HYSTERESIS)
,m_maxThreadStartTime_ms(GLWEBTOOLS_DEFAULT_TASKGROUP_MAX_THREAD_STARTING_TIME)

{
	GetAppInfo(m_applicationIdentifier, m_applicationVersion, m_osIdentifier, m_osVersion, m_deviceIdentifier);
}

glwebtools::Error GlWebToolsCore::CreateInstance(GlWebToolsCore*& glWebToolsCore)
{
	GlWebToolsCore* temp = 0;
	temp = GLWEBTOOLS_NEW GlWebToolsCore();
	if (temp == 0)
	{
		return glwebtools::E_MEMORY_ERROR;
	}

	glWebToolsCore = temp;

	return glwebtools::E_SUCCESS;
}

glwebtools::Error GlWebToolsCore::DestroyInstance(GlWebToolsCore* glWebToolsCore)
{
	if(glWebToolsCore == 0)
		return E_INVALID_PARAMETER;

	if(glWebToolsCore->CanDelete() == false)
		return E_INVALID_OPERATION;

	GLWEBTOOLS_DELETE(glWebToolsCore);

	return glwebtools::E_SUCCESS;
}

bool GlWebToolsCore::CanDelete() const  
{
	LockScope _ls(m_mutex);

	return (m_refCount < 1) && (m_urlConnections.size() == 0) && (m_urlRequests.size() == 0);
}

bool GlWebToolsCore::HasRunningConnection()
{
	LockScope _ls(m_mutex);

	return _HasRunningConnection();
}

bool GlWebToolsCore::_HasRunningConnection()
{
	UrlConnectionRefMap::iterator iterConnection = m_urlConnections.begin();
	UrlConnectionRefMap::iterator endConnection = m_urlConnections.end();

	for(;iterConnection != endConnection; ++iterConnection)
	{
		if(iterConnection->second->GetState() == glwebtools::UrlConnection::S_RUNNING)
			return true;
	}

	return false;
}

unsigned int GlWebToolsCore::Grab()
{
	LockScope _ls(m_mutex);
	return Managed::Grab();
}

unsigned int GlWebToolsCore::Drop()
{
	LockScope _ls(m_mutex);
	return Managed::Drop();
}

bool GlWebToolsCore::IsInitialized() const
{
	return m_isInitialized;
}

glwebtools::Error GlWebToolsCore::Initialize(const GlWebTools::CreationSettings& cs)
{
//	LockScope _ls(m_mutex);
	if(!m_isInitialized)
	{
		if (s_urlConnectionHandleTypeId == 0)
		{
			if(!HandleManager::RegisterType(s_urlConnectionHandleTypeId))
			{
				//could not register handle type
	#ifdef GLWEBTOOLS_DEBUG
				GLWEBTOOLS_ASSERT(s_urlConnectionHandleTypeId);
				GLWEBTOOLS_LOG_FATAL_ERROR("%s", "Failed to register handlable object to handle manager");
	#endif
				return glwebtools::E_TYPE_REGISTRATION_ERROR;
			}
		}

		if (s_urlRequestHandleTypeId == 0)
		{
			if(!HandleManager::RegisterType(s_urlRequestHandleTypeId))
			{
				//could not register handle type
	#ifdef GLWEBTOOLS_DEBUG
				GLWEBTOOLS_ASSERT(s_urlRequestHandleTypeId);
				GLWEBTOOLS_LOG_FATAL_ERROR("%s", "Failed to register handlable object to handle manager");
	#endif
				return glwebtools::E_MEMORY_ERROR;
			}
		}

		//set user agent
		m_userAgent.clear();
		if(cs.m_applicationIdentifier.size() > 0)
		{
			m_userAgent.append(cs.m_applicationIdentifier);
			m_userAgent.append("/");
			m_userAgent.append(cs.m_applicationVersion);
		}

		m_userAgent.append(" GlWebTools/");
		m_userAgent.append(GLWEBTOOLS_VERSION);

		m_userAgent.append(" ");
		m_userAgent.append(cs.m_osIdentifier);
		m_userAgent.append("/");
		m_userAgent.append(cs.m_osVersion);

		m_userAgent.append(" (");
		m_userAgent.append(cs.m_deviceIdentifier);
		m_userAgent.append(")");

#if GLWEBTOOLS_USE_OPENSSL

		if (m_openSSL.IsInitialized() == false)
		{
#ifdef GLWEBTOOLS_DEBUG
			GLWEBTOOLS_LOG_FATAL_ERROR("%s", "Failed to initialize OpenSSL");
#endif
			return E_INITIALIZATION_ERROR;
		}
#endif //GLWEBTOOLS_USE_OPENSSL

		m_creationSettings = cs;
		if(m_creationSettings.m_isThreadedUpdate)
		{
			m_thread = GLWEBTOOLS_NEW glwebtools::Thread(GlWebToolsCore::UpdateStatic, this, 0, "GlWebToolsThread");
			if(m_thread)
			{
				m_isRunning = true;
				m_thread->Start(m_creationSettings.m_updateThreadPriority);
			}
			else
			{
#ifdef GLWEBTOOLS_DEBUG
				GLWEBTOOLS_ASSERT(m_thread);
				GLWEBTOOLS_LOG_FATAL_ERROR("%s", "Failed to create thread for threaded update");
#endif
				return E_INITIALIZATION_ERROR;
			}
		}

		GLWEBTOOLS_RETURN_ERROR_ON_FAIL(AddDefaultTaskGroup());
		TaskGroup::CreationSettings sseTaskGroupSettings;
		sseTaskGroupSettings.m_minThreadCount = 0;
		sseTaskGroupSettings.m_maxThreadCount = (unsigned int)(-1);
		sseTaskGroupSettings.m_hysteresis_ms = 0;
		sseTaskGroupSettings.m_maxThreadStartTime_ms = 1000;
		m_sseTaskGroup.Initialize(sseTaskGroupSettings);

		if(m_creationSettings.m_instanceName.empty())
		{
			std::stringstream ss;
			ss << std::hex << reinterpret_cast<glwebtools::uptr_t>(this);
			m_creationSettings.m_instanceName = ss.str();
		}
		m_isInitialized = true;

#ifdef GLWEBTOOLS_DEBUG
		GLWEBTOOLS_LOG_VERBOSE("GlWebTools %s is running", GLWEBTOOLS_VERSION_COMPLETE);
#endif

		return glwebtools::E_SUCCESS;
	}

#ifdef GLWEBTOOLS_DEBUG
	GLWEBTOOLS_ASSERT(!s_isInitialized);
	GLWEBTOOLS_LOG_MINOR_ERROR("%s", "GlWebTools already initialized");
#endif

	return glwebtools::E_INVALID_OPERATION;
}

glwebtools::Error GlWebToolsCore::_WaitForCanDelete(unsigned int milliseconds)
{
	u64 accumulated_time = 0;

	while (CanDelete()==false && accumulated_time < milliseconds)
	{
		const u64 start_time = SystemClock::GetMilliseconds();

		glwebtools::Thread::Sleep(GLWEBTOOLS_URL_CONNECTION_SHUTDOWN_STEP_MS);

		const u64 end_time = SystemClock::GetMilliseconds();

		accumulated_time += (end_time - start_time);

		if(!m_creationSettings.m_isThreadedUpdate)
			Update();
	}

	return glwebtools::E_SUCCESS;
}

glwebtools::Error GlWebToolsCore::Terminate(unsigned int milliseconds)
{
	if (IsInitialized() == false)
		return glwebtools::E_SUCCESS;

	GLWEBTOOLS_RETURN_ERROR_ON_FAIL(Shutdown());

	GLWEBTOOLS_RETURN_ERROR_ON_FAIL(_WaitForCanDelete(milliseconds));

	return Terminate();
}

glwebtools::Error GlWebToolsCore::Terminate()
{
	LockScope _ls(m_mutex);

	if (IsInitialized() == false)
		return glwebtools::E_SUCCESS;

	m_shutdownInProgress = false;

	ClearTaskGroups();

	if(m_thread)
	{
		m_isRunning = false;
		m_thread->Join();

		GLWEBTOOLS_DELETE(m_thread);
		m_thread = 0;
	}

	//TODO force connection + request cleanup
	HandleManager* handleManager = glwebtools::HandleManager::GetInstance();

	//first update connection
	UrlConnectionRefMap::iterator iterConnection = m_urlConnections.begin();
	UrlConnectionRefMap::iterator endConnection = m_urlConnections.end();

	for(;iterConnection != endConnection; ++iterConnection)
	{
		if(handleManager)
			handleManager->UnregisterNode(iterConnection->second->GetToken());

		//Can only delete connection that are not running - will leak others ...
		if(iterConnection->second->CanDelete())
		{
			GLWEBTOOLS_DELETE(iterConnection->second);
		}
	}

	m_urlConnections.clear();

	//second update request
	UrlRequestRefMap::iterator iterRequest = m_urlRequests.begin();
	UrlRequestRefMap::iterator endRequest = m_urlRequests.end();

	for(;iterRequest != endRequest; ++iterRequest)
	{
		if(handleManager)
			handleManager->UnregisterNode(iterRequest->second->GetToken());

		//Can only delete request that are not running - will leak others ...
		if(iterRequest->second->CanDelete())
		{
			GLWEBTOOLS_DELETE(iterRequest->second);
		}
	}

	m_urlRequests.clear();

	m_isInitialized = false;

	return glwebtools::E_SUCCESS;
}

glwebtools::Error GlWebToolsCore::Shutdown()
{
	LockScope _ls(m_mutex);

	if (IsInitialized() == false)
		return glwebtools::E_SUCCESS;

	if (ShutdownInProgress() == true)
		return glwebtools::E_SUCCESS;

	m_shutdownInProgress = true;

	if(_HasRunningConnection())
	{		
		return _CancelAllConnections(); //Send a cancel instruction to all request
	}

	return glwebtools::E_SUCCESS;
}

bool GlWebToolsCore::ShutdownInProgress() const
{
	return m_shutdownInProgress;
}

UrlConnection GlWebToolsCore::CreateUrlConnection()
{
	return CreateUrlConnection(UrlConnection::CreationSettings());
}

UrlConnection GlWebToolsCore::CreateUrlConnection(const UrlConnection::CreationSettings& creationSettings)
{
	LockScope _ls(m_mutex);

	HandleManager* handleManager = glwebtools::HandleManager::GetInstance();

	if(IsInitialized() && handleManager && ShutdownInProgress() == false)
	{
		UrlConnection::CreationSettings  cs = creationSettings;
		if(cs.m_userAgent.empty())
		{
			cs.m_userAgent = m_userAgent;//set useragent if not set in the creation settings	
		}

		TaskGroup* taskGroup = 0;

		if (cs.m_supportServerSideEvent)
		{
			taskGroup = &m_sseTaskGroup;
		}
		else
		{
			taskGroup = GetTaskGroup(cs.m_taskGroupId);
			if (taskGroup == 0)
			{
	#ifdef GLWEBTOOLS_DEBUG
			GLWEBTOOLS_LOG_MAJOR_ERROR("Task group with id %s doesn\'t exist", cs.m_taskGroupId.c_str());
	#endif
				return UrlConnection();
			}
		}
		
		UrlConnectionCore* urlConnection = GLWEBTOOLS_NEW UrlConnectionCore(cs, *taskGroup);

		if(urlConnection)
		{
			UrlConnection handle;

			unsigned int counter = HandleManager::GetNextCounterValue();
			unsigned int token = 0;
			bool result = handleManager->RegisterNode(s_urlConnectionHandleTypeId, counter, static_cast<void*>(urlConnection), token);
			
			if(result)
			{				
				urlConnection->SetToken(token);
				handle = UrlConnection(token); //implicit grab
				urlConnection->SetIntanceName(m_creationSettings.m_instanceName);
				m_urlConnections[reinterpret_cast<uptr_t>(urlConnection)] = urlConnection;
			}
			else
			{
				GLWEBTOOLS_DELETE(urlConnection);
			}
			
			return handle;
		}
	}

	return UrlConnection();
}

UrlRequest GlWebToolsCore::CreateUrlRequest()
{
	UrlRequest::CreationSettings cs;
	return CreateUrlRequest(cs);
}

UrlRequest GlWebToolsCore::CreateUrlRequest(UrlRequest::CreationSettings& cs)
{
	LockScope _ls(m_mutex);

	HandleManager* handleManager = glwebtools::HandleManager::GetInstance();

	if(IsInitialized() && handleManager && ShutdownInProgress() == false)
	{
		UrlRequestCore* urlRequest = GLWEBTOOLS_NEW UrlRequestCore(cs);

		if(urlRequest)
		{
			UrlRequest handle;

			unsigned int counter = HandleManager::GetNextCounterValue();
			unsigned int token = 0;
			bool result = handleManager->RegisterNode(s_urlRequestHandleTypeId, counter, static_cast<void*>(urlRequest), token);
			
			if(result)
			{				
				urlRequest->SetToken(token);
				handle = UrlRequest(token); //implicit grab
				m_urlRequests[reinterpret_cast<uptr_t>(urlRequest)] = urlRequest;
			}
			else
			{
				GLWEBTOOLS_DELETE(urlRequest);
			}
			
			return handle;
		}
	}

	return UrlRequest();
}

u64 GlWebToolsCore::UpdateTime()
{
	const u64 current_time = SystemClock::GetMilliseconds();
	const u64 last_update_time = m_last_update_time;
	m_last_update_time = current_time;

	if (last_update_time)
	{
		if (current_time > last_update_time)
		{
			return (current_time - last_update_time);
		}
		else
		{
			// roll-over
			return ((std::numeric_limits<u64>::max)() - last_update_time + current_time);
		}
	}

	// first update
	return 0;
}

glwebtools::Error GlWebToolsCore::Update()
{
	const u64 delta_time = UpdateTime();

	glwebtools::Error result = glwebtools::E_SUCCESS;

	if(m_mutex.TryLock())
	{
		HandleManager* handleManager = glwebtools::HandleManager::GetInstance();

		if(IsInitialized() && handleManager)
		{
			result = UpdateTaskGroups(delta_time); 
			if(GLWEBTOOLS_FAIL(result))
			{
				m_mutex.Unlock();
				return result;
			}

			for(UrlConnectionRefMap::iterator iterConnection = m_urlConnections.begin(); iterConnection != m_urlConnections.end(); ++iterConnection)
			{
				iterConnection->second->Update(delta_time);
			}

			std::list<uptr_t, glwebtools::SAllocator<uptr_t> > deleteList;

			//first update connection
			UrlConnectionRefMap::iterator iterConnection = m_urlConnections.begin();
			UrlConnectionRefMap::iterator endConnection = m_urlConnections.end();

			for(;iterConnection != endConnection; ++iterConnection)
			{
				if(iterConnection->second->CanDelete())
					deleteList.push_back(iterConnection->first);
			}

			while(deleteList.size() > 0)
			{
				uptr_t id = deleteList.front();
				deleteList.pop_front();
				iterConnection = m_urlConnections.find(id);
				if(iterConnection->second)
					handleManager->UnregisterNode(iterConnection->second->GetToken());
				GLWEBTOOLS_DELETE(iterConnection->second);
				m_urlConnections.erase(iterConnection);
			}

			//second update request
			UrlRequestRefMap::iterator iterRequest = m_urlRequests.begin();
			UrlRequestRefMap::iterator endRequest = m_urlRequests.end();

			for(;iterRequest != endRequest; ++iterRequest)
			{
				if(iterRequest->second->CanDelete())
					deleteList.push_back(iterRequest->first);
			}

			while(deleteList.size() > 0)
			{
				uptr_t id = deleteList.front();
				deleteList.pop_front();
				iterRequest = m_urlRequests.find(id);
				if(iterRequest->second)
					handleManager->UnregisterNode(iterRequest->second->GetToken());
				GLWEBTOOLS_DELETE(iterRequest->second);
				m_urlRequests.erase(iterRequest);
			}
		}
		else if(!IsInitialized())
		{
			result = glwebtools::E_INVALID_OPERATION;
		}
		else if(!handleManager)
		{
			result = glwebtools::E_INVALID_DATA;
		}

		m_mutex.Unlock();
	}

	return result;
}

bool GlWebToolsCore::CancelAllConnections()
{
	LockScope _ls(m_mutex);

	return GLWEBTOOLS_SUCCESS(_CancelAllConnections());
}

glwebtools::Error GlWebToolsCore::_CancelAllConnections()
{
	//first update connection
	UrlConnectionRefMap::iterator iterConnection = m_urlConnections.begin();
	UrlConnectionRefMap::iterator endConnection = m_urlConnections.end();

	for(;iterConnection != endConnection; ++iterConnection)
	{
		iterConnection->second->CancelRequest();
	}

	return glwebtools::E_SUCCESS;
}

GlWebToolsCore::~GlWebToolsCore()
{
	if(IsInitialized())
	{
#ifdef GLWEBTOOLS_DEBUG
		GLWEBTOOLS_ASSERT(false);
		GLWEBTOOLS_LOG_MAJOR_ERROR("%s", "Calling destructor on GlWebTools before deintialization");
#endif
	}

	Terminate(GLWEBTOOLS_URL_CONNECTION_SHUTDOWN_TIMEOUT_MS);
}

//private:
GlWebToolsCore::GlWebToolsCore()
:m_isInitialized(false)
,m_shutdownInProgress(false)
,m_isRunning(false)
,m_last_update_time(0)
{
	m_thread = 0;
}


void GlWebToolsCore::UpdateStatic(void* caller, void* /*param*/)
{
	GlWebToolsCore* glWebTools = static_cast<GlWebToolsCore*>(caller);

	if(glWebTools)
	{
		while(glWebTools->m_isRunning)
		{
			glWebTools->Update();
			glwebtools::Thread::Sleep(glWebTools->m_creationSettings.m_threadedUpdatePeriod); //update time is really short compared to period so no need to adjust sleep
		}
	}
}

const TaskGroup* GlWebToolsCore::GetTaskGroup(const TaskGroupId& id) const
{
	TaskGroupMap::const_iterator it = m_taskGroupMap.find(id);
	if (it == m_taskGroupMap.end())
		return 0;

	return it->second;
}

TaskGroup* GlWebToolsCore::GetTaskGroup(const TaskGroupId& id) 
{
	TaskGroupMap::iterator it = m_taskGroupMap.find(id);
	if (it == m_taskGroupMap.end())
		return 0;

	return it->second;
}

glwebtools::Error GlWebToolsCore::AddDefaultTaskGroup()
{
	TaskGroup::CreationSettings creationSettings;
	creationSettings.m_minThreadCount = m_creationSettings.m_connectionMinThreadCount;
	creationSettings.m_maxThreadCount = m_creationSettings.m_connectionMaxThreadCount;
	creationSettings.m_threadPriority = m_creationSettings.m_connectionThreadPriority;
	creationSettings.m_hysteresis_ms = m_creationSettings.m_connectionHysteresis_ms;
	creationSettings.m_maxThreadStartTime_ms = m_creationSettings.m_maxThreadStartTime_ms;

	return AddTaskGroup(GLWEBTOOLS_DEFAULT_TASKGROUP_ID, creationSettings);
}

glwebtools::Error GlWebToolsCore::AddTaskGroup(const TaskGroupId& id)
{
	TaskGroup::CreationSettings creationSettings;
	creationSettings.m_minThreadCount = GLWEBTOOLS_URL_CONNECTION_MIN_THREADS;
	creationSettings.m_maxThreadCount = GLWEBTOOLS_URL_CONNECTION_MAX_THREADS;
	creationSettings.m_threadPriority = GLWEBTOOLS_URL_CONNECTION_THREAD_PRIORITY;
	creationSettings.m_hysteresis_ms = GLWEBTOOLS_URL_CONNECTION_HYSTERESIS;
	creationSettings.m_maxThreadStartTime_ms = GLWEBTOOLS_URL_CONNECTION_MAX_THREAD_STARTING_TIME;

	return AddTaskGroup(id, creationSettings);
}

glwebtools::Error GlWebToolsCore::AddTaskGroup(const TaskGroupId& id, const TaskGroup::CreationSettings& creationSettings)
{
	TaskGroupMap::iterator it = m_taskGroupMap.find(id);
	if (it != m_taskGroupMap.end())
	{
#ifdef GLWEBTOOLS_DEBUG
		GLWEBTOOLS_LOG_MAJOR_ERROR("Task group with id \"%s\" already exists", id.c_str());
#endif
		return E_INVALID_PARAMETER;

	}

	TaskGroup* taskGroup = GLWEBTOOLS_NEW TaskGroup();
	
	if (taskGroup == 0)
		return E_MEMORY_ERROR;

	Error error = taskGroup->Initialize(creationSettings);
	if (GLWEBTOOLS_FAIL(error))
	{
#ifdef GLWEBTOOLS_DEBUG
		GLWEBTOOLS_LOG_MAJOR_ERROR("%", "Error when initializing task group");
#endif

		GLWEBTOOLS_DELETE(taskGroup);
		return error;
	}

	m_taskGroupMap[id] = taskGroup;

	return E_SUCCESS;
}

glwebtools::Error GlWebToolsCore::UpdateTaskGroups(u64 delta_time_ms)
{
	for (TaskGroupMap::const_iterator it = m_taskGroupMap.begin(); it != m_taskGroupMap.end(); ++it)
	{
		Error error = (*it).second->Update(delta_time_ms);
		if (GLWEBTOOLS_FAIL(error))
		{
	#ifdef GLWEBTOOLS_DEBUG
			GLWEBTOOLS_LOG_MAJOR_ERROR("%", "Error when updating task group");
	#endif
		}

	}

	Error error = m_sseTaskGroup.Update(delta_time_ms);
	if (GLWEBTOOLS_FAIL(error))
	{
#ifdef GLWEBTOOLS_DEBUG
		GLWEBTOOLS_LOG_MAJOR_ERROR("%", "Error when updating SSE task group");
#endif
	}

	return E_SUCCESS;
}

void GlWebToolsCore::ClearTaskGroups()
{
	for (TaskGroupMap::const_iterator it = m_taskGroupMap.begin(); it != m_taskGroupMap.end(); ++it)
	{
		GLWEBTOOLS_DELETE((*it).second);
	}

	m_taskGroupMap.clear();

	m_sseTaskGroup.Terminate();
}

/* GlWebTools */

GlWebTools::GlWebTools()
:m_glWebTools(0)
{

}

GlWebTools::~GlWebTools()
{
	Release();
}

GlWebTools::GlWebTools(const GlWebTools& rhs)
:m_glWebTools(rhs.m_glWebTools)
{
	if(m_glWebTools)
	{
		m_glWebTools->Grab();
		GLWEBTOOLS_ASSERT(m_glWebTools->IsInitialized());
	}
}

GlWebTools& GlWebTools::operator=(const GlWebTools& rhs)
{
	if(this == &rhs)
		return *this;

	Release();

	if(rhs.m_glWebTools)
	{
		m_glWebTools = rhs.m_glWebTools;
		m_glWebTools->Grab();
		GLWEBTOOLS_ASSERT(m_glWebTools->IsInitialized());
	}

	return *this;
}

glwebtools::Error GlWebTools::Release(unsigned int milliseconds)
{
	if(IsInitialized())
	{
		if (m_glWebTools->Drop() == 0)
		{
			m_glWebTools->Terminate(milliseconds);
			glwebtools::GlWebToolsCore::DestroyInstance(m_glWebTools);
		}

		m_glWebTools = 0;
	}
	
	return glwebtools::E_SUCCESS;
}

glwebtools::Error GlWebTools::Release()
{
	if(IsInitialized())
	{
		if (m_glWebTools->Drop() == 0)
		{
			m_glWebTools->Terminate(GLWEBTOOLS_URL_CONNECTION_SHUTDOWN_TIMEOUT_MS);
			glwebtools::GlWebToolsCore::DestroyInstance(m_glWebTools);
		}

		m_glWebTools = 0;
	}
	
	return glwebtools::E_SUCCESS;
}

glwebtools::Error GlWebTools::Initialize(const GlWebTools::CreationSettings& cs)
{
	if (IsInitialized())
		return glwebtools::E_INVALID_OPERATION;

	GLWEBTOOLS_RETURN_ERROR_ON_FAIL(glwebtools::GlWebToolsCore::CreateInstance(m_glWebTools));

	m_glWebTools->Grab();

	glwebtools::Error result = m_glWebTools->Initialize(cs);
	if (GLWEBTOOLS_FAIL(result))
	{
		Release();
	}

	return result;
}

glwebtools::Error GlWebTools::Shutdown()
{
	if(IsInitialized() == false)
		return glwebtools::E_INVALID_HANDLE;

	return m_glWebTools->Shutdown();
}

glwebtools::Error GlWebTools::Terminate(unsigned int milliseconds)
{
	if(IsInitialized() == false)
		return glwebtools::E_INVALID_HANDLE;

	if (m_glWebTools->m_refCount > 1)
	{
#ifdef GLWEBTOOLS_DEBUG
		GLWEBTOOLS_LOG_FATAL_ERROR("%s", "Failed to terminate glwebtools. There are still references on it.");
#endif	
		return glwebtools::E_INVALID_OPERATION; 
	}

	return Release(milliseconds);
}

glwebtools::Error GlWebTools::Terminate()
{
	return Terminate(GLWEBTOOLS_URL_CONNECTION_SHUTDOWN_TIMEOUT_MS);
}

UrlConnection GlWebTools::CreateUrlConnection()
{
	if(IsInitialized())
	{
		return m_glWebTools->CreateUrlConnection();
	}

	return UrlConnection();
}

UrlConnection GlWebTools::CreateUrlConnection(UrlConnection::CreationSettings& cs)
{
	if(IsInitialized())
	{
		return m_glWebTools->CreateUrlConnection(cs);
	}

	return UrlConnection();
}

UrlRequest GlWebTools::CreateUrlRequest()
{
	if(IsInitialized())
	{
		return m_glWebTools->CreateUrlRequest();
	}

	return UrlRequest();
}

UrlRequest GlWebTools::CreateUrlRequest(UrlRequest::CreationSettings& cs)
{
	if(IsInitialized())
	{
		return m_glWebTools->CreateUrlRequest(cs);
	}

	return UrlRequest();
}

glwebtools::Error GlWebTools::Update()
{
	if(IsInitialized())
	{
		return m_glWebTools->Update();
	}

	return glwebtools::E_INVALID_HANDLE;
}

bool GlWebTools::IsInitialized() const
{
	return m_glWebTools && m_glWebTools->IsInitialized();
}

bool GlWebTools::ShutdownInProgress() const
{
	return (IsInitialized() && m_glWebTools->ShutdownInProgress());
}

glwebtools::Error GlWebTools::AddTaskGroup(const TaskGroupId& id, const TaskGroup::CreationSettings& creationSettings)
{
	if(IsInitialized())
	{
		return m_glWebTools->AddTaskGroup(id, creationSettings);
	}

	return glwebtools::E_INVALID_HANDLE;
}

glwebtools::Error GlWebTools::AddTaskGroup(const TaskGroupId& id)
{
	if(IsInitialized())
	{
		return m_glWebTools->AddTaskGroup(id);
	}

	return glwebtools::E_INVALID_HANDLE;
}

} //namespace glwebtools