/* amtog.c  version 2.0; B D McKay, Jun 2015. */

#define USAGE "amtog [-n#sgzhq] [-o#] [infile [outfile]]"

#define HELPTEXT \
" Read graphs in matrix format.\n\
\n\
    -n#   Set the initial graph order to # (no default).\n\
          This can be overridden in the input.\n\
    -g    Write the output in graph6 format (default).\n\
    -s    Write the output in sparse6 format.\n\
    -z    Write the output in digraph6 format.\n\
    -h    Write a header (according to -g or -s).\n\
    -w    Don't warn about loops (which are suppressed for -g)\n\
    -q    Suppress auxiliary information.\n\
    -o#   Treat digit # as 1 and other digits as 0.\n\
\n\
   Input consists of a sequence of commands restricted to:\n\
\n\
    n=#   set number of vertices (no default)\n\
          The = is optional.\n\
    m     Matrix to follow\n\
          An 'm' is also assumed if a digit is encountered.\n\
    M     Complement of matrix to follow (as m)\n\
    t     Upper triangle of matrix to follow, row by row\n\
           excluding the diagonal.\n\
    T     Complement of upper trangle to follow (as t)\n\
    s     Upper triangle of matrix to follow, row by row\n\
           excluding the diagonal; lower triangle is complement.\n\
    q     exit (optional)\n"

/*************************************************************************/

#include "gtools.h"  /* which includes nauty.h and stdio.h */
#include <ctype.h>

/**************************************************************************/
/**************************************************************************/

