#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif

#include "cfxExport.h"
#include "getargs.h"

static char options[] = "u:d:t:cif";

static char *usgmsg[] = {
    "usage: ExportTemplate [options] res_file [basename]",
    "  options are:",
    "    -u<level>     = user level of interest",
    "    -d<domain>    = domain of interest (default is 0 - all the domains",
    "                    are combined into a single domain)",
    "    -t<timestep>  = timestep of interest (if set to -1, all timesteps",
    "                    are exported)",
    "    -c            = use corrected boundary node data",
    "    -i            = include boundary node only data",
    "    -f            = get info on the res_file (No output is created)",
    "<basename> is the base filename for Template file output.",
    "If not specified, it defaults to 'res_file'. The Template",
    "geometry file will be written to <basename>.geom, the",
    "results file to <basename>.res, and the variables to",
    "<basename>.s## or <basename>.v## where ## is the variable",
    "number and s indicates a scalar and v a vector.",
    NULL
};

void main (int argc, char *argv[])
{
    char *pptr;
    char baseFileName[256], fileName[256], errmsg[256];
    int i, n, counts[cfxCNT_SIZE], dim, length, namelen;
    int nnodes, nelems, nscalars, nvectors, nvalues;
    int level = 1, zone = 0, alias = 1, bndfix = 0, bnddat = 0;
    int timestep = -1, infoOnly = 0;
    int ts, t, t1, t2;
    int nTimeDig = 1;     /* number of digits in transient file suffix */
    char zoneExt[256];    /* zone extension added to the base filename */
    int isTimestep = 0;
    float timeVal = 0.0;  /* time value in the single timestep mode */
    char *wildcard = { "**********" }; /* used in transient file 
                                          specification */
    FILE *fp;
    cfxNode *nodes;
    cfxElement *elems;
    float *var;

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

    while ((n = getargs (argc, argv, options)) > 0) {
        switch (n) {
            case 'u':
                level = atoi (argarg);
                break;
            case 'd':
                zone = atoi (argarg);
                break;
            case 't':
                timestep = atoi (argarg);
                isTimestep = 1;
                break;
            case 'c':
                bndfix = 1;
                break;
            case 'i':
                bnddat = 1;
                break;
            case 'f':
                infoOnly = 1;
                break;
        }
    }

    /* CFX-5 results file */

    if (argind >= argc)
        usage (usgmsg, "CFX-5 results file not specified");
    if (access (argv[argind], 0)) {
        fprintf (stderr, "result file <%s> does not exist\n", argv[argind]);
        exit (1);
    }

    /* base file name */

   if (argind + 1 < argc)
        strcpy (baseFileName, argv[argind+1]);
    else
        strcpy (baseFileName, argv[argind]);
    if (NULL != (pptr = strrchr (baseFileName, '/')))
        pptr++;
    else if (NULL != (pptr = strrchr (baseFileName, '\\')))
        pptr++;
    else
        pptr = baseFileName;

    /* don't overwrite results file */

    sprintf (fileName, "%s.res", baseFileName);
    if (0 == strcmp (argv[argind], fileName)) {
        fprintf (stderr, "Template res file would overwrite CFX-5 results file\n");
        fprintf (stderr, "Need to select new Template output base file name\n");
        exit (1);
    }

    /* open CFX-5 results file */

    printf ("\nreading CFX-5 results from <%s>\n", argv[argind]);
    n = cfxExportInit (argv[argind], NULL);

    if (infoOnly) {
      int nt;

      printf("\n%d domains:\n", n);
      for(i = 1; i <= n; i++)
        printf("  %d   %s\n", i, cfxExportZoneName(i));
      
      nt = cfxExportTimestepCount();
      printf("%d timesteps:\n", nt);    
      if(nt) {
        for(i = 1; i <= nt; i++)
          printf("  %d\n", cfxExportTimestepNumGet(i));
      }

      cfxExportDone();
      exit (0);
    }

    /* determine the zone suffix for the export files */
    strcpy(zoneExt, "");
    if(zone == 0) {
      printf ("processing all domains\n");
      cfxExportSetVarParams(bndfix, level);
    }
    else {
      printf ("processing domain %d\n", zone);
      if(n != 1) {
        float f;
        int nZoneDig = 0;
        
        /* count number of digits needed to fit any zone number */
        f = (float) n;
        while((f /= 10) >= 1) nZoneDig++;
        sprintf(zoneExt, "_d%*.*d", nZoneDig, nZoneDig, zone);
      }
    }

    if (cfxExportZoneSet (zone, counts) < 0)
        cfxExportFatal ("invalid zone number");

    nnodes = cfxExportNodeCount();
    nelems = cfxExportElementCount();

    if (counts[cfxCNT_PYR]) {
        printf ("%d pyramid elements found - they are being ignored",
            counts[cfxCNT_PYR]);
        nelems -= counts[cfxCNT_PYR];
    }
    if (!nnodes || !nelems)
        cfxExportFatal ("no nodes and/or elements");

   /* Timestep setup */
    if(isTimestep && timestep == -1 && !cfxExportTimestepCount()) {
      isTimestep = 0;
    }

    if(isTimestep) {
      int i;
      float f;
      
      if(timestep == -1) {     
        printf("processing all timesteps\n");
        t1 = 1;
        t2 = cfxExportTimestepCount() + 1;
      }
      else {
        int isFound = 0;
        printf("processing timestep %d\n", timestep); 
        for(i = 1; i <= cfxExportTimestepCount() + 1; i++)
          if(cfxExportTimestepNumGet(i) == timestep) {
            timeVal = cfxExportTimestepTimeGet(i);
            t1 = t2 = i;
            isFound = 1;
            break;
          }
        if(!isFound) {
          sprintf(errmsg, "\nTimestep %d not found. "
                  "Use -f to see the list of valid timesteps.\n", timestep);
          cfxExportFatal (errmsg);  
        }     
      }
      /* count number of digits needed to fit any timestep number */
      f = (float) cfxExportTimestepCount();
      while((f /= 10) >= 1) nTimeDig++;
    }  
    else {
      timeVal = cfxExportTimestepTimeGet(cfxExportTimestepCount() + 1);
      timestep = cfxExportTimestepNumGet(cfxExportTimestepCount() + 1);
      t1 = t2 = cfxExportTimestepCount() + 1;
    }

    /* Template geometry output */

    sprintf (fileName, "%s.geom", baseFileName);
    if (NULL == (fp = fopen (fileName, "w+"))) {
        sprintf (errmsg, "can't open <%s> for output", fileName);
        cfxExportFatal (errmsg);
    }
    printf ("writing Template Geometry file to <%s>\n", fileName);

    /* write header */

    fprintf( fp, "Template Geometry file exported from CFX-5\n");
    fprintf( fp, " \n");
    fprintf( fp, "node id given\n");
    fprintf( fp, "element id off\n");

    /* write nodes */

    fprintf( fp, "coordinates\n");
    fprintf( fp, "%8d\n", nnodes );

    nodes = cfxExportNodeList();
    printf ("  writing %d nodes ...", nnodes);
    fflush (stdout);
    for (n = 0; n < nnodes; n++, nodes++) {
      fprintf( fp, "%8d %12.5e %12.5e %12.5e\n", n + 1, nodes->x, 
            nodes->y, nodes->z );
    }
    cfxExportNodeFree();
    printf (" done\n");

    /* write elements */

    fprintf( fp, "part 1\n" );
    fprintf( fp, "volume elements\n");
    printf ("  writing %d elements...", nelems);
    fflush (stdout);

    /* tets */

    fprintf( fp, "tetra4\n");
    fprintf( fp, "%8d\n", counts[cfxCNT_TET] );

    if (counts[cfxCNT_TET]) {
        elems = cfxExportElementList();
        for (n = 0; n < nelems; n++, elems++) {
            if (cfxELEM_TET == elems->type) {
                for (i = 0; i < elems->type; i++)
                    fprintf (fp, "%8d", elems->nodeid[i]);
                putc ('\n', fp);
            }
        }
    }

    /* wedges */

    fprintf( fp, "penta6\n");
    fprintf( fp, "%8d\n", counts[cfxCNT_WDG] );

    if (counts[cfxCNT_WDG]) {
        elems = cfxExportElementList();
        for (n = 0; n < nelems; n++, elems++) {
            if (cfxELEM_WDG == elems->type) {
                for (i = 0; i < elems->type; i++)
                    fprintf (fp, "%8d", elems->nodeid[i]);
              putc ('\n', fp);
            }
        }
    }

    /* hexes */

    fprintf( fp, "hexa8\n");
    fprintf( fp, "%8d\n", counts[cfxCNT_HEX] );

    if (counts[cfxCNT_HEX]) {
        elems = cfxExportElementList();
        for (n = 0; n < nelems; n++, elems++) {
            if (cfxELEM_HEX == elems->type)
                fprintf (fp, "%8d%8d%8d%8d%8d%8d%8d%8d\n",
                    elems->nodeid[0], elems->nodeid[1],
                    elems->nodeid[3], elems->nodeid[2],
                    elems->nodeid[4], elems->nodeid[5],
                    elems->nodeid[7], elems->nodeid[6]);
        }
    }
    printf (" done\n");
    fclose (fp);
    cfxExportElementFree();

    /* output results file */

    nscalars = nvectors = namelen = 0;
    if ((nvalues = cfxExportVariableCount(level)) > 0) {
        for (n = 1; n <= nvalues; n++) {
            cfxExportVariableSize (n, &dim, &length, &i);
            if ((1 != dim && 3 != dim) ||
                (length != nnodes && length != bnddat))
                continue;
            if (1 == dim)
                nscalars++;
            else
                nvectors++;
            i = strlen (cfxExportVariableName (n, alias));
            if (namelen < i)
                namelen = i;
        }
    }
    if (0 == (nscalars + nvectors)) {
        cfxExportDone ();
        exit (0);
    }

    sprintf (fileName, "%s.res", baseFileName);
    if (NULL == (fp = fopen (fileName, "w+"))) {
        sprintf (errmsg, "can't open <%s> for writing", fileName);
        cfxExportFatal (errmsg);
    }
    printf ("writing Template results file to <%s>\n", fileName);
    fflush (stdout);

    fprintf( fp, "%d %d 0\n", nscalars, nvectors );
    fprintf( fp, "%d\n", t2 - t1 + 1 );
    for(i = t1; i <= t2; i++) {
      fprintf( fp, "%13.4e", cfxExportTimestepTimeGet(i));
      if(!(i % 6)) fprintf( fp, "\n");
    }   
    fprintf( fp, "\n");
    if(isTimestep && t1 != t2)
      fprintf( fp, "0 1\n");
    
    if ( nscalars ) {
        for (n = 1; n <= nvalues; n++) {
            cfxExportVariableSize (n, &dim, &length, &i);
            if (1 == dim && (length == nnodes || length == bnddat))
              if(!isTimestep) 
                fprintf (fp, "%s%s.s%2.2d %s\n", pptr, zoneExt, 
                         n, cfxExportVariableName(n, alias));
              else if(t1 == t2)
                fprintf (fp, "%s%s_t%d.s%2.2d %s\n", pptr, zoneExt, 
                         cfxExportTimestepNumGet(t1), n, 
                         cfxExportVariableName(n, alias));
              else
                fprintf (fp, "%s%s_t%*.*s.s%2.2d %s\n", pptr, zoneExt, 
                         nTimeDig, nTimeDig, wildcard, n, 
                         cfxExportVariableName(n, alias));
        }
    }
    if ( nvectors ) {
        for (n = 1; n <= nvalues; n++) {
            cfxExportVariableSize (n, &dim, &length, &i);
            if (3 == dim && (length == nnodes || length == bnddat))
                if(!isTimestep) 
                  fprintf (fp, "%s%s.v%2.2d %s\n", pptr, zoneExt, 
                           n, cfxExportVariableName(n, alias));
                else if(t1 == t2)
                  fprintf (fp, "%s%s_t%d.v%2.2d %s\n", pptr, zoneExt, 
                           cfxExportTimestepNumGet(t1), n, 
                           cfxExportVariableName(n, alias));
                else
                  fprintf (fp, "%s%s_t%*.*s.v%2.2d %s\n", pptr, zoneExt, 
                           nTimeDig, nTimeDig, wildcard, n,
                           cfxExportVariableName(n, alias));
        }
    }
    fclose( fp );


    /* output each timestep to a different file */

    for(t = t1; t <= t2; t++) {

      ts = cfxExportTimestepNumGet(t);

      if(cfxExportTimestepSet(ts) < 0) {
        continue;
      }

      /* create variable files */

      printf ("writing variable output files\n");
      for (n = 1; n <= nvalues; n++) {
        cfxExportVariableSize (n, &dim, &length, &i);
        if ((1 == dim || 3 == dim) &&
            (length == nnodes || length == bnddat)) {
            if (NULL == (var = cfxExportVariableList (n, bndfix)))
                cfxExportFatal ("error getting variable");

            /* build file name and open file */

            if(!isTimestep) 
              sprintf( fileName, "%s%s.%c%2.2d", baseFileName, zoneExt,
                       1 == dim ? 's' : 'v', n);
            else if(t1 == t2)
              sprintf( fileName, "%s%s_t%d.%c%2.2d", baseFileName, zoneExt,
                       ts, 1 == dim ? 's' : 'v', n);
            else
              sprintf( fileName, "%s%s_t%*.*d.%c%2.2d", baseFileName, zoneExt,
                       nTimeDig, nTimeDig, t-1, 1 == dim ? 's' : 'v', n);
            
            if (NULL == (fp = fopen (fileName, "w+"))) {
                sprintf (errmsg, "can't open <%s> for writing\n", fileName);
                cfxExportFatal (errmsg);
            }
            printf ("  %-*s -> %s ...", namelen,
                cfxExportVariableName(n, alias), fileName);
            fflush (stdout);

            fprintf( fp, "%s\n", cfxExportVariableName(n, alias));
            length = nnodes * dim;
            for ( i = 0; i < length; i++, var++ ) {
                fprintf( fp, "%12.5e ", *var );
                if ( i && 5 == (i % 6) )
                    putc ('\n', fp);
            }
            if ( 0 != ( nvalues % 6 ) )
                putc( '\n', fp );
            fclose( fp );
            cfxExportVariableFree (n);
            printf (" done\n");
        }
      }
    } /* loop for each timestep */

    cfxExportDone();
    exit (0);
}
