/*
 * @(#)HexagonsU.c
 *
 * Copyright 1994 - 2023  David A. Bagley, bagleyd AT verizon.net
 *
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of the author not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 *
 * 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.
 */

/* Undo algorithm for Hexagons */

#include "HexagonsP.h"

static int startSpacePosition[SPACES];
static int startSpaceRow[ROW_TYPES];
int *startPosition = NULL;

static void
newStack(HexagonsStack *s)
{
	if (s->lastMove != NULL || s->firstMove != NULL)
		return;
	if (!(s->lastMove = (MoveStack *) malloc(sizeof (MoveStack)))) {
		DISPLAY_ERROR("Not enough memory, exiting.");
	}
	if (!(s->firstMove = (MoveStack *) malloc(sizeof (MoveStack)))) {
		DISPLAY_ERROR("Not enough memory, exiting.");
	}
	s->firstMove->previous = s->lastMove->next = NULL;
	s->firstMove->next = s->lastMove;
	s->lastMove->previous = s->firstMove;
	s->count = 0;
}

static void
pushStack(HexagonsStack *s, MoveRecord **move)
{
	if (!(s->currMove = (MoveStack *) malloc(sizeof (MoveStack)))) {
		DISPLAY_ERROR("Not enough memory, exiting.");
	}
	s->lastMove->previous->next = s->currMove;
	s->currMove->previous = s->lastMove->previous;
	s->currMove->next = s->lastMove;
	s->lastMove->previous = s->currMove;
	*move = &(s->currMove->move);
	s->count++;
}

static void
popStack(HexagonsStack *s)
{
	s->currMove = s->lastMove->previous;
	s->lastMove->previous->previous->next = s->lastMove;
	s->lastMove->previous = s->lastMove->previous->previous;
	free(s->currMove);
	s->count--;
}

static MoveRecord *
topStack(HexagonsStack *s)
{
	return &(s->lastMove->previous->move);
}

static int
emptyStack(HexagonsStack *s)
{
	return (s->lastMove->previous == s->firstMove);
}

static void
flushStack(HexagonsStack *s)
{
	while (s->lastMove->previous != s->firstMove) {
		s->currMove = s->lastMove->previous;
		s->lastMove->previous->previous->next = s->lastMove;
		s->lastMove->previous = s->lastMove->previous->previous;
		free(s->currMove);
	}
	s->count = 0;
}

static void
deleteStack(HexagonsStack *s)
{
	flushStack(s);
	if (s->firstMove) {
		free(s->firstMove);
		s->firstMove = NULL;
	}
	if (s->lastMove) {
		free(s->lastMove);
		s->lastMove = NULL;
	}
}

/**********************************/

void
newMoves(HexagonsStack *s)
{
	newStack(s);
}

void
deleteMoves(HexagonsStack *s)
{
	deleteStack(s);
}

static void
writeMove(MoveRecord *move, int direction)
{
#if 0
	move->direction = direction;
#endif
	move->packed = (unsigned char) (direction & 0xF);
}

static void
readMove(MoveRecord *move, int *direction)
{
#if 0
	*direction = move->direction;
#endif
	*direction = (int) (move->packed & 0xF);
}

void
setMove(HexagonsStack *s, int direction)
{
	MoveRecord *move;

	pushStack(s, &move);
	writeMove(move, direction);
}

void
getMove(HexagonsStack *s, int *direction)
{
	readMove(topStack(s), direction);
	popStack(s);
}

int
madeMoves(HexagonsStack *s)
{
	return !emptyStack(s);
}

void
flushMoves(HexagonsWidget w, HexagonsStack *s, Boolean undo)
{
	int i;

	flushStack(s);
	if (undo) {
		startSpacePosition[LOW] = w->hexagons.spacePosition[LOW];
		startSpacePosition[HIGH] = w->hexagons.spacePosition[HIGH];
		startSpaceRow[TRBL] = w->hexagons.spaceRow[TRBL];
		startSpaceRow[TLBR] = w->hexagons.spaceRow[TLBR];
		startSpaceRow[ROW] = w->hexagons.spaceRow[ROW];
		for (i = 0; i < w->hexagons.sizeSize; i++)
			startPosition[i] = w->hexagons.tileOfPosition[i];
	}
}

