/*
	ZazouMiniWebServer

	Copyright (C) 2003-2011 Xavier Garreau <xavier@xgarreau.org>

	This file is part of ZazouMiniWebServer.

    ZazouMiniWebServer 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; either version 2 of the License, or
    (at your option) any later version.

    ZazouMiniWebServer 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 ZazouMiniWebServer; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/

// ZMWSFileUtils.cpp: implementation of the ZMWSFileUtils class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ZMWSFileUtils.h"

#ifdef WIN32
#define aSlash		'\\'
#define twoSlashes	"\\\\"
#define slashPtPt	"\\.."
#else
#define aSlash		'/'
#define twoSlashes	"//"
#define slashPtPt	"/.."
#endif

ZMWSFileUtils::ZMWSFileUtils() {
#ifdef WIN32
	handle = INVALID_HANDLE_VALUE;
#else
	wasStatedAndIsOK = false;
	dirData = NULL;
	dirEntry = NULL;
#endif
}

ZMWSFileUtils::~ZMWSFileUtils() { 
#ifdef WIN32
	if (handle != INVALID_HANDLE_VALUE) {
		FindClose(handle);
	}
	handle = INVALID_HANDLE_VALUE;
#else
	if (dirData) {
		closedir(dirData);
	}
#endif
}


BOOL ZMWSFileUtils::fileExists(const std::string& fileName) {
	ZMWSFileUtils zfu;
	zfu.getFile(fileName);
	return zfu.fileExists();
}

BOOL ZMWSFileUtils::normalizePath(std::string& aPath) {
#ifdef WIN32
	std::replace(aPath.begin(), aPath.end(), '/','\\');
#endif
	std::string::size_type ptptPos;
	std::string::size_type aSlashPos;
	std::string::size_type twoSlashPos;
	do {
		twoSlashPos = aPath.find(twoSlashes);
		if (twoSlashPos != std::string::npos) {
			aPath = aPath.substr(0, twoSlashPos) + aPath.substr(twoSlashPos+1);
		}
	} while (twoSlashPos != std::string::npos);
	do {
		ptptPos = aPath.find(slashPtPt);
		if (ptptPos != std::string::npos) {
			aSlashPos = aPath.rfind(aSlash, ptptPos-1);
			if (aSlashPos != std::string::npos) {
				aPath = aPath.substr(0, aSlashPos) + aPath.substr(ptptPos+3);
			} else {
				break;
			}
		}
	} while (ptptPos != std::string::npos);
	return ZMWSFileUtils::fileExists(aPath);
}

BOOL ZMWSFileUtils::normalizeUrl (std::string& anUrl) {
	std::string tmpUrl = anUrl;
	std::string::size_type i = 0;
	std::string::size_type len = anUrl.length();
	unsigned char c;
	char tmpStr[3];

	anUrl = "";
	while (i<len) {
		c = tmpUrl[i];
		if (c>127) {
			anUrl += "%";
			anUrl += _ultoa(c & 0x000000FF, tmpStr, 16);
		} else {
			anUrl += c;
		}
		++i;
	}
	return TRUE;
}

BOOL ZMWSFileUtils::getFile(const std::string& searchPath) {
#ifdef WIN32
	if (handle != INVALID_HANDLE_VALUE)
		FindClose(handle);
	handle = FindFirstFile(searchPath.c_str(), &fileData);
	return handle != INVALID_HANDLE_VALUE;
#else
	BOOL isErr = FALSE;
	if (!dirData) this->searchPath = searchPath;
	wasStatedAndIsOK = (0 == stat(searchPath.c_str(), &fileData));
	if (!wasStatedAndIsOK) return false;
	
	return wasStatedAndIsOK;	
#endif
}

BOOL ZMWSFileUtils::fileExists() {
#ifdef WIN32
	return (handle != INVALID_HANDLE_VALUE);
#else
	return wasStatedAndIsOK;
#endif
}

BOOL ZMWSFileUtils::isDir() {
#ifdef WIN32
	return ((handle != INVALID_HANDLE_VALUE) && (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
#else
	return (wasStatedAndIsOK && (fileData.st_mode & S_IFDIR));
#endif
}

BOOL ZMWSFileUtils::isFile() {
#ifdef WIN32
	return ((handle != INVALID_HANDLE_VALUE) && !(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
#else
	return (wasStatedAndIsOK && (fileData.st_mode & S_IFREG));
#endif
}

BOOL ZMWSFileUtils::getNextFile() {
#ifdef WIN32
	if (handle == INVALID_HANDLE_VALUE) return FALSE;
	return FindNextFile(handle, &fileData);
#else
	if (!dirData) {
		dirData = opendir(searchPath.c_str());
	}
	if (!dirData) return FALSE;
	
	dirEntry = readdir (dirData);
	if (!dirEntry) {
		closedir (dirData);
		dirData = NULL;
		return FALSE;
	}
	return getFile(searchPath+"/"+dirEntry->d_name);
#endif
}

std::string ZMWSFileUtils::getFileName() {
#ifdef WIN32
	if (handle == INVALID_HANDLE_VALUE) return "";
	return fileData.cFileName;
#else
	if ( dirData && dirEntry ) {
		return dirEntry->d_name;
	} else {
		print_dbg ("!(dirData && dirEntry)\n"); 
		return searchPath;
	}
	return "";
#endif
}

/*
BOOL ZMWSFileUtils::isReadOnly()
{
	if (handle == INVALID_HANDLE_VALUE) return TRUE;
	return ((fileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY);
}
*/

