/*
 * ImportTemplate.c - Patran Neutral File Import
 * reads packets 1 (nodes), 2 (elements) and 21 (named groups)
 * and optionally packet 6 (loads), and sends data to TfC
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "cfxImport.h"
#include "getargs.h"

#ifdef _WIN32
#  define STAT _stati64
#else
#  define STAT stat
#endif

static char options[] = "vlF:";

static char *usgmsg[] = {
    "usage  : ImportTemplate.c [options] Patran_file",
    "options:",
    "   -v      = verbose output",
    "   -l      = process packet 6 - distributed loads",
    NULL
};

/*---------- print_error -------------------------------------------
 * print error message and line number
 *------------------------------------------------------------------*/

static int lineno = 0;

static void print_error (
#ifdef PROTOTYPE
    char *errmsg)
#else
    errmsg)
char *errmsg;
#endif
{
    fprintf (stderr, "%s on line %d\n", errmsg, lineno);
}

/*---------- add_face -----------------------------------------------
 * add an element face to the region list
 *-------------------------------------------------------------------*/

static void add_face (
#ifdef PROTOTYPE
    int elemid, char *data)
#else
    elemid, data)
int elemid;
char *data;
#endif
{
    int n, nnodes, nodes[8];
    ID_t nodeid[8];
    char errmsg[81];

    /* check for node flags set */

    for (nnodes = 0, n = 0; n < 8; n++) {
        if ('1' == data[n])
            nodes[nnodes++] = n;
    }

    /* if node flags set, use the node values */

    if (nnodes) {
        ID_t elemnodes[8];
        int elemtype = cfxImportGetElement (elemid, elemnodes);
        if (!elemtype) {
            sprintf (errmsg,
                "element %d not found for packet 6\n", elemid);
            cfxImportFatal (errmsg);
        }
        for (n = 0; n < nnodes; n++) {
            if (nodes[n] >= elemtype) {
                sprintf (errmsg,
                    "invalid node flags for element %d\n", elemid);
                cfxImportFatal (errmsg);
            }
            nodeid[n] = elemnodes[nodes[n]];
        }
    }

    /* else get nodes from face number */

    else {
        int faceid = atoi (&data[8]);
        nnodes = cfxImportGetFace (elemid, faceid, nodeid);
        if (nnodes < 0) {
            sprintf (errmsg,
                "element %d not found for packet 6\n", elemid);
            cfxImportFatal (errmsg);
        }
        if (0 == nnodes) {
            sprintf (errmsg,
                "invalid face number for element %d\n", elemid);
            cfxImportFatal (errmsg);
        }
    }

    cfxImportAddReg (nnodes, nodeid);
}

/*========== main ===================================================*/

#define getline()   \
    {if (NULL == fgets (buffer, sizeof(buffer), fp)) \
        cfxImportFatal ("premature EOF"); \
    lineno++;}

