/* 
ZLib license:
Copyright (c) 2011 Dirk de la Hunt

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/

/*
This file does some Linux/Windows abstraction (thread anf file stuff).
*/
#ifndef __UTILS_H_
#define __UTILS_H_

#include <string.h>
#ifdef _WIN32
	#include <direct.h>
	#include <Windows.h>
	#include <process.h>
	#define THREADPROC(x) DWORD WINAPI x(void *Parameters)
	typedef LPTHREAD_START_ROUTINE THREADPROCPROTO;
	typedef HANDLE OSMutex;
#else
	#include <libgen.h>
	#include <unistd.h>
	#include <sys/stat.h>
	#include <sys/types.h>
	#include <sys/time.h>
	#include <pthread.h>
	#define THREADPROC(x) void* x(void *Parameters)
	typedef void* (*THREADPROCPROTO)(void *Parameters);
	typedef pthread_mutex_t OSMutex;
#endif

class Utils
{
public:
	static int Mkdir(const char *Path)
	{
#ifdef _WIN32
		return _mkdir(Path);
#else
		return mkdir(Path, S_IRWXU);
#endif
	}

	static bool FileExists(const char *Path)
	{
		FILE *file = fopen(Path, "r");
		if (!file)
			return false;
		fclose(file);
		return true;
	}

	static void Sleep(long Seconds)
	{
#ifdef _WIN32
		::Sleep(Seconds * 1000);
#else
		sleep(Seconds);
#endif
	}

	static char* GetExecutionPath(char *argv0)
	{
		char *path = new char[1024];

#ifdef _WIN32
		if (path)
		{
			const char *pos = strrchr(argv0, '\\');
			strncpy(path, argv0, pos-argv0);
			path[pos-argv0] = '\\';
			path[pos-argv0+1] = 0;
		}
#else
		if (path && readlink("/proc/self/exe", path, 1024) != -1)
		{
			dirname(path);
			strcat(path, "/");
		}
#endif
		return path;
	}

	static long GetSeconds()
	{
#ifdef _WIN32
		return GetTickCount() / 1000;
#else
		struct timeval  tv;
		gettimeofday(&tv, 0);
		return tv.tv_sec;
#endif
	}

	static bool CreateThread(THREADPROCPROTO ThreadFunction, void *Parameters)
	{
#ifdef _WIN32
		return ::CreateThread(0, 0, ThreadFunction, Parameters, 0, 0) != 0;
#else
		pthread_t thread;
		return pthread_create(&thread, 0, ThreadFunction, Parameters) == 0;
#endif
	}

	static int InitMutex(OSMutex *mutex)
	{
#ifndef _WIN32
        return pthread_mutex_init (mutex, NULL);
#else
        *mutex = CreateMutex(0, FALSE, 0);
        return (*mutex == 0);
#endif
        return -1;
	}

	static int FreeMutex(OSMutex *mutex)
	{
#ifndef _WIN32
        return pthread_mutex_destroy (mutex);
#else
		CloseHandle(*mutex);
		return 0;
#endif
        return -1;
	}

	static int LockMutex(OSMutex *mutex)
	{
#ifndef _WIN32
        return pthread_mutex_lock( mutex );
#else
        return (WaitForSingleObject(*mutex, INFINITE)==WAIT_FAILED ? 1 : 0);
#endif
	    return -1;
	}

	static int UnlockMutex(OSMutex *mutex)
	{
#ifndef _WIN32
		return pthread_mutex_unlock( mutex );
#else	
		return (ReleaseMutex(*mutex)==0);
#endif
		return -1;
	}

	/**
	 * C++ version 0.4 char* style "itoa":
	 * Written by Lukás Chmela
	 * Released under GPLv3.
	 * Originally from: http://www.jb.man.ac.uk/~slowe/cpp/itoa.html
	 */
	static char* itoa(int value, char* result, int base) 
	{
		// check that the base if valid
		if (base < 2 || base > 36) 
		{ 
			*result = '\0'; 
			return result; 
		}
	
		char* ptr = result, *ptr1 = result, tmp_char;
		int tmp_value;
	
		do 
		{
			tmp_value = value;
			value /= base;
			*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
		} 
		while (value);
	
		// Apply negative sign
		if (tmp_value < 0) 
			*ptr++ = '-';
		*ptr-- = '\0';

		while (ptr1 < ptr) 
		{
			tmp_char = *ptr;
			*ptr--= *ptr1;
			*ptr1++ = tmp_char;
		}

		return result;
	}
};

#endif
