/* vim: set ts=8 sts=4 sw=4 tw=80 noet: */
/*======================================================================
Copyright (C) 2004,2005,2009 Walter Doekes <walter+tthsum@wjd.nu>
This file is part of tthsum.

tthsum 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.

tthsum 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 tthsum.  If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#include "texts.h"

#include <assert.h>

#ifdef _WIN32
#    define WINDOWS_LEAN_AND_MEAN
#    include <windows.h>
#else /* !_WIN32 */
#    include <stdio.h>
#    include <string.h>
#    include <errno.h>
#endif /* !_WIN32 */


static int last_error = 0;
static int last_error_os = 0;
static const char* last_error_context = 0;
static char last_error_buf[512];

static const char* texts[] = {
    /* ERROR_FIRST */
    "No error yet",
    /* BASE32_INVALID_CHARACTER */
    "Invalid character encountered in BASE32 stream",
    /* ESCAPE_INVALID_ESCAPE */
    "Invalid escape sequence encountered",
    /* TEXTS_UNKNOWN_ERROR */
    "Unknown error",
    /* THEX_INVALID_BLOCK_SIZE */
    "The read operation isn't supplying multiples of 1024",
    /* TTHSUM_FILENAME_TOO_LARGE */
    "File name is too long",
    /* TTHSUM_LINE_CORRUPT */
    "Improperly formatted line",
    /* TTHSUM_MISMATCHED_TTH */
    "TTH check failed for",
    /* UTF8_INVALID_UNICODE */
    "Invalid character encountered in UNICODE stream",
    /* UTF8_INVALID_UTF8 */
    "Invalid character encountered in UTF8 stream",
    /* UTF8_OVERLONG_UTF8 */
    "Overlong character encountered in UTF8 stream"
    /* ERROR_LAST */
};

void set_error(char const* context, int error) {
    assert(strlen(context) < 32);
    if (error == -1) {
#ifdef _WIN32
	last_error = GetLastError();
#else /* !_WIN32 */
	last_error = errno;
#endif /* !_WIN32 */
	last_error_os = 1;
    } else {
	last_error = error;
	last_error_os = 0;
    }
    last_error_context = context;
}

const char* get_error() {
    if (!last_error_os) {
	return texts[last_error];
    } else {
#ifdef _WIN32
	DWORD w;
	int i;
	i = sprintf(last_error_buf, "%s: ", last_error_context);
	if ((w = FormatMessage(
		FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
		NULL, (DWORD)last_error, 0, last_error_buf + i, 480 - i, NULL)
	) != 0) { /* 32 is more than enough for " (int)" */
	    if (w >= 2)
		sprintf(last_error_buf + i + w - 2, " (0x%x)", last_error);
	} else {
	    sprintf(last_error_buf + i, ": %s (0x%x)",
		    get_text(TEXTS_UNKNOWN_ERROR), (unsigned)last_error);
	}
#else /* !_WIN32 */
	/* Avoid snprintf because it's not C90 */
	/* XXX this needs overflow checks! use strncpy and such! */
	/* was snprintf(last_error_buf, 511, ...) */
	sprintf(last_error_buf, "%s: %s (%i)", last_error_context,
		strerror(last_error), last_error);
#endif /* !_WIN32 */
	return last_error_buf;
    }
}

const char* get_text(enum text_id id) {
    return texts[id];
}
