/* QST.C  Copyright (C) 1993 Fergus Patrick Duniho */

#define MAXLINE 256

typedef struct qnode {
    int p[2];
    int num, ans, first;
    char *Qtext, *Atext[2];
    struct qnode *pv, *nx;
} qst;

qst *RND_QList (qst *Q, int size);
char *Get_QList (char *fname, qst *Q, int size);
void AskQuestions (qst *Q, int col);
int AskQ (qst *Q, int col);
char get_answer(int col);
qst *new_qnode (int num);

qst *new_qnode (int num) {
    qst *node;

    if ((node = (qst *)malloc(sizeof(qst))) == NULL) {
      perror ("Malloc can't allocate enough memory for a new qnode.\n");
      exit (2);
   }
   node->ans = -1;
   node->num = num;
   return node;
}

/* Get_QList: Reads questions from a file into a linked list.
   Returns the version # string from the beginning of the
   questions file. */

char *Get_QList (char *fname, qst *Q, int size) {
    FILE *fptr;
    int i, j;
    char *V;
    qst *S;

    S = Q;
    RdOpen (fptr, fname);
    V = clone_line(fptr, MAXLINE);
    for (i = 1; i <= size; i++) {
	Q->nx = new_qnode(i);
	Q->nx->pv = Q;
	Q = Q->nx;
	Q->Qtext = clone_line(fptr, MAXLINE);
	for (j = 0; j < 2; j++) {
	    Q->p[j] = fgetp(fptr);
	    Q->Atext[j] = clone_line(fptr, MAXLINE);
	}
    }
    fclose (fptr);
    Q->nx = S;
    return V;
}

/* nth_qnode: Returns the nth member of a linked list of qst nodes. */

qst *nth_qnode (qst *Q, unsigned int n) {
    while (n--)
	Q = Q->nx;
    return Q;
}

/* RND_QList: Randomizes a linked list of questions. */

qst *RND_QList (qst *Q, int size) {
    qst *S, *L, *N, *SN;
    unsigned int i;

    SN = N = new_qnode(0);  /* Randomizes Question Order */
    S = Q;
    for (; size; size--) {
	i = (rand() % size) + 1;
	L = nth_qnode(S, i);
	L->nx->pv = L->pv;
	L->pv->nx = L->nx;
	N->nx = L;
	L->pv = N;
	N = L;
	N->first = rand() % 2; /* Randomizes Answer Order */
    }
    free (S);
    N->nx = SN;
    SN->pv = N;
    return SN;
}

void AskQuestions (qst *Q, int col) {
    int more = 1, flag = 1, num;

    while (more) {
	for (Q = Q->nx, num = 1; Q->num > 0; Q = Q->nx, num++) {
	    if ((Q->ans != -1) && flag)
		continue;
	    flag = 1;
	    printf ("\nQuestion #%d\n", num);
	    if (AskQ(Q, col)) {
		Q = Q->pv->pv;
		flag = 0;
		num -= 2;
		if (num < 0) num = 0;
	    }
	}
	more = 0;
	for (Q = Q->nx; Q->num > 0; Q = Q->nx)
	    if (Q->ans == -1) more = 1;
    }
}

/* AskQ: Asks a single question. */

int AskQ (qst *Q, int col) {
    char A;

    wrapwrite (stdout, 0, 0, col, Q->Qtext, 0);
    wrapwrite (stdout, 0, 4, col, "(A)", Q->Atext[0], 0);
    puts (" ... Or");
    wrapwrite (stdout, 0, 4, col, "(B)", Q->Atext[1], 0);
    if ((A = get_answer(col)) < 2)
	Q->ans = Q->p[A];
    else if (A == 4)
	exit (2);
    return A == 3;
}

char get_answer(int col) {
    char c;

    for (;;) {
	c = fgetc(stdin);
	while (fgetc(stdin) != '\n');
	if (islower(c))
	    c = toupper(c);
	if (c == 'A')
	    return 0;
	if (c == 'B')
	    return 1;
	if (c == 'S')
	    return 2;
	if (c == 'P')
	    return 3;
	if (c == 'Q')
	    return 4;
	wrapwrite (stdout, 0, 0, col,
	    "Answer with an A or a B.\n",
	    "P = Go back to Previous question\n",
	    "Q = Quit\n",
	    "S = Skip until later.\n", 0);
    }
}
