/****************************************************************************
**
*A  pretty_filter.c             ANUPQ source                   Eamonn O'Brien
**
*A  @(#)$Id$
**
*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 "pq_functions.h"
#include "constants.h"
#include "pcp_vars.h"
#include "pretty_filterfns.h"

/* SIGNIFICANT is the number of significant characters in the 
   keyword strings; if you change this, you'll have to change 
   the calls to strcmp so that the strings being compared with 
   label continue to have length SIGNIFICANT */

#define SIGNIFICANT 3

FILE *rfile;
FILE *wfile; 

extern int num_gens;
extern gen_type *inv_of;
extern word *user_gen_name;
extern int gen_array_size;
extern int *pairnumber;
extern int paired_gens;
char gpname[MAXIDENT];
char filename[MAXIDENT];

/* process "pretty" presentation input from file using key words; 
   this is a modified version of code written by Sarah Rees */

int pretty_filter (FILE *file, int *max_class, int *output, struct pcp_vars *pcp)
{
   register int *y = y_address;

   int prime = 0;
   int exponent = 0;
   int nrels = 0;
   int end = MAXIDENT - 1;

   int count, posn;
   int ptr, relp, length;
   int i = 1;
   char c;
   word w;
   word_link *root = word_link_create ();
   word_link *wlp = 0;
   word_link *next = 0;
   gen_type g;
   char label[SIGNIFICANT + 1];
   Logical metabelian_flag = FALSE;

   rfile = file;

   wfile = stdout;
   *max_class = 10;
   *output = 1;
   inv_of = 0;
   paired_gens = 0;

   strcpy (gpname, "G");
   wfile = stdout;
   
   pcp->cover = 0;

   while (read_next_string (label, SIGNIFICANT, rfile)) {
      if (strcmp (label, "nam")==0) {
	 read_next_string (gpname, end, rfile);
	 /* knock off the blank spaces at the end  */
	 i = end - 1; while (i >= 0 && gpname[i] == ' ') i-- ; 
	 gpname[i+1] = '\0'; 
      }
      else if (strcmp (label, "pri") == 0) {
	 read_next_int (&prime, rfile);
      }
      else if (strcmp (label, "cla") == 0) {
	 read_next_int (max_class, rfile);
      }
      else if (strcmp (label, "out") == 0) {
	 read_next_int (output, rfile);
      }
      else if (strcmp (label, "met") == 0) {
	 metabelian_flag = TRUE;
      }
      else if (strcmp (label, "exp") == 0) {
	 read_next_int (&exponent, rfile);
      }
      else if (strcmp (label, "gen") == 0) {
	 read_gen_name_array (rfile);
	 default_inverse_array ();
	 pairnumber = anu_valloc (int, num_gens + 1);
	 for (i = 1; i <= num_gens; i++){ 
	    if (i <= inv (i)){
	       paired_gens++;
	       pairnumber[i] = pairnumber[inv (i)] = paired_gens;
	    }
	 }
      }
      else if (strcmp (label, "rel") == 0) {
	 /* read in and store the relations/relators; every 
	    relator/relation is actually stored as a relation 
	    (i.e. two consecutive words in the list) */
	 find_char ('{', rfile);
	 pc_word_init (&w);
	 wlp = root;
	 while (read_next_word (&w, rfile)){
	    nrels++;
	    word_link_init (wlp);
	    word2prog_word (&w, wlp->wp);
	    wlp = wlp->next;
	    pc_word_reset (&w);
	    while ((c = read_char (rfile)) == ' ');
	    word_link_init (wlp);
	    if (c == '='){
	       count = 1;
	       posn = ftell(rfile); /* mark posn */
	       /* pick up the word at the end of the chain of '=''s as 
		  the right hand side of the equation */
	       do {
		  read_next_word (&w, rfile);
		  while ((c = read_char (rfile)) == ' ');
		  if (c == '='){ pc_word_reset (&w); count++;}
	       } while (c == '=');
	       ungetc(c,rfile);
	       word2prog_word (&w, wlp->wp);
	       pc_word_reset (&w);
	       if (count>1){
		  if (!isatty (0)) fseek (rfile,posn,0);
		  /* go back to the marker if there was more than one '=' */
		  else { 
		     /* we can't use fseek if we're inputting from stdin */
		     printf ("You may not input relations of the type u = v = w from terminal\n");
		     exit (FAILURE);
		  }
	       }
	    }
	    else ungetc (c, rfile);
	    wlp = wlp->next;
	 }
	 find_char ('}', rfile);
	 word_clear (&w);
      }
   }

   /* a single ; or one preceded by an unrecognised keyword 
      marks the end of the data */
   find_char (';', rfile);      /* pick up the terminating ';' */

   pcp->p = prime;
   pcp->ndgen = paired_gens;
   pcp->ndrel = nrels;
   pcp->extra_relations = exponent;
   strcpy (pcp->ident, gpname);
   pcp->diagn = (*output == MAX_PRINT);
   pcp->fullop = (*output >= INTERMEDIATE_PRINT);

   check_input (*output, max_class, pcp);
   if (!pcp->valid)
      return INPUT_ERROR;

   initialise_pcp (*output, pcp);

   /* set the metabelian flag appropriatedly */
   pcp->metabelian = metabelian_flag;

   setup (pcp);

   /* next set up each relation in the list, as left hand side followed
      by right hand side, after expressing each as a power if possible */
   wlp = root; ptr = pcp->lused;
   relp = pcp->relp;

   while (wlp->wp) {
      word * wp = wlp->wp;
      gen_type * gp = wp->g + wp->first;
      gen_type * ggp = wp->g + wp->last;
      ptr = pcp->lused + 1;

      length = 1;
      while (gp <= ggp) {
	 g = *gp;
	 y[ptr + (++length)] = 
	    (g <= inv (g)) ? pairnumber[g] : -pairnumber[g];
	 gp++;
      }
      
      /* set up exponent */
      if (wp->n) y[ptr + 1] = wp->n;
      else if (length==1) y[ptr + 1] = 0; 
      /* this deals with the trivial word */
      else y[ptr + 1] = 1;

      /* set up relation length */
      if (wp->type=='c') y[ptr] = -length;
      else y[ptr] = length;

      ++relp;
      y[relp] = ptr;
      pcp->lused += (length + 1);
      next = wlp->next;
      word_link_clear (wlp);
      wlp = next;
   }

   pcp->gspace = pcp->lused + 1;
   free ((char *) wlp);

   if (user_gen_name) {
      for (i = 0; i < gen_array_size; ++i) 
	 word_clear (user_gen_name + i);
      free ((char *) user_gen_name);
      user_gen_name = 0;
   }
   if (inv_of) {
      free ((char *) inv_of); 
      inv_of = 0;
   }

   return SUCCESS;
}