int
main(int argc, char *argv[])
{
    int m,n,outdigit;
    int argnum,i,j,outcode,val;
    int unsym0,unsym1,loop0;
    char *arg,sw,ochar;
    boolean badargs;
    boolean nswitch,sswitch,gswitch,hswitch,qswitch;
    boolean warn,loop,unsymm,compl,triangle,tournament;
    boolean zswitch,oswitch,nowarn;
    char *infilename,*outfilename;
    FILE *infile,*outfile;
    nauty_counter nin;
    char s[10];
#if MAXN
    graph g[MAXN*MAXM];
#else
    DYNALLSTAT(graph,g,g_sz);
#endif

    HELP; PUTVERSION;

    sswitch = gswitch = zswitch = oswitch = FALSE;
    nowarn = qswitch = nswitch = hswitch = FALSE;
    infilename = outfilename = NULL;
    n = -1;

    argnum = 0;
    badargs = FALSE;
    for (j = 1; !badargs && j < argc; ++j)
    {
        arg = argv[j];
        if (arg[0] == '-' && arg[1] != '\0')
        {
            ++arg;
            while (*arg != '\0')
            {
                sw = *arg++;
                     SWBOOLEAN('s',sswitch)
                else SWBOOLEAN('g',gswitch)
                else SWBOOLEAN('z',zswitch)
                else SWBOOLEAN('h',hswitch)
                else SWBOOLEAN('w',nowarn)
                else SWBOOLEAN('q',qswitch)
                else SWINT('n',nswitch,n,">E amtog -n")
                else SWINT('o',oswitch,outdigit,">E amtog -o")
                else badargs = TRUE;
            }
        }
        else
        {
            ++argnum;
            if      (argnum == 1) infilename = arg;
            else if (argnum == 2) outfilename = arg;
            else                  badargs = TRUE;
        }
    }

    if ((sswitch!=0) + (gswitch!=0) + (zswitch!=0) > 1)
        gt_abort(">E amtog: -sgz are incompatible\n");

    if (oswitch && (outdigit < 0 || outdigit > 9))
        gt_abort(">E amtog: only digits are allowed for -o\n");

    if (badargs || argnum > 2)
    {
        fprintf(stderr,">E Usage: %s\n",USAGE);
        GETHELP;
        exit(1);
    }

    if (oswitch) ochar = outdigit + '0';
    else         ochar = '1';

    if (!infilename || infilename[0] == '-')
    {
        infilename = "stdin";
        infile = stdin;
    }
    else if ((infile = fopen(infilename,"r")) == NULL)
        gt_abort_1(">E amtog: Can't open input file %s\n",infilename);

    if (!outfilename || outfilename[0] == '-')
    {
        outfilename = "stdout";
        outfile = stdout;
    }
    else if ((outfile = fopen(outfilename,"w")) == NULL)
        gt_abort_1(">E amtog: Can't open output file %s\n",outfilename);

    if (sswitch)      outcode = SPARSE6;
    else if (zswitch) outcode = DIGRAPH6;
    else              outcode = GRAPH6;

    if (hswitch)
    {
        if (outcode == SPARSE6)       writeline(outfile,SPARSE6_HEADER);
        else if (outcode == DIGRAPH6) writeline(outfile,DIGRAPH6_HEADER);
        else                          writeline(outfile,GRAPH6_HEADER);
    }

#if MAXN
    if (nswitch && n > MAXN)
        gt_abort(">E amtog: value of -n too large\n");
#else
    if (nswitch)
    {
        m = (n + WORDSIZE - 1) / WORDSIZE;
        DYNALLOC2(graph,g,g_sz,n,m,"amtog");
    }
#endif

     /* perform scanning required */

    warn = FALSE;
    nin = 0;
    while (fscanf(infile,"%1s",s) == 1)
    {
        if (s[0] == 'n')
        {
            if (fscanf(infile,"=%d",&n) != 1)
                gt_abort(">E amtog: invalid n=# command\n");
            m = (n + WORDSIZE - 1) / WORDSIZE;
#if MAXN
            if (n < 1 || n > MAXN || m > MAXM)
                gt_abort(">E amtog: n<0 or n,m too big\n");
#else
            DYNALLOC2(graph,g,g_sz,n,m,"amtog");
#endif
        } 
        else if (s[0] == 'm' || s[0] == 'M' || s[0] == 't' ||
                 s[0] == 'T' || s[0] == 's' || s[0] == '0' ||
                 s[0] == '1' || (oswitch && isdigit(s[0])))
        {
            if (n < 0)
            {
                fprintf(stderr,
                    ">E amtog: matrix found before n is defined\n");
            }
            if (isdigit(s[0])) ungetc(s[0],infile);
            m = (n + WORDSIZE - 1) / WORDSIZE;
    
            EMPTYSET(g,m*(size_t)n);

            loop = unsymm = tournament = FALSE;
            triangle = (s[0] == 't') || (s[0] == 'T') || (s[0] == 's');
            tournament = s[0] == 's';
            compl = (s[0] == 'M') || (s[0] == 'T');

            ++nin;
            for (i = 0; i < n; ++i)
            for (j = (triangle ? i+1 : 0); j < n; ++j)
            {
                if (fscanf(infile,"%1s",s) != 1)
                    gt_abort(">E amtog: incomplete matrix\n");
 
                if (s[0] == '0' || s[0] == '1'
                      || (oswitch && isdigit(s[0])))
                {
                    val = ((i != j) & compl) ^ (s[0] == ochar);
                    if (val == 1)
                    {
                        if (tournament)
                            ADDELEMENT(GRAPHROW(g,i,m),j);
                        else if (triangle)
                        {
                            ADDELEMENT(GRAPHROW(g,i,m),j);
                            ADDELEMENT(GRAPHROW(g,j,m),i);
                        }
                        else
                        {
                            if (j < i && !ISELEMENT(GRAPHROW(g,j,m),i))
                            {
                                unsymm = TRUE;
                                unsym0 = i; unsym1 = j;
                            }
                            ADDELEMENT(GRAPHROW(g,i,m),j);
                        }
                        if (i == j)
                        {
                            loop = TRUE;
                            loop0 = i;
                        }
                    }
                    else if (tournament)
                        ADDELEMENT(GRAPHROW(g,j,m),i);
                    else if (j < i && ISELEMENT(GRAPHROW(g,j,m),i))
                    {
                        unsymm = TRUE;
                        unsym0 = i; unsym1 = j;
                    }
                }
                else
                {
                    gt_abort_1(
                      ">E amtog: illegal character in matrix: \"%c\"\n",
                      s[0]);
                }
            }

            if ((tournament || unsymm) && outcode != DIGRAPH6)
                fprintf(stderr,">W amtog: warning, graph "
                    COUNTER_FMT " is unsymmetric (%d,%d)\n",nin,unsym0,unsym1);
    
            if (outcode == DIGRAPH6)     writed6(outfile,g,m,n);
            else if (outcode == SPARSE6) writes6(outfile,g,m,n);
            else                         writeg6(outfile,g,m,n);
            if (loop && outcode == GRAPH6) ++warn;
        }
        else if (s[0] == 'q')
        {
            exit(0);
        }
        else
            gt_abort_1(">E amtog: invalid command \"%c\"\n",s[0]);
    }

    if (warn && !nowarn) fprintf(stderr,">Z amtog: loops were lost (%d)\n",loop0);

    if (!qswitch)
        fprintf(stderr,">Z  " COUNTER_FMT " graphs converted from %s to %s.\n",
                       nin,infilename,outfilename);

    exit(0);
}
