
#include "ml_date.h"

long now() {
	// get-universal-time
	time_t t = std::time(0);
	long int now = static_cast<long int>(t);

	return now;
}

std::string date_to_string(const long datetime, const std::string format) {
	// std::locale::global(std::locale("en-US.UTF8"));

	time_t timestamp = datetime;
	char mbstr[128];

	if (std::strftime(mbstr, sizeof(mbstr), format.c_str(), std::localtime(&timestamp))) {
		std::string result = {mbstr};
		return result;
	}
	// TODO exception here
	return "invalid argument";
}

time_t time_to_epoch ( const struct tm *ltm, int utcdiff ) {
	//   const int mon_days [] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	const int mon_days [] = {31, 31+28, 31+28+31,
				 31+28+31+30, 31+28+31+30+31, 31+28+31+30+31+30,
				 31+28+31+30+31+30+31, 31+28+31+30+31+30+31+31, 31+28+31+30+31+30+31+31+30,
				 31+28+31+30+31+30+31+31+30+31, 31+28+31+30+31+30+31+31+30+31+30, 31+28+31+30+31+30+31+31+30+31+30+31};

	long tyears, tdays, leaps, utc_hrs;
	int i;

	tyears = ltm->tm_year - 70 ; // tm->tm_year is from 1900.
	leaps = (tyears + 2) / 4; // no of next two lines until year 2100.
	//i = (ltm->tm_year – 100) / 100;
	//leaps -= ( (i/4)*3 + i%4 );

	//   tdays = 0;
	//   for (i=0; i < ltm->tm_mon; i++) tdays += mon_days[i];
	tdays = mon_days[ltm->tm_mon-1];

	tdays += ltm->tm_mday-1; // days of month passed.
	tdays = tdays + (tyears * 365) + leaps;

	utc_hrs = ltm->tm_hour + utcdiff/3600; // for your time zone.
	return (tdays * 86400) + (utc_hrs * 3600) + (ltm->tm_min * 60) + ltm->tm_sec;
}

long string_to_date(const std::string &datestr, const std::string &format) {
	// format for example "%d.%m.%Y";

	struct tm tm;
	memset(&tm, 0, sizeof(tm));
	if (strptime(datestr.c_str(), format.c_str(), &tm)) {
		time_t curTime;
		struct tm * timeinfo;

		time(&curTime );
		timeinfo = localtime(&curTime);

		timeinfo->tm_year = tm.tm_year;
		timeinfo->tm_mon = tm.tm_mon;
		timeinfo->tm_mday = tm.tm_mday;
		timeinfo->tm_hour = tm.tm_hour;
		timeinfo->tm_min = tm.tm_min;
		timeinfo->tm_sec = tm.tm_sec;

		return time_to_epoch(timeinfo, -1 * timeinfo->tm_gmtoff);
	}

	// throw Exception("invalid date string or format");
	return -1;
}


long add_to_date(const long datetime, const long quantity, const std::string &part) {
	// part is one of 'year', 'month', 'day', 'hour', 'minute' or 'second'

	// very basic implementation, just for now - no timezones DST etc
	time_t base = datetime;
	struct tm *tm = localtime(&base);

	if (part == "year") {
		tm->tm_year += quantity;
	} else if (part == "month") {
		tm->tm_mon += quantity;
	} else if (part == "day") {
		tm->tm_mday += quantity;
	} else if (part == "hour") {
		tm->tm_hour += quantity;
	} else if (part == "minute") {
		tm->tm_min += quantity;
	} else if (part == "second") {
		tm->tm_sec += quantity;
	} else {
		// TODO exception here
	}

	return mktime(tm);
}
