#############################################################################
##
#W  types.gi             GAP 4 package `atlasrep'               Thomas Breuer
##
#H  @(#)$Id: types.gi,v 1.21 2003/11/03 09:43:03 gap Exp $
##
#Y  Copyright (C)  2001,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
##
##  This file contains implementations of the functions for administrating
##  the data types used in the {\ATLAS} of Group Representations.
##
Revision.( "atlasrep/gap/types_gi" ) :=
    "@(#)$Id: types.gi,v 1.21 2003/11/03 09:43:03 gap Exp $";


#############################################################################
##
#F  TOCEntryStringDefault( <typename>, <entry> )
##
BindGlobal( "TOCEntryStringDefault", function( typename, entry )
    return Concatenation( [
    "AGRTOC(\"", typename, "\",\"", entry[ Length( entry ) ], "\");\n" ] );
    end );


#############################################################################
##
#F  AGRTestWordsDefault( <tocid>, <name>, <file>, <outputs> )
##
##  For the program stored in the file whose name is returned by
##  `FilenameAtlas' (see~"FilenameAtlas") when this is called with the first
##  three arguments,
##  it is checked that it is internally consistent and that it can be
##  evaluated at the right number of arguments.
##  If the argument <outputs> is `true' then it is additionally checked
##  that the result record has a component `outputs', a list whose length
##  equals the number of outputs of the program.
##
BindGlobal( "AGRTestWordsDefault", function( tocid, name, file, outputs )
    local filename, prog, prg, gens;

    # Read the program.
    if tocid = "local" then
      tocid:= "dataword";
    fi;
    filename:= FilenameAtlas( tocid, name, file );
    if filename = fail then
      Print( "#E  no filename `", file, "' for `", name, "'\n" );
      return false;
    fi;
    prog:= ScanStraightLineProgram( filename );

    # Check consistency.
    if prog = fail or not IsInternallyConsistent( prog.program ) then
      Print( "#E  program `", file, "' not internally consistent\n" );
      return false;
    fi;
    prg:= prog.program;

    # Create the list of (trivial) generators.
    gens:= ListWithIdenticalEntries( NrInputsOfStraightLineProgram( prg ),
                                     () );

    # Run the program.
    gens:= ResultOfStraightLineProgram( prg, gens );

    # If the script computes class representatives then
    # check whether there is an `outputs' component of the right length.
    if outputs = true then
      if not IsBound( prog.outputs ) then
        Print( "#E  program `", file, "' without component `outputs'\n" );
        return false;
      elif Length( prog.outputs ) <> Length( gens ) then
        Print( "#E  program `", file, "' with wrong number of `outputs'\n" );
        return false;
      fi;
    fi;

    return true;
end );


#############################################################################
##
#F  AGRTestFileHeadersDefault( <tocid>, <groupname>, <entry>, <dim>,
#F                             <special> )
##
BindGlobal( "AGRTestFileHeadersDefault",
    function( tocid, groupname, entry, dim, special )
    local filename, name, mats;

    # Try to read the file.
    if tocid = "local" then
      tocid:= "datagens";
    fi;
    filename:= entry[ Length( entry ) ];
    name:= FilenameAtlas( tocid, groupname, filename );
    if name = fail then
      Print( "#E  filename `", filename, "' not found\n" );
      return false;
    fi;
    InfoRead1( "#I  reading `",name,"' started\n" );
    mats:= ReadAsFunction( name );
    InfoRead1( "#I  reading `",name,"' done\n" );
    if mats = fail then
      Print( "#E  problem reading `", name, "' as function\n" );
      return false;
    else
      mats:= mats().generators;
    fi;

    # Check that the return value is a list of matrices.
    if not ( IsList( mats ) and ForAll( mats, IsMatrix ) ) then
      Print( "#E  file `", filename,
             "' does not contain a list of matrices\n" );
      return false;
    fi;

    # Check the dimension.
    dim:= [ dim, dim ];
    if ForAny( mats, mat -> DimensionsMat( mat ) <> dim ) then
      Print( "#E  matrices in `",filename,"' have wrong dimensions\n" );
      return false;
    fi;

    # Check the entries.
    special:= special( entry, mats, filename );
    if IsString( special ) then
      Print( "#E  ", special, "\n" );
      return false;
    fi;

    return true;
end );


