//       _________ __                 __
//      /   _____//  |_____________ _/  |______     ____  __ __  ______
//      \_____  \\   __\_  __ \__  \\   __\__  \   / ___\|  |  \/  ___/
//      /        \|  |  |  | \// __ \|  |  / __ \_/ /_/  >  |  /\___ |
//     /_______  /|__|  |__|  (____  /__| (____  /\___  /|____//____  >
//             \/                  \/          \//_____/            \/
//  ______________________                           ______________________
//                        T H E   W A R   B E G I N S
//         Stratagus - A free fantasy real time strategy game engine
//
/**@name translate.cpp - Translate languages. */
//
//      (c) Copyright 2005 by Jimmy Salmon
//
//      This program 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; only version 2 of the License.
//
//      This program 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 this program; if not, write to the Free Software
//      Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
//      02111-1307, USA.

#include "stratagus.h"

#include "translate.h"

#include "iolib.h"

typedef std::map<std::string, std::string> EntriesType;
static EntriesType Entries;

/**
**  Translate a string
*/
const char *Translate(const char *str)
{
	try {
		EntriesType::iterator i = Entries.find(str);
		if (i != Entries.end() && !i->second.empty()) {
			return i->second.c_str();
		} else {
			return str;
		}
	} catch (...) {
		std::throw_with_nested(std::runtime_error("Failed to get translation for string."));
	}
}

/**
**  Add a translation
*/
void AddTranslation(const char *str1, const char *str2)
{
	Entries[str1] = str2;
}

/**
**  Load a .po file
*/
void LoadPO(const char *file)
{
	if (!file || !*file) {
		return;
	}

	const std::string fullfile = LibraryFileName(file);
	FILE *fd = fopen(fullfile.c_str(), "rb");
	if (!fd) {
		fprintf(stderr, "Could not open file: %s\n", file);
		return;
	}
	enum { MSGNONE, MSGID, MSGSTR } state = MSGNONE;
	std::array<char, 16 * 1024> msgid{};
	std::array<char, 16 * 1024> msgstr{};
	char *currmsg = nullptr;

	msgid[0] = msgstr[0] = '\0';

	// skip 0xEF utf8 intro if found
	char c = fgetc(fd);
	if (c == static_cast<const char>(0xEF)) {
		fgetc(fd);
		fgetc(fd);
	} else {
		rewind(fd);
	}

	char buf[4096];
	while (fgets(buf, sizeof(buf), fd)) {
		// Comment
		if (buf[0] == '#') {
			continue;
		}
		char *s = buf;

		// msgid or msgstr
		if (!strncmp(s, "msgid ", 6)) {
			if (state == MSGSTR) {
				*currmsg = '\0';
				if (msgid.front() != '\0') {
					AddTranslation(msgid.data(), msgstr.data());
				}
			}
			state = MSGID;
			currmsg = msgid.data();
			*currmsg = '\0';
			s += 6;
			while (*s == ' ') { ++s; }
		} else if (!strncmp(s, "msgstr ", 7)) {
			if (state == MSGID) {
				*currmsg = '\0';
			}
			state = MSGSTR;
			currmsg = msgstr.data();
			*currmsg = '\0';
			s += 7;
			while (*s == ' ') { ++s; }
		}

		// String
		if (*s == '"') {
			++s;
			while (*s && *s != '"') {
				if (*s == '\\') {
					++s;
					if (*s) {
						if (*s == 'n') {
							*currmsg++ = '\n';
						} else if (*s == 't') {
							*currmsg++ = '\t';
						} else if (*s == 'r') {
							*currmsg++ = '\r';
						} else if (*s == '"') {
							*currmsg++ = '"';
						} else if (*s == '\\') {
							*currmsg++ = '\\';
						} else {
							fprintf(stderr, "Invalid escape character: %c\n", *s);
						}
						++s;
					} else {
						fprintf(stderr, "Unterminated string\n");
					}
				} else {
					*currmsg++ = *s++;
				}
			}
			continue;
		}
	}
	if (state == MSGSTR) {
		*currmsg = '\0';
		AddTranslation(msgid.data(), msgstr.data());
	}

	fclose(fd);
}

/** Set the stratagus and game translations
**
** Those filenames will be saved in the preferences when SavePreferences will be called.
**/
void SetTranslationsFiles(const char *stratagusfile, const char *gamefile)
{
	Entries.clear();
	LoadPO(stratagusfile);
	LoadPO(gamefile);
}
