// File:  KOHVIEW.CPP

#ifndef __BORLANDC__
#ifndef __TURBOC__
#error Borland C or Turbo C compiler required
#endif
#endif

#include <bios.h>
#include <ctype.h>
#include <dir.h>
#include <graphics.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <values.h>

#define BUFSIZE 1024

char
    programname [MAXFILE],
    buffer [BUFSIZE + 1],
    buf1 [BUFSIZE + 1],
    buf2 [BUFSIZE + 1],
    buf3 [BUFSIZE + 1];

int
    mapsize,
    celwidth,
    x0,
    y0,
    input_line,
    in_graph = 0;
float
    maxdif;

void
    syntax (),
    trim (),
    start_graph (),
    close_graph (),
    change_palette (),
    read_files (char const *basename),
    errit (char const *format, ...);
int
    getline (FILE *fp, int required, char const *filename);
FILE
    *r_fopen (char const *filename);

void main (int argc, char *argv [])
{
    fnsplit (argv [0], 0, 0, programname, 0);
    strupr (programname);

    if (argc != 2)
	syntax ();

    start_graph ();
    change_palette ();

    read_files (argv [1]);

    _bios_keybrd (_KEYBRD_READ);

    close_graph ();
}

void change_palette ()
{
    int	color [16][3] =			// red, green, blue
    {
        {  0,  0,  0},
        {  4,  4,  4},
        {  8,  8,  8},
        { 12, 12, 12},
	{ 16, 16, 16},
        { 20, 20, 20},
        { 24, 24, 24},
        { 28, 28, 28},
        { 32, 32, 32},
        { 36, 36, 36},
        { 40, 40, 40},
        { 44, 44, 44},
        { 48, 48, 48},
        { 52, 52, 52},
        { 56, 56, 56},
	{ 63, 63, 63}
    };

    palettetype
	pal;

    getpalette (&pal);

    for (int i = 0; i < 16; i++)
	setrgbpalette
	(
	    pal.colors [i],
	    color [i][0],
	    color [i][1],
	    color [i][2]
	);
}

void read_files (char const *basename)
{
    int
	x,
	y,
	n,
	c,
	x1,
	y1,
	x2,
	y2;
    float
	diff,
	mindiff,
	maxdiff,
	xc,
	yc,
	a1,
	a2,
	r,
	xf,
	yf,
	f;
    FILE
	*fp;

    maxdif = 0;
    sprintf (buf3, "%s.DIF", basename);
    fp = r_fopen (buf3);
    getline (fp, 1, buf3);
    mapsize = atoi (buffer);
    if (mapsize < 2)
	errit ("Illegal mapsize in \"%s\"", buf3);
    celwidth = getmaxy () / mapsize - 2;
    x0 = (getmaxx () - mapsize * celwidth) / 2;
    y0 = getmaxy () - ((getmaxy () - mapsize * celwidth) / 2);

    setlinestyle (SOLID_LINE, -1, 3);
    for (y = 1; y <= mapsize; y++)
	for (x = 1; x < mapsize; x++) {
	    getline (fp, 1, buf3);
	    f = atof (buffer);
	    if (f > maxdif)
		maxdif = f;
	}
    for (x = 1; x <= mapsize; x++)
	for (y = 1; y < mapsize; y++) {
	    getline (fp, 1, buf3);
	    f = atof (buffer);
	    if (f > maxdif)
		maxdif = f;
	}
    fclose (fp);
    fp = r_fopen (buf3);
    getline (fp, 1, buf3);
    for (y = 0; y < mapsize; y++)
	for (x = 1; x < mapsize; x++) {
	    getline (fp, 1, buf3);
	    f = atof (buffer);
	    c = f / maxdif * 22.0;
	    if (c > 15)
		c = 15;
	    setcolor (c);
	    line (
		x0 + celwidth * x,
		y0 - celwidth * y,
		x0 + celwidth * x,
		y0 - celwidth * (y + 1)
	    );
	}
    for (x = 0; x < mapsize; x++)
	for (y = 1; y < mapsize; y++) {
	    getline (fp, 1, buf3);
	    f = atof (buffer);
	    c = f / maxdif * 22.0;
	    if (c > 15)
		c = 15;
	    setcolor (c);
	    line (
		x0 + celwidth * x,
		y0 - celwidth * y,
		x0 + celwidth * (x + 1),
		y0 - celwidth * y
	    );
	}
    fclose (fp);

    sprintf (buf3, "%s.SPN", basename);
    fp = fopen (buf3, "r");
    if (fp) {
	maxdiff = 0;
	mindiff = MAXFLOAT;
	while (getline (fp, 0, 0)) {
	    sscanf (buffer, "%i %i %i %i %f", &x1, &y1, &x2, &y2, &diff);
            diff *= diff;
	    if (diff > maxdiff)
		maxdiff = diff;
	    if (diff < mindiff)
		mindiff = diff;
	}
	rewind (fp);
	input_line = 0;
	setlinestyle (SOLID_LINE, -1, 1);
        setcolor (7);
	while (getline (fp, 0, 0)) {
	    sscanf (buffer, "%i %i %i %i %f", &x1, &y1, &x2, &y2, &diff);
	    if (x1 != x2 || y1 != y2) {
                diff *= diff;
                if (maxdiff != mindiff)
                    setcolor (
                        15.5 - (diff - mindiff) / (maxdiff - mindiff) * 10.0
                    );
		if (abs (x1 - x2) == 1 || abs (y1 - y2) == 1)
		    line (
			x0 + (((float)x1) - 0.5) * celwidth,
			y0 - (((float)y1) - 0.5) * celwidth,
			x0 + (((float)x2) - 0.5) * celwidth,
			y0 - (((float)y2) - 0.5) * celwidth
		    );
		else {
		    if (x1 > x2 || (x1 == x2 && y1 > y2)) {
			c = x2; x2 = x1; x1 = c;
                        c = y2; y2 = y1; y1 = c;
                    }
                    x1 = (((float)x1) - 0.5) * celwidth;
                    y1 = (((float)y1) - 0.5) * celwidth;
                    x2 = (((float)x2) - 0.5) * celwidth;
                    y2 = (((float)y2) - 0.5) * celwidth;
                    xc = ((float)(x1 + x2)) / 2.0 - ((float)(y2 - y1));
                    yc = ((float)(y1 + y2)) / 2.0 + ((float)(x2 - x1));
                    a1 = atan2 (y1 - yc, x1 - xc) / M_PI * 180.0;
                    a2 = atan2 (y2 - yc, x2 - xc) / M_PI * 180.0;
                    r = sqrt (pow (x1 - xc, 2) + pow (y1 - yc, 2));
                    arc (x0 + xc, y0 - yc, a1, a2, r);
                }
	    }
	}
        fclose (fp);
    }

    setlinestyle (SOLID_LINE, -1, 1);
    setcolor (10);
    moveto (x0, y0);
    lineto (x0 + mapsize * celwidth, y0);
    lineto (x0 + mapsize * celwidth, y0 - mapsize * celwidth);
    lineto (x0, y0 - mapsize * celwidth);
    lineto (x0, y0);

    setcolor (15);
    settextjustify (CENTER_TEXT, CENTER_TEXT);
    sprintf (buf3, "%s.TOP", basename);
    fp = r_fopen (buf3);
    getline (fp, 1, buf3);
    if (mapsize != atoi (buffer))
	errit ("Wrong mapsize in \"%s\"", buf3);
    while (getline (fp, 0, 0)) {
        sscanf (buffer, "%f %f%n", &xf, &yf, &n);
        memmove (buffer, buffer + n, strlen (buffer) + 1);
        trim ();
	outtextxy (
	    x0 + (xf - 0.5) * celwidth,
	    y0 - (yf - 0.5) * celwidth,
            buffer
	);
    }
    fclose (fp);
}

