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

#define MAXLINE 256

typedef struct qnode {
    int p[2]; /* Preference Array Numbers */
    int num, ans, strength;
    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);
int get_strength (int col);

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, j;
    char *temp;

    SN = N = new_qnode(0);
    S = Q;

    /* Randomizes Answer Order */
    for (i = 0; i < size; i++)
        if (rand() % 2) {
            L = nth_qnode(S, i);
            j = L->p[1]; L->p[1] = L->p[0]; L->p[0] = j;
            temp = L->Atext[1];
            L->Atext[1] = L->Atext[0];
            L->Atext[0] = temp;
        }

    /* Randomizes Question Order */
    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;
    }
    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];
        Q->strength = get_strength(col);
    }
    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);
    }
}

int get_strength (int col) {
    int i;
    wrapwrite (stdout, 0, 0, col, "Please rate the strength of this",
        "preference on a scale of 1 to 7.\n",
        "1 = Faint\n",
        "2 = Weak\n",
        "3 = Modest\n",
        "4 = Moderate\n",
        "5 = Strong\n",
        "6 = Extreme\n",
        "7 = Excessive\n", 0);
    for (;;) {
        i = fgetp(stdin);
        if (i < 8)
            break;
        wrapwrite (stdout, 0, 0, col,
            "Please select a number from 1 to 7.", 0);
    }
    return i;
}
