/****************************************************************************
**
*A  setup_reps.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 "pcp_vars.h"
#include "pga_vars.h"
#include "constants.h"
#include "pq_functions.h"
#include "global.h"
#include "standard.h"

/* factor out the allowable subgroups whose labels are listed
   in the array reps; assemble the necessary automorphism
   information and save the descriptions to file */

void setup_reps (int *reps, int nmr_of_reps, int *orbit_length,
                 int **perms, int *a, int *b, char *c, int ***auts, 
                 FILE *descendant_file, FILE *covers_file,
                 struct pga_vars *pga, struct pcp_vars *pcp)
{ 

   char *d;                     /* used in stabiliser computation */
   FILE * tmp_file;
   struct pga_vars original;    /* copy of pga structure */
   register int i;
   Logical soluble_group;       /* indicates that stabilisers may 
				   be computed using soluble machinery */

#ifdef HAVE_GMP
   MP_INT original_aut;         /* copy of automorphism order */
#endif 

   soluble_group = (pga->soluble || pga->Degree == 1 || pga->nmr_of_perms == 0);

   tmp_file = TemporaryFile ();
   save_pcp (tmp_file, pcp);

   if (soluble_group) {
      d = find_permutation (b, c, pga);
      if (pga->print_stabiliser_array) {
	 printf ("The array D is \n"); 
	 print_chars (d, 1, pga->nmr_subgroups + 1);
      }
   }

#ifdef HAVE_GMP
   /* first record current automorphism group order */
   mpz_init_set (&original_aut, &pga->aut_order);
   mpz_clear (&pga->aut_order);
#endif 

   /* keep copy of pga */
   original = *pga;

#ifdef HAVE_GMP
   /* now reset automorphism order in pga */
   mpz_init_set (&pga->aut_order, &original_aut);
#endif 

   for (i = 1; i <= nmr_of_reps; ++i) {

      pga->fixed = pga->s;

      if (pga->final_stage) {
	 ++original.nmr_of_descendants;
	 update_name (pcp->ident, original.nmr_of_descendants, pga->s);
      }

      process_rep (perms, a, b, c, d, auts, reps[i], orbit_length[i], 
		   tmp_file, descendant_file, covers_file, pga, pcp);

      if (pga->final_stage && pga->capable) { 
	 ++original.nmr_of_capables;
	 if (pga->trace) 
	    printf ("Capable group #%d\n", original.nmr_of_capables);
      }

      /* revert to original pga structure */
      if (!StandardPresentation) {
#ifdef HAVE_GMP
	 mpz_clear (&pga->aut_order);
#endif 

         *pga = original;                                                       

#ifdef HAVE_GMP
	 mpz_init_set (&pga->aut_order, &original_aut);
#endif 
      }
   }
   
   if (soluble_group)
      free (++d);

#ifdef HAVE_GMP
   mpz_clear (&original_aut);
#endif 

   CloseFile (tmp_file);
}

/* process orbit representative; if reduced p-covering group, 
   save description to covers_file, otherwise to descendant file */

void process_rep (int **perms, int *a, int *b, char *c, char *d,
                  int ***auts, int rep, int orbit_length,
                  FILE * tmp_file, FILE * descendant_file, FILE * covers_file,
                  struct pga_vars *pga, struct pcp_vars *pcp)
{
   int index;
   int *subset;
   int ***central;
   int ***stabiliser;
   int **S;
   int *seq;
   FILE * file;
   FILE * GAP_library; 
   int lused, rank_of_cover;

   /* construct the presentation for the descendant and 
      assemble the necessary automorphism information */
   S = label_to_subgroup (&index, &subset, rep, pga);
   if (pga->print_subgroup) {
      printf ("The standard matrix for the allowable subgroup is:\n");
      print_matrix (S, pga->s, pga->q);
   }
   factorise_subgroup (S, index, subset, pga, pcp);
   free_matrix (S, pga->s, 0);

   free_vector (subset, 0);

   if ((pga->print_group && pga->final_stage) || pga->print_reduced_cover) {
      print_presentation (FALSE, pcp);
      print_structure (1, pcp->lastg, pcp);
      print_pcp_relations (pcp);
      printf ("\n");
   }

   if (pga->final_stage) {
      central = immediate_descendant (descendant_file, pga, pcp);

      /* should we write a compact description to file? */
      if ((pga->capable || pga->terminal) && (Compact_Description == TRUE  
&& (Compact_Order <= pcp->lastg || Compact_Order == 0))) {
	 seq = compact_description (TRUE, pcp);
	 free_vector (seq, 1);
      }

      /* should we write a description of group to GAP file? */
      if (pga->capable || pga->terminal) {
	 if (Group_library == GAP_LIBRARY) {
	    if (Group_library_file != NULL) 
	       GAP_library = OpenFile (Group_library_file, "a+");
	    else 
	       GAP_library = OpenFile ("GAP_library", "a+");
	    write_GAP_library (GAP_library, pcp);
	    CloseFile (GAP_library);
	 }
      }

      /* if the group is not capable and we do not want to 
	 process terminal groups, we are finished */
      if (!pga->capable && !pga->terminal) {
	 /* first restore the original p-covering group */
	 RESET(tmp_file);
	 restore_pcp (tmp_file, pcp);
	 return;
      }
   }
   else { 
      save_pcp (covers_file, pcp);
      /* if characteristic subgroup in nucleus, revise the nuclear rank */ 
      if (pga->s < pcp->newgen)
	 pcp->newgen = pga->nuclear_rank + pga->s - pga->q;
      set_values (pga, pcp);
      pga->nmr_centrals = 0;
   }

#ifdef HAVE_GMP
   update_autgp_order (orbit_length, pga, pcp);
#endif 

   /* restore the original p-covering group before computing stabiliser */
   RESET(tmp_file);
   restore_pcp (tmp_file, pcp);

   /* note following information before computing stabiliser */
   rank_of_cover = pcp->lastg;
   lused = pcp->lused;

   stabiliser = stabiliser_of_rep (perms, rep, orbit_length,
				   a, b, c, d, auts, pga, pcp);

#ifdef HAVE_GMP
   if (pga->final_stage) 
      report_autgp_order (pga, pcp);
#endif 

   if (pga->final_stage && (pga->capable || pga->terminal)) {
      if (Group_library == GAP_LIBRARY) {
	 GAP_library = OpenFile ("GAP_library", "a+");
	 GAP_auts (GAP_library, central, stabiliser, pga, pcp);
	 CloseFile (GAP_library);
      }
   }

   if (pga->final_stage) {
      if (StandardPresentation) pga->fixed = 0; else initialise_pga (pga, pcp);
      pga->step_size = 0; 
   }

   /* save structure + automorphism information */
   file = (pga->final_stage ? descendant_file : covers_file); 
      
   save_pga (file, central, stabiliser, pga, pcp);

#if defined (GROUP) 
#if defined (STANDARD_PCP)
   if (StandardPresentation)
      print_aut_description (central, stabiliser, pga, pcp);
#endif
#endif

   if (pga->nmr_centrals != 0) 
      free_array (central, pga->nmr_centrals, pga->ndgen, 1);
   if (pga->nmr_stabilisers != 0) {
      free_array (stabiliser, pga->nmr_stabilisers, pga->ndgen, 1);
   }

   pcp->lastg = rank_of_cover;
   pcp->lused = lused;
}
