/* Copyright 2020, Michele Santullo
 * This file is part of orotool.
 *
 * Orotool 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 3 of the License, or
 * (at your option) any later version.
 *
 * Orotool 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 Orotool.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "dateconv.hpp"

#define HAS_UNCAUGHT_EXCEPTIONS 1
#include "date/date.h"

#include <sstream>
#include <clocale>
#include <memory>

namespace oro {
namespace {
	struct LocaleDeleter {
		void operator() (char* old_locale) {
			std::setlocale(LC_TIME, old_locale);
		}
	};

	Timestamp to_timestamp (const char* fmt, std::string&& str) {
		std::istringstream iss{std::move(str)};
		Timestamp ts;
		date::from_stream(iss, fmt, ts.ts);
		return ts;
	}

	typedef std::unique_ptr<char, LocaleDeleter> UniqueLocale;
} //unnamed namespace

//For formatting modifiers see:
//https://howardhinnant.github.io/date/date.html#from_stream_formatting

Timestamp from_json_timestamp (std::string&& str) {
	if (not str.empty() and str.back() == 'Z') {
		//date has this format: 2020-06-19T22:40:51Z
		return to_timestamp("%FT%TZ", std::move(str));
	}
	else {
		//date has this format: 2020-06-19T22:33:36.855672+00:00
		return to_timestamp("%FT%T%Ez", std::move(str));
	}
}

Timestamp from_header_timestamp (std::string&& str) {
	UniqueLocale loc(std::setlocale(LC_TIME, "POSIX"));
	//date has this format: Fri, 19 Jun 2020 22:33:43 GMT
	return to_timestamp("%a, %d %b %Y %T %Z", std::move(str));
}

Timestamp from_sqlite_timestamp (std::string&& str) {
	return to_timestamp("%F %T", std::move(str));
}

std::string to_sqlite_string (const oro::Timestamp& ts) {
	using date::operator<<;
	using std::chrono::seconds;
	using date::floor;
	using date::format;

	return format("%F %T", floor<seconds>(ts.ts));
}

//https://en.wikipedia.org/wiki/ISO_8601
std::string to_iso8601_string (const oro::Timestamp& ts) {
	using date::operator<<;
	using std::chrono::seconds;
	using date::floor;
	using date::format;

	return format("%FT%TZ", floor<seconds>(ts.ts));
}

} //namespace oro