void main (argc, argv)
int argc;
char *argv[];
{
    int n, packet, nlines;
    int nnodes;
    int  elemid;
    ID_t nodeid[8];
    int lastid = -1, loadid;
    int verbose = 0, do_loads = 0;
    double xyz[3];
    char *p, buffer[256];
    char *testfile = NULL;
    FILE *fp;
    struct STAT st;

    if (argc < 2)
        usage (usgmsg, NULL);

    while ((n = getargs (argc, argv, options)) > 0) {
        switch (n) {
            case 'v':
                verbose = 7;
                break;
            case 'l':
                do_loads = 1;
                break;
            case 'F':
                testfile = argarg;
                break;
        }
    }

    if (argind >= argc)
        usage (usgmsg, "filename not specified\n");
    if (STAT (argv[argind], &st)) {
        fprintf (stderr, "can't stat <%s>\n", argv[argind]);
        exit (1);
    }
    if (S_IFREG != (st.st_mode & S_IFMT)) {
        fprintf (stderr, "<%s> is not a regular file\n", argv[argind]);
        exit (1);
    }

    if (NULL == testfile)
        cfxImportInit ();
    else {
        if (verbose)
            printf ("writing output to <%s>\n", testfile);
        cfxImportTest (testfile);
    }

    if (NULL == (fp = fopen (argv[argind], "r"))) {
        sprintf (buffer, "can't open <%s> for reading", argv[argind]);
        cfxImportFatal (buffer);
    }
    if (verbose) {
        printf ("reading Patran Neutral file from <%s>\n", argv[argind]);
        fflush (stdout);
    }
    cfxImportError (print_error);

    getline ();

    /* header - packet 25 */

    if ((packet = atoi (buffer)) == 25) {
        getline ();
        if (verbose)
            fputs (buffer, stdout);
        getline ();
        packet = atoi (buffer);
    }

    /* summary - packet 26 */

    if (packet == 26) {
        getline ();
        getline ();
        packet = atoi (buffer);
    }

    /* get remaining packets */

    while (packet != 99) {

        /* node */

        if (packet == 1) {
            if (0 != (verbose & 4)) {
                printf ("reading packet 01 (nodes)...\n");
                fflush (stdout);
                verbose &= 3;
            }
            *nodeid = atoi (&buffer[2]);
            getline ();
            p = buffer + 48;
            for (n = 2; n >= 0; n--) {
                *p = 0;
                p -= 16;
                xyz[n] = atof (p);
            }
            getline ();
            cfxImportNode (*nodeid, xyz[0], xyz[1], xyz[2]);
        }

        /* element */

        else if (packet == 2) {
            if (0 != (verbose & 2)) {
                printf ("reading packet 02 (elements)...\n");
                fflush (stdout);
                verbose &= 1;
            }
            elemid = atoi (&buffer[2]);
            n = atoi (&buffer[10]);
            nlines = atoi (&buffer[18]);
            if (n == 5 || n == 7 || n == 8) {
                cfxImpElemType_t typ;

                getline ();
                nnodes = n == 8 ? n : n-1;

                if (nnodes == 4) {
                  typ = cfxELEM_TET;
                } else if (nnodes == 5) {
                  typ = cfxELEM_PYR;
                } else if (nnodes == 6) {
                  typ = cfxELEM_WDG;
                } else if (nnodes == 8) {
                  typ = cfxELEM_HEX;
                } else {
                  cfxImportFatal("invalid number of nodes for element.");
		}

                lineno++;
                for (n = 0; n < nnodes; n++) {
		    int tmp;
                    if (1 != fscanf (fp, "%d", &tmp) || tmp < 1) {
                        cfxImportFatal ("missing or invalid node ID");
		    } else {
		      nodeid[n] = (ID_t)tmp;
		    }
                }
                while (getc (fp) != '\n')
                    ;
                nlines -= 2;
                cfxImportElement ((ID_t)elemid, typ, nodeid);
            }
            while (nlines-- > 0)
                getline ();
        }

        /* distributed loads */

        else if (packet == 6 && do_loads) {
            elemid = atoi (&buffer[2]);
            loadid = atoi (&buffer[10]);
            nlines = atoi (&buffer[18]);

            if (loadid != lastid) {
                sprintf (buffer, "PatranLoad%d", loadid);
                if (verbose) {
                    printf ("reading packet 06 (loads) as region <%s>...\n",
                        buffer);
                    fflush (stdout);
                }
                cfxImportBegReg (buffer, cfxImpREG_NODES);
                lastid = loadid;
            }
            getline ();

            /* add if element load flag is set */

            if ('1' == buffer[0])
                add_face (elemid, &buffer[9]);
            while (--nlines > 0)
                getline ();
        }

        /* named component */

        else if (packet == 21) {
            int cnt, type, id;
            elemid = atoi (&buffer[2]);
            nnodes = atoi (&buffer[10]) / 2;
            getline ();
            
            /* strip leading and trailing spaces */

            buffer[sizeof(buffer)-1] = 0;
            p = buffer + strlen (buffer);
            while (--p >= buffer && isspace(*p))
                ;
            *++p = 0;
            for (p = buffer; *p && isspace(*p); p++)
                ;
            if (verbose) {
                printf ("reading packet 21 (group) as region <%s>...\n", p);
                fflush (stdout);
            }
            cfxImportBegReg (p, cfxImpREG_NODES);

            /* currently only handle type 5 (nodes) in groups */

            for (n = 0, cnt = 0; n < nnodes; n++) {
                if (0 == (n % 5))
                    lineno++;
                fscanf (fp, "%d%d", &type, &id);
                if (5 == type) {
                    nodeid[cnt++] = id;
                    if (8 == cnt) {
                        cfxImportAddReg (8, nodeid);
                        cnt = 0;
                    }
                }
            }
            while (getc (fp) != '\n')
                ;
            if (cnt)
                cfxImportAddReg (cnt, nodeid);
            cfxImportEndReg ();
        }

        /* all others */

        else {
            nlines = atoi (&buffer[18]);
            while (nlines--)
                getline ();
        }

        if (NULL == fgets (buffer, sizeof(buffer), fp))
            break;
        lineno++;
        packet = atoi (buffer);
    }

    fclose (fp);
    cfxImportError (NULL);

    /* finish up and send the data */

    if (verbose) {
        printf ("transfering data...\n");
        fflush (stdout);
    }
    cfxImportDone ();

    /* print summary */

    if (verbose) {
        size_t stats[cfxImpCNT_SIZE];
        long bytes;
        static char *statname[] = {
            "imported nodes    ",
            "imported elements ",
            "imported regions  ",
            "unreferenced nodes",
            "duplicate nodes   ",
            "tet elements      ",
            "pyramid elements  ",
            "wedge elements    ",
            "hex elements      ",
            "total bytes sent  "
        };
        bytes = cfxImportTotals (stats);
        putchar ('\n');
        for (n = 0; n < 9; n++)
            printf ("%s = %ld\n", statname[n], stats[n]);
        printf ("%s = %ld\n", statname[9], bytes);
    }
    exit (0);
}
