/****************************************************************************
**
*A  read_word.c                 ANUPQ source                   Eamonn O'Brien
**
*Y  Copyright 1995-2001,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
*Y  Copyright 1995-2001,  School of Mathematical Sciences, ANU,     Australia
**
*/

#include "pq_defs.h"
#include "pcp_vars.h"
#include "constants.h"
#include "pq_functions.h"
#include "pretty_filterfns.h"
#include "word_types.h"

static void setup_relation(int disp,
                           int length,
                           int type,
                           Logical commutator,
                           int *t,
                           struct pcp_vars *pcp);
static int check_for_commutator(char *s);
static int check_for_symbol(char *s);
static int string_to_integer(char *s, int *integer);

/* display the appropriate input message */
static void display_message(int type)
{
   switch (type) {
   case LHS:
      printf("Input left-hand side of relation:\n");
      break;

   case RHS:
      printf("Input right-hand side of relation:\n");
      break;

   case WORD:
      printf("Input the word for collection:\n");
      printf("(use generators x1,x2,... and terminate with a semicolon)\n");
      break;

   case VALUE_A:
      printf("Input the value of a:\n");
      printf("(use generators x1,x2,... and terminate with a semicolon)\n");
      break;

   case VALUE_B:
      printf("Input the value of b:\n");
      break;

   case FIRST_ENTRY:
      printf("Input the first component of commutator:\n");
      break;

   case NEXT_ENTRY:
      printf("Input the next component of commutator:\n");
      break;
   case ACTION:
      break;
   }
}

/* set up array of generators x1, x2, .., xlastg and their
   inverses to represent the pcp generators of the group;
   this permits words to be input using the pretty format */

void setup_symbols(struct pcp_vars *pcp)
{
   int i, j, k, m;
   int log, digit;

   /* space for this array may have been previously allocated */
   /* memory leak September 1996 */

   if (user_gen_name != NULL) {
      num_gens = user_gen_name[0].first;

      for (i = 1; i <= num_gens; ++i) {
         free_vector(user_gen_name[i].g, 0);
      }
      free(user_gen_name);
      user_gen_name = NULL;
      free_vector(inv_of, 0);
      free_vector(pairnumber, 0);
   }

   paired_gens = pcp->lastg;
   num_gens = 2 * paired_gens;
   user_gen_name = anu_valloc(word, num_gens + 1);
   inv_of = anu_valloc(gen_type, num_gens + 1);
   pairnumber = anu_valloc(int, num_gens + 1);

   /* memory leak September 1996 */
   user_gen_name[0].first = num_gens;

   for (i = 1; i <= paired_gens; i++) {
      j = i;
      word_init(user_gen_name + 2 * i - 1);
      word_init(user_gen_name + 2 * i);
      word_put_last(user_gen_name + 2 * i - 1, 'x');
      word_put_last(user_gen_name + 2 * i, 'x');
      /* extract the digits of the number, i, from left to right */
      log = log10((double)j);
      for (k = log; k >= 0; --k) {
         m = int_power(10, k);
         digit = j / m;
         word_put_last(user_gen_name + 2 * i - 1, digit + '0');
         word_put_last(user_gen_name + 2 * i, digit + '0');
         j %= m;
      }
      word_put_last(user_gen_name + 2 * i, '^');
      word_put_last(user_gen_name + 2 * i, '-');
      word_put_last(user_gen_name + 2 * i, '1');
      inv_of[2 * i - 1] = 2 * i;
      inv_of[2 * i] = 2 * i - 1;
      pairnumber[2 * i] = pairnumber[2 * i - 1] = i;
   }
}

/* read in a word using the basic format;
   type determines the message printed out;
   store the word with address ptr which has value lused + 1 + disp;
   y[ptr] is the length of the word (includes exponent);

   if the word is one side of a relation, and it is a commutator,
   then y[ptr] is the negative of the length, as this allows
   collect_relations to recognise that this word is a commutator;

   y[ptr + 1] is the exponent;

   y[ptr + 2] .. y[ptr + length] are generators (either defining or pcp)
   or their inverses */

void read_word(FILE *file, int disp, int type, struct pcp_vars *pcp)
{
   Logical finish = FALSE;
   Logical commutator = FALSE;
   char s[MAXWORD];
   int t[MAXWORD];
   int integer, temp;
   int length = 0;
   int nmr_items;

   display_message(type);

   while (!finish && (nmr_items = fscanf(file, "%s", s)) != EOF) {

      verify_read(nmr_items, 1);

      while (s[0] == COMMENT) {
         read_line();
         nmr_items = fscanf(file, "%s", s);
         verify_read(nmr_items, 1);
      }

      /* check for end of relation marker */
      if (check_for_symbol(s))
         finish = TRUE;

      /* check for commutator symbol */
      if (!commutator)
         commutator = check_for_commutator(s);

      /* convert string to integer */
      integer = 0;
      temp = string_to_integer(s, &integer);

      if (integer == 0 && !(commutator || finish || *s == ',')) {
         printf("Error in input data -- %s\n", s);
         if (!isatty(0))
            exit(FAILURE);
      }

      if (integer != 0) {
         if ((length == 0 && temp == 0) || temp != 0) {
            t[length] = temp;
            ++length;
         }
      }
   }

   setup_relation(disp, length, type, commutator, t, pcp);
}