/* check the input supplied to the p-quotient calculation */

void check_input (int output, int *max_class, struct pcp_vars *pcp)
{
   pcp->valid = TRUE;

   if (output < 0 || output > MAX_PRINT) {
      printf ("Print level must lie between %d and %d\n", MIN_PRINT, MAX_PRINT);
      pcp->valid = FALSE;
   }

   if (pcp->ndgen > MAXGENS) {
      printf ("The maximum number of defining generators is %d\n", MAXGENS);
      pcp->valid = FALSE;
   }

   if (pcp->ndgen < 1) {
      printf ("The minimum number of defining generators is 1\n");
      pcp->valid = FALSE;
   }

   if (pcp->p != 2 && MOD(pcp->p, 2) == 0) {
      printf ("%d is not a prime\n", pcp->p);
      pcp->valid = FALSE;
   }

   if (*max_class == 0) {
      *max_class = DEFAULT_CLASS;
      text (15, DEFAULT_CLASS, 0, 0, 0);
   }
   else if (*max_class > MAXCLASS) {
      *max_class = MAXCLASS;
      text (15, MAXCLASS, 0, 0, 0);
   }
   else if (*max_class < 0) {
      printf ("Class must be a non-negative integer\n");
      pcp->valid = FALSE;
   }
}

/* read the generator list */

