/*****************************************************************************/
/*									     */
/*									     */
/*	X patience - loadsave.c						     */
/*									     */
/*	written by Heiko Eissfeldt and Michael Bischoff			     */
/*									     */
/*	24-Feb-1993: First release (0.1)				     */
/*	19-Mar-1993: POSIX.1 now optional				     */
/*	24-Mar-1993: changed filename "log" to "xpat.log"		     */
/*									     */
/*									     */
/*****************************************************************************/

#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif

#include <limits.h>

#ifndef _POSIX_NAME_MAX
#  undef _POSIX_SOURCE		/* seems that we have no POSIX system! */
#  define NAME_MAX	14	/* every UNIX should have at least this */
#else
#  include <unistd.h>		/* for pathconf() */
#  include <sys/utsname.h>	/* for uname() */
#endif

#include <time.h>

#include "xpat.h"
#include "version.h"

#define MAGIC	0x7419

#define WERR(msg)	fprintf(stderr, "Saving of game FAILED. %s\n", msg)


static void read_err(const char *msg)
{   fprintf(stderr, "Loading of saved game FAILED. %s\n", msg);
    exit(1);
}

static void portable_to_internal(long *args, unsigned char *p, int num)
{
    do {
	int j;
	*args = 0;
	for (j = 0; j < 4; ++j)
	    *args += (long)p[3-j] << (j << 3);
	++args;
	p += 4;
    } while (--num);
}

static void internal_to_portable(unsigned char *p, long *args, int num)
{
    do {
	int j;
	memset(p, (*args < 0 ? -1 : 0), 4);
	for (j = 0; j < 4; ++j)
	    p[3-j] = (unsigned char)(*args >> (j << 3));
	++args;
	p += 4;
    } while (--num);
}