/* read word using pretty format */

void pretty_read_word(FILE *file, int disp, int type, struct pcp_vars *pcp)
{
   register int *y = y_address;

   int ptr = pcp->lused + 1 + disp;
   word w1, w2, w3;
   gen_type g;
   int i, exp;
   int length;

   if (file == stdin)
      display_message(type);

   word_init(&w1);
   word_init(&w2);
   word_init(&w3);
   read_next_word(&w1, file);
   find_char(';', file);
   word2prog_word(&w1, &w2);
   word_factor(&w2, &w3, &exp);

   y[ptr] = length = 0;
   y[ptr + 1] = exp;
   while (word_delget_first(&w3, &g))
      if (g != 0)
         y[ptr + 1 + (++length)] =
             (g <= inv(g)) ? pairnumber[g] : -pairnumber[g];
   word_clear(&w1);
   word_clear(&w2);
   word_clear(&w3);

   if (length != 0)
      y[ptr] = ++length;

   if (file != stdin)
      return;

   printf("The input word is ");
   for (i = 1; i <= length; ++i)
      printf("%d ", y[ptr + i]);
   printf("\n");
}

/* process the input word and set it up as an entry in y */

static void setup_relation(int disp,
                           int length,
                           int type,
                           Logical commutator,
                           int *t,
                           struct pcp_vars *pcp)
{
   register int *y = y_address;

   register int i;
   int u[MAXWORD];
   register int total;
   register int ptr;
   Logical commutator_relation;

   /* currently, only a commutator which is one side of a
      relation is not expanded -- this may be changed later */
   commutator_relation = (commutator && (type == LHS || type == RHS));

   /* is the word trivial? */
   if (t[0] == 0 || length == 1) {
      length = 1;
      ptr = pcp->lused + 1 + disp;
      y[ptr + 1] = 0;
   } else {
      /* set up relation */
      for (i = 1; i < MAXWORD; ++i)
         u[i] = 0;
      u[0] = t[1];

      if (length >= MAXWORD) {
         text(18, 0, 0, 0, 0);
         exit(FAILURE);
      }

      if (commutator_relation || !commutator)
         for (i = 1; i < length - 1; ++i)
            u[i] = t[i + 1];
      else {
         for (i = 2; i < length; ++i)
            expand_commutator(u, t[i]);
      }

      /* check how much space is required to store the word in y */
      total = 2;
      while (u[total] != 0)
         ++total;

      /* the length of the relation is total */
      if (total >= MAXWORD) {
         text(18, 0, 0, 0, 0);
         exit(FAILURE);
      }

      /* is there enough room in array y to store the word? */
      if (is_space_exhausted(total, pcp))
         return;

      ptr = pcp->lused + 1 + disp;

      /* copy expanded word and set up as relation stored in y */
      y[ptr + 1] = t[0];
      length = 0;
      while (u[length] != 0) {
         y[ptr + 2 + length] = u[length];
         ++length;
      }
      ++length;
   }

   /* set up the length */
   if (commutator_relation)
      y[ptr] = -length;
   else
      y[ptr] = length;

   PRINT("The input word is ");
   PRINT("%d ", y[ptr + 1]);
   if (commutator_relation)
      PRINT("[ ");
   for (i = 2; i <= length; ++i)
      PRINT("%d ", y[ptr + i]);
   if (commutator_relation)
      PRINT("]");
   PRINT("\n");
}

/* check whether relation is a commutator */

static int check_for_commutator(char *s)
{
   int not_found;
   register int length = strlen(s);

   while (length > 0 && (not_found = (s[length - 1] != LHS_COMMUTATOR &&
                                      s[length - 1] != RHS_COMMUTATOR)))
      --length;

   return !not_found;
}

/* check for occurrence of END_OF_WORD in word */

static int check_for_symbol(char *s)
{
   int not_found;
   register int length = strlen(s);

   while (length > 0 && (not_found = (s[length - 1] != END_OF_WORD)))
      --length;

   return !not_found;
}

/* convert string s to integer */

static int string_to_integer(char *s, int *integer)
{
   int i, n, sign;

   for (i = 0; isspace(s[i]); i++) /* skip white space */
      ;
   sign = (s[i] == '-') ? -1 : 1;
   if (s[i] == '+' || s[i] == '-') /* skip sign */
      i++;
   for (n = 0; s[i] != '\0'; i++) {
      if (isdigit(s[i])) {
         *integer = 1;
         n = 10 * n + (s[i] - '0');
      }
   }

   return sign * n;
}
