#include <stdio.h>
#include "fudgit.h"
#include "head.h"

extern int Ft_Debug;
extern int Ft_almost(register char *str1, register char *str2);

static int Ifst[MAXIF];
static int iffi = 0;

int Ft_pushif(int val)
{
	Ifst[iffi] = val;
	if (++iffi >= MAXIF) {
		fputs("Error: 'if' too deeply nested.\n", stderr);
		return(ERRR);
	}
	if (Ft_Debug & DEBUG_IF)
		fprintf(stderr, "Pushing value %d in if level %d.\n", val, iffi);
	return(0);
}

int Ft_popif(void)
{
	if (--iffi < 0) {
		fputs("Error: Unmatched 'endif'.\n", stderr);
		return(ERRR);
	}
	if (Ft_Debug & DEBUG_IF)
		fprintf(stderr,
		"Popping if level %d (value %d).\n", iffi+1, Ifst[iffi]);
	return(0);
}

int Ft_switchif(int val)
{
	if (iffi == 0) {
		fputs("Error: Unmatched 'else'.\n", stderr);
		return(ERRR);
	}
	if (Ft_Debug & DEBUG_IF)
		fprintf(stderr, "Switching level %d if from %d to %d.\n",
		iffi, Ifst[iffi-1], val);
	switch (Ifst[iffi-1]) {
	case DONE_IF:
		if (val == FORCED_IF)
			Ifst[iffi-1] = NFORCE_IF;
		break;
	case FALSE_IF:
		if (val == TRUE_IF)
			Ifst[iffi-1] = TRUE_IF;
		if (val == FORCED_IF)
			Ifst[iffi-1] = FORCED_IF;
		break;
	case TRUE_IF:
		if (val == FORCED_IF)
			Ifst[iffi-1] = NFORCE_IF;
		else
			Ifst[iffi-1] = DONE_IF;
		break;
	case NFORCE_IF:
	case FORCED_IF:
		fputs("else: Non-terminal 'else' in 'if' construction.\n", stderr);
		return(ERRR);
	case DUMMY_IF:
		fputs("else: Bad construction.\n", stderr);
		return(ERRR);
	default:
		fputs("else: Impossible case.\n", stderr);
		return(ERRR);
	}
	return(0);
}

static int Dcmode = 0;

int Ft_clearpop_if(void)
{
	iffi = 0;
	Dcmode = 0;
	return(0);
}

int Ft_iflevel(void)
{
	return(iffi);
}

int Ft_ifrun(int c, char *v)
{

	if (iffi == 0)
		return(TRUE_IF);
	/***
	fprintf(stderr, "iffi: %d | Dcmode: %d | argc: %d | argv[0]: '%s' \n",
	iffi, Dcmode, c, v);
	***/
	if (Ifst[iffi-1] != TRUE_IF &&
		Ifst[iffi-1] != FORCED_IF) { /* looking for endif or else */
		if (Ft_almost(v, "cm!ode") && c == 1) {
			if (Dcmode) {
				fputs("cmode: Double call to cmode.\n", stderr);
				return(ERRR);
			}
			Dcmode = 1;
			return(FALSE_IF);
		}
		else if (Ft_almost(v, "fm!ode")) {
			if (!Dcmode) {
				fputs("Warning: Double call to fmode.\n", stderr);
			}
			Dcmode = 0;
			return(FALSE_IF);
		}
		else if (!Dcmode && Ft_almost(v, "if")) {
			if (Ft_pushif(DUMMY_IF) == ERRR) /* push a dummy */
				return(ERRR);
		}
		else if (Ft_almost(v, "en!dif")) {
			if (Dcmode) {
				fputs("Error: 'endif' reached while still in cmode.\n",
				stderr);
				return(ERRR);
			}
			if (Ft_popif() == ERRR)  /* pop something */
				return(ERRR);
		}
		else if (Ft_almost(v, "el!se") && Ifst[iffi-1] != DUMMY_IF) {
			if (Dcmode) {
				fputs("Error: 'else' reached while still in cmode.\n",
				stderr);
				return(ERRR);
			}
			return(TRUE_IF);
		}
		return(FALSE_IF);
	}
	return(TRUE_IF);
}

int Ft_ifexp(char *cline)
{
	if (!iffi)
		return(YES);
	switch(Ifst[iffi-1]) {
		case FALSE_IF:  /* Waiting for an else or endif */
			if (Ft_almost(cline, "el!se "))
				return(YES);
		case DUMMY_IF:   /* somewhere nested in a false if */
		case NFORCE_IF:  /* Waiting for a endif */
		case DONE_IF:  /* Waiting for a endif */
			return(NO);
		case TRUE_IF:  /* For sure!  */
		case FORCED_IF:
			return(YES);
		default:
			fputs("Impossible case in ifexp().\n", stderr);
			return(0);
	}
}
