/*
   sys/sys.cc
   This file is part of the Osirion project and is distributed under
   the terms of the GNU General Public License version 2
*/


#ifdef _WIN32

#include <windows.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <direct.h>

#else

#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>

#endif

#include <stdio.h>
#include <stdlib.h>
#include <string>

#include "sys/sys.h"

namespace sys
{

bool file_exists(const std::string &filename)
{
#ifdef _WIN32
	struct ::_stat path_stat;
	memset(&path_stat, 0, sizeof(struct ::_stat));

	if (::_stat(filename.c_str(), &path_stat) != 0) {
		return false;
	}

	if (path_stat.st_mode & _S_IFDIR) {
		return false;
	}
	return true;
#else
	struct stat path_stat;
	memset(&path_stat, 0, sizeof(path_stat));

	if (stat(filename.c_str(), &path_stat) != 0) {
		return false;
	}

	if (path_stat.st_mode & S_IFDIR) {
		return false;
	}

	return true;
#endif
}


bool directory_exists(const std::string &path)
{
#ifdef _WIN32
	struct ::_stat path_stat;
	memset(&path_stat, 0, sizeof(struct ::_stat));

	if (::_stat(path.c_str(), &path_stat) != 0) {
		return false;
	}

	if (path_stat.st_mode & _S_IFDIR) {
		return true;
	}
	return false;
#else
	struct stat path_stat;
	memset(&path_stat, 0, sizeof(path_stat));

	if (stat(path.c_str(), &path_stat) != 0) {
		return false;
	}

	if (path_stat.st_mode & S_IFDIR) {
		return true;
	}

	return false;
#endif
}

void mkdir(const std::string &path)
{
#ifdef _WIN32
	std::string p(path);
	for (size_t i = 0; i < p.size(); i++)
		if (p[i] == '/') p[i] = '\\';
	if (p.size() && (p[p.size()-1] == '\\'))
		p.erase(p.size() - 1, 1);

	if (_mkdir(p.c_str()) != 0) {
		con_warn << "Could not create directory '" << p << "'" << std::endl;
	}
#else

	::mkdir(path.c_str(), 0777);
#endif
}

void signal(int signum, signalfunc handler)
{
#ifndef _WIN32
	struct sigaction sa;

	sa.sa_sigaction = 0;
	memset(&sa.sa_mask, 0 , sizeof(sigset_t));
	sa.sa_flags = 0;
	sa.sa_handler = handler;

	::sigaction(signum, &sa, 0);
#endif
}

void sleep(long milliseconds)
{
#ifndef _WIN32
	::usleep((useconds_t)(milliseconds * 1000));
#else
	Sleep((DWORD)milliseconds);
#endif
}

/*

POSIX:

	struct tm {
		int tm_sec;         // seconds
		int tm_min;         // minutes
		int tm_hour;        // hours
		int tm_mday;        // day of the month
		int tm_mon;         // month
		int tm_year;        // year
		int tm_wday;        // day of the week
		int tm_yday;        // day in the year
		int tm_isdst;       // daylight saving time
	};

WIN32:

	typedef struct _SYSTEMTIME {
		WORD wYear;
		WORD wMonth;
		WORD wDayOfWeek;
		WORD wDay;
		WORD wHour;
		WORD wMinute;
		WORD wSecond;
		WORD wMilliseconds;
	} SYSTEMTIME, *PSYSTEMTIME;

*/

void get_localtime(int & year, int & month, int & day, int & hours, int & minutes, int & seconds, int & milliseconds)
{
#ifndef _WIN32
	struct ::timeval tv;
	struct ::timezone tz;
	struct ::tm localtime;
	
	::gettimeofday(&tv, &tz);
	::localtime_r(&tv.tv_sec, &localtime);

	year = localtime.tm_year + 1900;
	month = localtime.tm_mon + 1;
	day = localtime.tm_mday;

	hours = localtime.tm_hour;
	minutes = localtime.tm_min;
	seconds = localtime.tm_sec;
	milliseconds =  + tv.tv_usec / 1000;
#else
	SYSTEMTIME localtime;
	::GetLocalTime(&localtime);

	year = localtime.wYear;
	month = localtime.wMonth;
	day = localtime.wDay;

	hours = localtime.wHour;
	minutes = localtime.wMinute;
	seconds = localtime.wSecond;
	milliseconds = localtime.wMilliseconds;
#endif
}

void get_localtime(int & hours, int & minutes, int & seconds) {
	int year, month, day, milliseconds;	
	get_localtime(year, month, day, hours, minutes, seconds, milliseconds);
}

void quit(int status)
{
	::exit(status);
}

}