void load_game(const char *file)
{   FILE *fp;
    char buffer[32];
    long args[16];
    int i;
    unsigned char p[16 * 4];

    if (!(fp = fopen(file, "r")))
	read_err("File could not be opened");
    if (fread(buffer, 1, 32, fp) != 32 ||
	fread(p, 4, 16, fp) != 16)
	read_err("Error reading header");
    portable_to_internal(args, p, 16);
    if (args[15] != MAGIC)
	read_err("Magic match failed");
    new_rules(buffer, args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
    if (game.numalloc < args[9]) {
	free(game.move);
	mem_alloc(args[9]);
    }
    /* (*rules.new_game)(args[8]); */	/* must do that later */
    game.seed = args[8];
    game.stored_moves = args[9];
    game.n_moves = args[10];
    game.cheat_count = args[11];
    game.finished = args[12];
    game.flipnum = args[13];
    for (i = 0; i < game.stored_moves; i += 16) {
	if (fread(p, 4, 16, fp) != 16) {
	    read_err("Error reading moves");
	    break;
	}
	portable_to_internal((long *)(game.move+i), p, 16);
    }
    fclose(fp);
}


void save_game(const char *file)
{   FILE *fp;
    char buffer[32];
    char filename[64];	/* must be 15 at least */
    long args[16];
    int i;
    unsigned char p[4 * 16];

    if (!file) {
	/* compute the filename to use */
	long name_max;

#ifdef NAME_MAX	
	name_max = NAME_MAX;
#else
	if ((name_max = pathconf(".", _PC_NAME_MAX)) == -1L)
	    name_max = _POSIX_NAME_MAX;	/* error => use 14 chars */
#endif
	if (name_max >= sizeof(filename))
	    name_max = sizeof(filename) - 1;
	if (strlen(rules.shortname) <= name_max - 10)	/* is OK */
	    sprintf(filename, "%s.%09ld", rules.shortname, game.seed);
	else {
	    strncpy(filename, rules.shortname, name_max - 9);
	    sprintf(filename + name_max - 9, "%09ld", game.seed);
	}
	file = filename;
    }
    if (!(fp = fopen(file, "w"))) {
	show_message("Saving of game FAILED. Could not open file");
	goto werr2;
    }
    strcpy(buffer, rules.shortname);
    args[0] = args[1] = args[2] = args[3] = args[4] = args[5] = args[6] =
	args[7] = -1;
    if (rules.variant & CUSTOM_DECKS)
	args[0] = rules.numdecks;
    if (rules.variant & CUSTOM_SLOTS)
	args[1] = rules.numslots;
    if (rules.variant & CUSTOM_FACEUP)
	args[2] = rules.faceup;
    if (rules.variant & CUSTOM_FACEDOWN)
	args[3] = rules.facedown;
    if (rules.variant & CUSTOM_JOKERS)
	args[4] = rules.numjokers;
    if (rules.variant & CUSTOM_FLIPS)
	args[5] = rules.numflips;
    if (rules.variant & CUSTOM_TURNS)
	args[6] = rules.numturns;
    args[ 8] = game.seed;
    args[ 9] = game.stored_moves;
    args[10] = game.n_moves;
    args[11] = game.cheat_count;
    args[12] = game.finished;
    args[13] = game.flipnum;
    args[14] = -1;
    args[15] = MAGIC;
    internal_to_portable(p, args, 16);
    if (fwrite(buffer, 1, 32, fp) != 32 ||
	fwrite(p, 4, 16, fp) != 16) {
	show_message("Saving of game FAILED. Could not write header");
	goto werr;
    }
    for (i = 0; i < game.stored_moves; i += 16) {
	internal_to_portable(p, (long *)(game.move+i), 16);
	if (fwrite(p, 4, 16, fp) != 16) {
	    show_message("Saving of game FAILED. Could not write moves");
	    goto werr;
	}
    }
    fclose(fp);
    show_message("Saving the game succeeded.");
    sun_sound("ok");	/* found no sound file for this. maybe later */
    return;

werr:
    fclose(fp);
werr2:
    sun_sound("cannotsave");
}

void write_log_file(void)
{   time_t t;
    FILE *fp;

#ifdef _POSIX_SOURCE
    struct utsname utsname;
    const char *username;
#endif

    t = time((time_t *)0);

    if (!(fp = fopen(SCOREFILE, "a"))) {
	fprintf(stderr, "xpat: warning: cannot write to log file "
		SCOREFILE "\n");
	return;		/* cannot write to file */
    }
    fprintf(fp, "\n%s", ctime(&t));

#ifdef _POSIX_SOURCE
    if ((username = getlogin()))
	fprintf(fp, "  \"%s\"", username);
    else
#endif
	fprintf(fp, "  someone");

#ifdef _POSIX_SOURCE
    if (uname(&utsname) >= 0)
	fprintf(fp, " on %s\n  running %s Version %s (%s)\n ",
		utsname.nodename,
		utsname.sysname, utsname.release, utsname.version);
#endif

    fprintf(fp, " finished patience %s\n", rules.shortname);
    if (rules.variant & CUSTOM_DECKS)
	fprintf(fp, "  with %d decks\n", rules.numdecks);
    if (rules.variant & CUSTOM_SLOTS)
	fprintf(fp, "  with %d slots\n", rules.numslots);
    if (rules.variant & CUSTOM_FACEUP)
	fprintf(fp, "  with %d cards faceup\n", rules.faceup);
    if (rules.variant & CUSTOM_FACEDOWN)
	fprintf(fp, "  with %d cards facedown\n", rules.facedown);
    if (rules.variant & CUSTOM_JOKERS)
	fprintf(fp, "  with %d jokers\n", rules.numjokers);
    if (rules.variant & CUSTOM_TURNS)
	fprintf(fp, "  %d cards turned at a time\n", rules.numturns);
    if (rules.numflips)
	fprintf(fp, "  flipping the deck %d times\n", game.flipnum);
    fprintf(fp, "  xpat version %s, game seed %9ld with %d moves\n",
	    VERSION, game.seed, game.n_moves);
    if (game.cheat_count)
	fprintf(fp, "  and cheatet! (count = %d)\n", game.cheat_count);
    else
	fprintf(fp, "  in a truly noble manner!\n");
    fclose(fp);
}
