#include "stdafx.h"

std::string SystemStringToStdString(System::String^ str){
	using namespace System;
	using namespace Runtime::InteropServices;
	const char* chars =
		(const char*)(Marshal::StringToHGlobalAnsi(str)).ToPointer();
	std::string result = chars;
	Marshal::FreeHGlobal(IntPtr((void*)chars));
	return result;
}

std::wstring SystemStringToStdWString(System::String^ str){
	using namespace System;
	using namespace Runtime::InteropServices;
	const wchar_t* chars =
		(const wchar_t*)(Marshal::StringToHGlobalUni(str)).ToPointer();
	std::wstring result = chars;
	Marshal::FreeHGlobal(IntPtr((void*)chars));
	return result;
}

INT64 GetByteValue(_TCHAR *str)
{
	INT64 value = 0;
	long double tempvalue = 0;
	int pointlen = 0;
	INT64 scale = 1;
	_TCHAR *p = str;
	for (; *p != NULL; p++){
		switch (*p){
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			if (pointlen){
				int digit = *p - '0';
				tempvalue *= 10;
				tempvalue += digit;
				pointlen++;
			}
			else{
				int digit = *p - '0';
				value *= 10;
				value += digit;
			}
		case ',':
			continue;
		case '.':
			pointlen = 1;
			continue;
		case 'k':
		case 'K':
			scale = 1024;
			break;
		case 'm':
		case 'M':
			scale = 1024 * 1024;
			break;
		case 'g':
		case 'G':
			scale = 1024 * 1024 * 1024;
			break;
		case 't':
		case 'T':
			scale = 1024LL * 1024 * 1024 * 1024;
			break;
		case 'p':
		case 'P':
			scale = 1024LL * 1024 * 1024 * 1024 * 1024;
			break;
		case 'e':
		case 'E':
			scale = 1024LL * 1024 * 1024 * 1024 * 1024 * 1024;
			break;
		default:
			return -1;
		}
		p++;
		break;
	}
	if (pointlen){
		pointlen--;
		tempvalue /= pow(10, pointlen);
		INT64 pvalue = INT64(tempvalue * scale);
		return value*scale + pvalue;
	}
	else {
		return value*scale;
	}
}

INT64 GetDateValue(_TCHAR *str)
{
	SYSTEMTIME datevalue = { 0 };

	WORD *value[] = {
		&datevalue.wYear,
		&datevalue.wMonth,
		&datevalue.wDay,
		&datevalue.wHour,
		&datevalue.wMinute,
		&datevalue.wSecond,
		&datevalue.wMilliseconds,
		NULL,
	};
	byte fieldcount[] = {
		4, 2, 2, 2, 2, 2, 3, 0 };
	FILETIME filetimevalue;


	_TCHAR *p = str;
	int digitcount = 0;
	for (int fc = 0; (*p != NULL) && fc<sizeof(fieldcount); p++){
		WORD *thisvalue = value[fc];
		switch (*p){
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		{
					WORD digit = *p - '0';
					*thisvalue *= 10;
					*thisvalue += digit;
					digitcount++;
					if (digitcount<fieldcount[fc]){
						continue;
					}
					break;
		}
		case NULL:
			continue;
		}
		if (digitcount){
			fc++;
			digitcount = 0;
		}
	}
	if (datevalue.wYear == 0){
		return 0;
	}
	if (datevalue.wMonth == 0){
		datevalue.wMonth = 1;
	}
	if (datevalue.wDay == 0){
		datevalue.wDay = 1;
	}
	FILETIME localfiletimevalue;
	if (SystemTimeToFileTime(&datevalue, &localfiletimevalue) &&
		LocalFileTimeToFileTime(&localfiletimevalue, &filetimevalue)){
		ULARGE_INTEGER value;
		value.HighPart = filetimevalue.dwHighDateTime;
		value.LowPart = filetimevalue.dwLowDateTime;
		return value.QuadPart;
	}
	else {
		return -1;
	}
}

_TCHAR *GetDecimalValue(_TCHAR *str, double *value)
{
	*value = 0;
	long double tempvalue = 0;
	int pointlen = 0;
	_TCHAR *p = str;
	for (; *p != NULL; p++){
		switch (*p){
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			if (pointlen){
				int digit = *p - '0';
				tempvalue *= 10;
				tempvalue += digit;
				pointlen++;
			}
			else{
				int digit = *p - '0';
				*value *= 10;
				*value += digit;
			}
			continue;
		case ',':
			break;
		case '.':
			pointlen = 1;
			continue;
		default:
			*value = -1;
			return p;
		}
		p++;
		break;
	}
	if (pointlen){
		pointlen--;
		tempvalue /= pow(10, pointlen);
		*value += tempvalue;
		return p;
	}
	else {
		return p;
	}
}

tstring filetimestr(const FILETIME &t)
{
	tstringstream ss;
	FILETIME t0;
	SYSTEMTIME t1;
	FileTimeToLocalFileTime(&t, &t0);
	if (FileTimeToSystemTime(&t0, &t1)){
		ss << std::setw(4) << std::setfill(_T('0')) << t1.wYear << '/';
		ss << std::setw(2) << std::setfill(_T('0')) << t1.wMonth << '/';
		ss << std::setw(2) << std::setfill(_T('0')) << t1.wDay << '_';
		ss << std::setw(2) << std::setfill(_T('0')) << t1.wHour << ':';
		ss << std::setw(2) << std::setfill(_T('0')) << t1.wMinute << ':';
		ss << std::setw(2) << std::setfill(_T('0')) << t1.wSecond << '.';
		ss << std::setw(3) << std::setfill(_T('0')) << t1.wMilliseconds;
	}
	return ss.str();
}

tstring bytestring(INT64 size)
{
	tstringstream ss;
	double d = (double)size;
	int i = 0;
	tstring Bprefix[] = { _T("Byte"), _T("KiB"), _T("MiB"), _T("GiB"), _T("TiB"), _T("PiB"), _T("EiB"), _T("ZiB"), _T("YiB") };
	while (d > 1024){
		d /= 1024;
		i++;
	}
	ss << std::fixed << std::setprecision(2) << d << Bprefix[i];
	return ss.str();
}

tstring timestring(double sec)
{
	tstringstream ss;
	int day = (int)(sec / (60 * 60 * 24));
	sec -= (double)day * 60 * 60 * 24;
	int hour = (int)(sec / (60 * 60));
	sec -= (double)hour * 60 * 60;
	int min = (int)(sec / 60);
	sec -= (double)min * 60;
	if (day > 0) {
		ss << day << _T("d");
	}
	ss << std::setw(2) << std::setfill(_T('0')) << hour << ':';
	ss << std::setw(2) << std::setfill(_T('0')) << min << ':';
	ss << std::fixed << std::setw(5) << std::setfill(_T('0')) << std::setprecision(2) << sec;
	return ss.str();
}

void printdatesize(const WIN32_FIND_DATA &fd)
{
	LARGE_INTEGER size;
	size.HighPart = fd.nFileSizeHigh;
	size.LowPart = fd.nFileSizeLow;
	_tprintf(_T("%s %I64d byte\t"), filetimestr(fd.ftLastWriteTime).c_str(), size.QuadPart);
}

int mainproc(BitcasaDLL::BitcasaWrapper^ API, param::paramdata& param)
{
	switch (param.mode)
	{
	case param::list:
		return listBitcasa(API, param);
	case param::local:
		return listLocal(param);
	case param::diff:
		return diffBitcasa(API, param);
	default:
		return 1;
	}
	return 0;
}