std::string ZMWSFileUtils::getFileSize() {
#ifdef WIN32
	if (handle == INVALID_HANDLE_VALUE) return "";
	std::stringstream tmpSS;
	tmpSS << fileData.nFileSizeLow;
#else
	if (!wasStatedAndIsOK) return "";
	std::stringstream tmpSS;
	tmpSS << fileData.st_size;
#endif
	return tmpSS.str();
}

DWORD ZMWSFileUtils::getFileSizeN() {
#ifdef WIN32
	if (handle == INVALID_HANDLE_VALUE) return 0;
	return fileData.nFileSizeLow;
#else
	if (!wasStatedAndIsOK) return 0;
	return fileData.st_size;
#endif
}

std::string ZMWSFileUtils::getFileSizeH(){
	std::stringstream tmpSS;
	DWORD Size;
	std::string SizeUnit("");
	
#ifdef WIN32
	if (handle == INVALID_HANDLE_VALUE) return "";
	// On considère que les fichiers seront < 4Go ...
	Size = fileData.nFileSizeLow;
#else
	if (!wasStatedAndIsOK) return "";
	Size = fileData.st_size;
#endif	
	
	if (Size>1024) {
		Size /= 1024;
		SizeUnit = "k";
	}
	if (Size>1024) {
		Size /= 1024;
		SizeUnit = "M";
	}
	if (Size>1024) {
		Size /= 1024;
		SizeUnit = "G";
	}
	tmpSS << Size << SizeUnit;
	return tmpSS.str();
}

std::string ZMWSFileUtils::getWriteDate() {
	std::stringstream tmpSS;
	SYSTEMTIME sysTime;
	
#ifdef WIN32
	if (handle == INVALID_HANDLE_VALUE) return "";
	FILETIME fileTime = fileData.ftLastWriteTime;
	FileTimeToSystemTime (&fileTime, &sysTime);
#else
	if (!wasStatedAndIsOK) return "";
	GetSystemTime (&sysTime, fileData.st_mtime);
#endif

	if (sysTime.wDay<10)
		tmpSS << "0";
	tmpSS << sysTime.wDay << '/';

	if (sysTime.wMonth<10)
		tmpSS << "0";
	tmpSS << sysTime.wMonth << '/';

	if (sysTime.wYear<10)
		tmpSS << "0";
	tmpSS << sysTime.wYear << " ";

	if (sysTime.wHour<10)
		tmpSS << "0";
	tmpSS << sysTime.wHour << ":";

	if (sysTime.wMinute<10)
		tmpSS << "0";
	tmpSS << sysTime.wMinute;
		
	return tmpSS.str();
}