void pretty_read_generators (struct pcp_vars *pcp)
{
   Logical reading = TRUE;
   int i;

   rfile = stdin;
   wfile = stdout;

   while (reading) {

      printf ("Input generating set (in { }): ");

      paired_gens = 0;
      inv_of = 0;                  /* bug fix */
      read_gen_name_array (rfile);
      default_inverse_array ();
      pairnumber = anu_valloc (int, num_gens + 1);
      for (i = 1; i <= num_gens; i++) { 
	 if (i <= inv (i)){
	    paired_gens++;
	    pairnumber[i] = pairnumber[inv (i)] = paired_gens;
	 }
      }
      pcp->ndgen = paired_gens;


      reading = (pcp->ndgen > MAXGENS);
      if (reading)
	 printf ("The maximum number of defining generators is %d\n", MAXGENS);

      if (!isatty (0)) printf ("\n");
   }
}

/* read the list of relations (and the exponent) using pretty format */

void pretty_read_relations (int output, int *max_class, struct pcp_vars *pcp)
{
   register int *y = y_address;

   int ptr, relp, length;
   int i = 1;
   char c;
   int nrels = 0;
   int count, posn;
   word w;
   word_link *root = word_link_create ();
   word_link *wlp = 0;
   word_link *next = 0;
   gen_type g;

   rfile = stdin;
   wfile = stdout;

   printf ("Input defining set of relations (in { }): ");

   /* read in and store the relations/relators; each relator/relation 
      is stored as a relation (two consecutive words in the list) */

   find_char ('{', rfile);
   pc_word_init (&w);
   wlp = root;
   while (read_next_word (&w, rfile)) {
      nrels++;
      word_link_init (wlp);
      word2prog_word (&w, wlp->wp);
      wlp = wlp->next;
      pc_word_reset (&w);
      while ((c = read_char (rfile)) == ' ');
      word_link_init (wlp);
      if (c == '=') {
	 count = 1;
	 posn = ftell(rfile);   /* mark position */
	 /* pick up the word at the end of the chain of '=''s as 
	    the right hand side of the equation */
	 do {
	    read_next_word (&w, rfile);
	    while ((c = read_char (rfile)) == ' ');
	    if (c == '=') { pc_word_reset (&w); count++;}
	 } while (c == '=');
	 ungetc (c,rfile);
	 word2prog_word (&w, wlp->wp);
	 pc_word_reset (&w);
	 if (count > 1){
	    if (!isatty (0)) fseek (rfile,posn,0);
	    /* go back to the marker if there was more than one '=' */
	    else { 
	       /* we can't use fseek if we're inputting from stdin */
	       printf ("You may not input relations of the type u = v = w from terminal\n");
	       exit (FAILURE);
	    }
	 }
      }
      else ungetc (c, rfile);
      wlp = wlp->next;
   }
   find_char ('}', rfile);

   if (!isatty (0)) printf ("\n");

   pcp->ndrel = nrels;

   check_input (output, max_class, pcp);
   if (!pcp->valid)
      return;

#if defined (GROUP) 
   read_value (TRUE, "Input exponent law (0 if none): ",
	       &pcp->extra_relations, 0);
#endif

   initialise_pcp (output, pcp);
   setup (pcp);

   /* next set up each relation in the list, as left hand side followed
      by right hand side, after expressing each as a power if possible */
   wlp = root; ptr = pcp->lused;
   relp = pcp->relp;

   while (wlp->wp) {
      word * wp = wlp->wp;
      gen_type * gp = wp->g + wp->first;
      gen_type * ggp = wp->g + wp->last;
      ptr = pcp->lused + 1;

      length = 1;
      while (gp <= ggp) {
	 g = *gp;
	 y[ptr + (++length)] = (g <= inv (g)) ? pairnumber[g] : -pairnumber[g];
	 gp++;
      }
      
      /* set up exponent */
      if (wp->n) y[ptr + 1] = wp->n;
      else if (length == 1) y[ptr + 1] = 0; 
      /* this deals with the trivial word */
      else y[ptr + 1] = 1;

      /* set up relation length */
      if (wp->type == 'c') y[ptr] = -length;
      else y[ptr] = length;

      ++relp;
      y[relp] = ptr;
      pcp->lused += (length + 1);
      next = wlp->next;
      word_link_clear (wlp);
      wlp = next;
   }

   pcp->gspace = pcp->lused + 1;
   free ((char *) wlp);

   if (user_gen_name) {
      for (i = 0; i < gen_array_size; ++i) 
	 word_clear (user_gen_name + i);
      free ((char *) user_gen_name);
      user_gen_name = 0;
   }
   if (inv_of) {
      free ((char *) inv_of); 
      inv_of = 0;
   }
}