int
numMoves(HexagonsStack *s)
{
	return s->count;
}

Boolean
scanMoves(FILE *fp, HexagonsWidget w, int moves)
{
	int direction, l, c;

	for (l = 0; l < moves; l++) {
		while ((c = getc(fp)) != EOF && c != SYMBOL);
		if (fscanf(fp, "%d", &direction) != 1) {
			(void) fprintf(stderr,
				"corrupt scan, expecting an integer for move %d\n", l);
			return False;
		}
		if (!movePuzzleDir(w, direction, INSTANT)) {
			(void) fprintf(stderr,
				"%d move in direction %d, cannot be made.",
				l, direction);
			return False;
		}
	}
	return True;
}

void
printMoves(FILE *fp, HexagonsStack *s)
{
	int direction, counter = 0;

	s->currMove = s->firstMove->next;
	(void) fprintf(fp, "moves\tdirection\n");
	while (s->currMove != s->lastMove) {
		readMove(&(s->currMove->move), &direction);
		(void) fprintf(fp, "%d%c\t%d\n", ++counter, SYMBOL, direction);
		s->currMove = s->currMove->next;
	}
}

Boolean
scanStartPosition(FILE *fp, HexagonsWidget w)
{
	int i, num, c;

	while ((c = getc(fp)) != EOF && c != SYMBOL);
	for (i = 0; i < w->hexagons.sizeSize; i++) {
		if (fscanf(fp, "%d ", &num) != 1) {
			(void) fprintf(stderr,
				"corrupt scan, expecting an integer for %d\n", i);
			return False;
		}
		startPosition[i] = num;
		if (!num)
			startSpacePosition[HIGH] = i;
		else if (num == -1)
			startSpacePosition[LOW] = i;
	}
	if (w->hexagons.corners) {
		startSpaceRow[HIGH] = toRow(w, startSpacePosition[HIGH]);
		if (w->hexagons.sizeX > 1 || w->hexagons.sizeY > 1)
			startSpaceRow[LOW] = toRow(w,
				startSpacePosition[LOW]);
	} else {
		startSpaceRow[ROW] = toRow(w, startSpacePosition[HIGH]);
		startSpaceRow[TRBL] = toTrBl(w, startSpacePosition[HIGH],
			startSpaceRow[ROW]);
		startSpaceRow[TLBR] = toTlBr(w, startSpacePosition[HIGH],
			startSpaceRow[ROW]);
	}
	return True;
}

void
printStartPosition(FILE *fp, HexagonsWidget w)
{
	int rowPos = 0, r = 0, rp, p, length = 0;

	(void) fprintf(fp, "\nstartingPosition%c\n", SYMBOL);
	for (p = 0; p < w->hexagons.sizeSize; p++) {
		if (rowPos == 0) {
			if (p < w->hexagons.sizeCenter) {
				length = w->hexagons.sizeX + r;
				for (rp = 0; rp < w->hexagons.sizeY - r - 1; rp++)
					(void) fprintf(fp, "  ");
			} else {
				length = 2 * w->hexagons.sizeY +
					w->hexagons.sizeX - r - 2;
				for (rp = 0; rp < r - w->hexagons.sizeY + 1; rp++)
					(void) fprintf(fp, "  ");
			}
		}
		(void) fprintf(fp, "%4d", startPosition[p]);
		if (rowPos == length - 1) {
			r++;
			rowPos = 0;
			(void) fprintf(fp, "\n");
		} else
			rowPos++;
	}
	(void) fprintf(fp, "\n");
}

void
setStartPosition(HexagonsWidget w)
{
	int i;

	w->hexagons.spacePosition[HIGH] = startSpacePosition[HIGH];
	w->hexagons.spacePosition[LOW] = startSpacePosition[LOW];
	w->hexagons.spaceRow[TRBL] = startSpaceRow[TRBL];
	w->hexagons.spaceRow[TLBR] = startSpaceRow[TLBR];
	w->hexagons.spaceRow[ROW] = startSpaceRow[ROW];
	for (i = 0; i < w->hexagons.sizeSize; i++)
		w->hexagons.tileOfPosition[i] = startPosition[i];
	drawAllTiles(w);
}