std::string ZMWSFileUtils::getWriteDateSort()
{
	std::stringstream tmpSS;
	SYSTEMTIME sysTime;

#ifdef WIN32
	if (handle == INVALID_HANDLE_VALUE) return "";
	FILETIME fileTime = fileData.ftLastWriteTime;
	FileTimeToSystemTime (&fileTime, &sysTime);
#else
	if (!wasStatedAndIsOK) return "";
	GetSystemTime (&sysTime, fileData.st_mtime);
#endif

	if (sysTime.wYear<10)
		tmpSS << "0";
	tmpSS << sysTime.wYear;

	if (sysTime.wMonth<10)
		tmpSS << "0";
	tmpSS << sysTime.wMonth;

	if (sysTime.wDay<10)
		tmpSS << "0";
	tmpSS << sysTime.wDay;

	if (sysTime.wHour<10)
		tmpSS << "0";
	tmpSS << sysTime.wHour;

	if (sysTime.wMinute<10)
		tmpSS << "0";
	tmpSS << sysTime.wMinute;

	if (sysTime.wSecond<10)
		tmpSS << "0";
	tmpSS << sysTime.wSecond;

	return tmpSS.str();
}

std::string ZMWSFileUtils::getExtension(const std::string& fileName) {
		int extensionPos = fileName.rfind('.');
		std::string extension("");
		if (extensionPos != std::string::npos) 
			extension = fileName.substr(extensionPos+1);

		return extension;
}

std::string ZMWSFileUtils::getWriteDateRFC1123() {
	std::stringstream tmpSS;
	SYSTEMTIME sysTime;

#ifdef WIN32
	if (handle == INVALID_HANDLE_VALUE) return "";
	FILETIME fileTime = fileData.ftLastWriteTime;
	FileTimeToSystemTime (&fileTime, &sysTime);
#else
	if (!wasStatedAndIsOK) return "";
	GetSystemTime (&sysTime, fileData.st_mtime);
#endif

	switch (sysTime.wDayOfWeek) {
		case 0: tmpSS << "Sun, "; break;
		case 1: tmpSS << "Mon, "; break;
		case 2: tmpSS << "Tue, "; break;
		case 3: tmpSS << "Wed, "; break;
		case 4: tmpSS << "Thu, "; break;
		case 5: tmpSS << "Fri, "; break;
		case 6: tmpSS << "Sat, "; break;
	}
	
	if (sysTime.wDay<10)
		tmpSS << "0";
	tmpSS << sysTime.wDay << " ";

	switch (sysTime.wMonth) {
		case 1: tmpSS << "Jan "; break;
		case 2: tmpSS << "Feb "; break;
		case 3: tmpSS << "Mar "; break;
		case 4: tmpSS << "Apr "; break;
		case 5: tmpSS << "May "; break;
		case 6: tmpSS << "Jun "; break;
		case 7: tmpSS << "Jul "; break;
		case 8: tmpSS << "Aug "; break;
		case 9: tmpSS << "Sep "; break;
		case 10: tmpSS << "Oct "; break;
		case 11: tmpSS << "Nov "; break;
		case 12: tmpSS << "Dec "; break;
	}

	tmpSS << sysTime.wYear << " ";

	if (sysTime.wHour<10)
		tmpSS << "0";
	tmpSS << sysTime.wHour << ":";

	if (sysTime.wMinute<10)
		tmpSS << "0";
	tmpSS << sysTime.wMinute << ":";

	if (sysTime.wSecond<10)
		tmpSS << "0";
	tmpSS << sysTime.wSecond << " GMT";

	return tmpSS.str();
}

/* Formats de date:
      Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
      Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
      Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
*/