#############################################################################
##
#F  AGRTestFilesMTX( <tocid>, <groupname>, <entry> )
##
BindGlobal( "AGRTestFilesMTX", function( tocid, groupname, entry )
    local result, name, filename;

    if tocid = "local" then
      tocid:= "datagens";
    fi;
    result:= true;
    for name in entry[ Length( entry ) ] do

      # Read the file.
      filename:= FilenameAtlas( tocid, groupname, name );
      if filename = fail then
        Print( "#E  file `",name,"' not available\n" );
        result:= false;
      fi;
      filename:= ScanMeatAxeFile( filename );
      if filename = fail then
        Print( "#E  file `",name,"' corrupted\n" );
        result:= false;
      fi;

    od;
    return result;
end );


#############################################################################
##
#F  AGRCheckOneCondition( <func>, <condlist> )
#F  AGRCheckOneCondition( <func>, <detect>, <condlist> )
##
BindGlobal( "AGRCheckOneCondition", function( arg )
    local func, detect, condlist, pos, val;

    if Length( arg ) = 2 then
      func:= arg[1];
      condlist:= arg[2];
    else
      func:= arg[1];
      detect:= arg[2];
      condlist:= arg[3];
    fi;
    pos:= Position( condlist, func );
    if   pos = fail then
      return true;
    elif Length( arg ) = 2 then
      Unbind( condlist[ pos ] );
      return true;
    elif pos = Length( condlist ) then
      return true;
    fi;
    val:= condlist[ pos+1 ];
    if    ( not IsList( val ) and detect( val ) )
       or ( IsList( val ) and ForAny( val, detect ) ) then
      Unbind( condlist[ pos ] );
      Unbind( condlist[ pos+1 ] );
      return true;
    fi;
    return true;
    end );


#############################################################################
##
#F  AGRDeclareDataType( <kind>, <name>, <record> )
##
##  Check that the necessary components are bound,
##  and add default values if necessary.
##
InstallGlobalFunction( AGRDeclareDataType, function( kind, name, record )
    local types, nam;

    # Check that the type does not yet exist.
    types:= AtlasOfGroupRepresentationsInfo.TableOfContents.types;
    if ForAny( types.( kind ), x -> x[1] = name ) then
      Error( "data type <name> exists already" );
    fi;
    record:= ShallowCopy( record );

    # Check compulsory components.
    for nam in [ "FilenameFormat", "AddFileInfo" ] do
      if not IsBound( record.( nam ) ) then
        Error( "the component `", nam, "' must be bound in <record>" );
      fi;
    od;

    # Add default components.
    if not IsBound( record.DisplayOverviewInfo ) then
      record.DisplayOverviewInfo := [ "", "r",
          function( tocs, groupname ) return [ "", false ]; end ];
    fi;
    if not IsBound( record.TOCEntryString ) then
      record.TOCEntryString := TOCEntryStringDefault;
    fi;
    if not IsBound( record.PostprocessFileInfo ) then
      record.PostprocessFileInfo := Ignore;
    fi;
    if   kind = "rep" then
      if not IsBound( record.AccessGroupCondition ) then
        record.AccessGroupCondition := ReturnFalse;
      fi;
      for nam in [ "DisplayGroup" ] do
        if not IsBound( record.( nam ) ) then
          Error( "the component `", nam, "' must be bound in <record>" );
        fi;
      od;
      if not IsBound( record.TestFileHeaders ) then
        record.TestFileHeaders := ReturnTrue;
      fi;
      if not IsBound( record.TestFiles ) then
        record.TestFiles := ReturnTrue;
      fi;
    elif kind = "slp" then
      if not IsBound( record.DisplaySLP ) then
        record.DisplaySLP := function( tocs, name, std, stdavail )
            return []; end;
      fi;
      if not IsBound( record.AccessSLP ) then
        record.AccessSLP := function( record, std, conditions )
          return fail;
        end;
      fi;
      if not IsBound( record.TestWords ) then
        record.TestWords := function( tocid, name, file )
          return AGRTestWordsDefault( tocid, name, file, false );
        end;
      fi;
    else
      Error( "<kind> must be one of \"rep\", \"slp\"" );
    fi;

    # Add the pair.
    Add( types.( kind ), [ name, record ] );

    # Clear the cache.
    types.cache:= [];
end );


#############################################################################
##
#F  AGRDataTypes( <kind1>[, <kind2>] )
##
InstallGlobalFunction( AGRDataTypes, function( arg )
    local types, result, kind;

    types:= AtlasOfGroupRepresentationsInfo.TableOfContents.types;
    result:= First( types.cache, x -> x[1] = arg );

    if result = fail then
      result:= [];
      for kind in arg do
        if IsBound( types.( kind ) ) then
          Append( result, types.( kind ) );
        fi;
      od;
      result:= [ arg, result ];
      Add( types.cache, result );
    fi;

    return result[2];
end );


#############################################################################
##
#E