FILE *r_fopen (char const *filename)
{
    FILE
	*fp;

    fp = fopen (filename, "r");
    if (! fp)
	errit ("Bestand \"%s\" niet gevonden", filename);
    input_line = 0;
    return fp;
}


int getline (FILE *fp, int required, char const *filename)
/* Lees een regel in
 * Plaats in buffer
 * Negeer lege regels en regels die beginnen met #
 */
{
    for (;;) {
	if (fgets (buffer, BUFSIZE, fp) == NULL) {
	    if (required)
		errit ("Unexpected end of file in \"%s\"", filename);
	    else
		return 0;
	}
	input_line++;
        trim ();
        if (buffer [0])
            return 1;
    }
}

void trim ()
{
    int
        i;

    // commentaar verwijderen
    for (i = 0; buffer [i]; i++)
        if (buffer [i] == '#' && (i == 0 || isspace (buffer [i - 1]))) {
            buffer [i] = '\0';
            break;
        }

    // spaties aan het einde verwijderen
    for (i = strlen (buffer) - 1; i >= 0; i--)
        if (isspace (buffer [i]))
            buffer [i] = '\0';
        else
            break;

    // voorloopspaties verwijderen
    for (i = 0; buffer [i] && isspace (buffer [i]); i++)
        ;
    memmove (buffer, buffer + i, strlen (buffer) + 1);
}

void start_graph ()
{
    int
	gdriver = DETECT,
	gmode,
	errorcode;

    registerbgidriver (EGAVGA_driver);
    initgraph (&gdriver, &gmode, getenv ("BGI"));
    errorcode = graphresult();
    if (errorcode != grOk) {
	errit (
	    "%s\n\n"
	    "Environment variable BGI can be used to point to\n"
	    "directory where graphic driver files are to be found",
	    grapherrormsg (errorcode)
	);
	exit (1);
    }
    in_graph = 1;
    if (getmaxcolor () < 15)
        errit ("16 colors required");
}

void close_graph ()
{
    if (in_graph) {
	closegraph ();
	in_graph = 0;
    }
}

void errit (char const *format, ...)
{
    va_list
	list;

    close_graph ();

    fprintf (stderr, "\nError %s: ", programname);

    va_start (list, format);
    vfprintf (stderr, format, list);

    fprintf (stderr, "\n\n");

    exit (1);
}

void syntax ()
{
    fprintf (
	stderr,
        "\nKohonen Map Viewer\n"
        "\n(c) P. Kleiweg 1996\n"
	"\nSyntax: %s basename\n",
	programname
    );
    exit (1);
}
