#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#ifdef WINNT
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#endif

#define error_IMPORT
#include "error.h"
#undef error_IMPORT


void error_init(char *prog_name)
{
	error_prog_name = prog_name;
	
#ifdef WINNT
	if( AllocConsole() ){
		// FIXME: what if something goes wrong here? try writing to stdxxx anyway...
		int hCrt;
		FILE *hf;
		
		// Remap stdout to the console:
		hCrt = _open_osfhandle( (long) GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
		if( hCrt == -1 )
			error_internal("_open_osfhandle() on STD_OUTPUT_HANDLE", 0);
		hf = _fdopen(hCrt, "w");
		if( hf == NULL )
			error_internal("_fdopen() failed on STD_OUTPUT_HANDLE", 0);
		*stdout = *hf;
		/* ignore = */ setvbuf(stdout, NULL, _IONBF, 0);
		
		// Remap stderr to the console:
		hCrt = _open_osfhandle( (long) GetStdHandle(STD_ERROR_HANDLE), _O_TEXT);
		if( hCrt == -1 )
			error_internal("_open_osfhandle() on STD_ERROR_HANDLE", 0);
		hf = _fdopen(hCrt, "w");
		if( hf == NULL )
			error_internal("_fdopen() failed on STD_ERROR_HANDLE", 0);
		*stderr = *hf;
		/* ignore = */ setvbuf(stderr, NULL, _IONBF, 0);
		
		// Make the console (nearly) invisible:
		ShowWindow(GetConsoleWindow(), SW_HIDE);
	}
#endif
}


void error_internal_PRIVATE(char *file, int line, char *fmt, ...)
{
	va_list ap;
	char s[999];

	va_start(ap, fmt);
	vsnprintf(s, sizeof(s), fmt, ap);
	va_end(ap);
	fflush(stdout);
	fprintf(stderr, "%s internal error in %s:%d: %s.\n",
		error_prog_name, file, line, s);
	abort();
}

void error_external(char *fmt, ...)
{
	va_list ap;
	char s[999];

	va_start(ap, fmt);
	vsnprintf(s, sizeof(s), fmt, ap);
	va_end(ap);
	fflush(stdout);
	fprintf(stderr, "%s: %s.\n", error_prog_name, s);
	exit(1);
}

void error_system(char *fmt, ...)
{
	int err;
	va_list ap;
	char s[999];

	err = errno; // save current value of errno
	va_start(ap, fmt);
	vsnprintf(s, sizeof(s), fmt, ap);
	va_end(ap);
	fflush(stdout);
	fprintf(stderr, "%s: %s: %s.\n", error_prog_name, s, strerror(err));
	exit(1);
}
