/*
Generate tesseroid model from a regular grid.
*/


#include <stdio.h>
#include <time.h>
#include "../lib/version.h"
#include "../lib/parsers.h"
#include "../lib/logger.h"
#include "../lib/geometry.h"


/** Print the help message */
void print_help()
{
    printf("Usage: tessmodgen [ARGUMENTS] [OPTIONS]\n\n");
    printf("Generate a tesseroid model of an interface, like topography,\n");
    printf("moho, sediment thickness, etc.\n\n");
    printf("Each tesseroid has its top face centered of the respective grid\n");
    printf("point. The top and bottom of the tesseroid are define as:\n");
    printf("  * top = height of grid point and bottom = reference level\n");
    printf("    if height of grid point > reference level\n");
    printf("  * other way around if otherwise\n\n");
    printf("All units either SI or degrees!\n\n");
    printf("Input:\n");
    printf("  REGULAR grid passed through standard input (stdin).\n");
    printf("  Reads 3 values per line: longitude latitude height\n");
    printf("  height should be read as 'height above the mean Earth radius'\n");
    printf("  If bellow the Earth radius use negative heights.\n");
    printf("  Lines that start with # are ignored as comments.\n");
    printf("  Lines should be no longer than 10000 (ten thousand) characters.");
    printf("  \n\n");
    printf("Output:\n");
    printf("  Tesseroids printed to standard output (stdout)\n");
    printf("  * Each tesseroid is specified by the values of its borders\n");
    printf("    and density\n");
    printf("  * Will print one tesseroid per line\n");
    printf("  * Each line has the following column format:\n");
    printf("       West East South North Top Bottom Density\n");
    printf("  * Top and Bottom should be read as 'height to top' and \n");
    printf("    'height to bottom' from the mean Earth radius. Use negative\n");
    printf("    values if bellow the surface, for example when modeling\n");
    printf("    deep structures, and positive if above the surface, for\n");
    printf("    example when modeling topography.\n");
    printf("  * If a line starts with # it will be considered a comment\n");
    printf("    and will be ignored\n\n");
    printf("Arguments:\n");
    printf("  -sDLON/DLAT The grid spacing in the longitude and latitude\n");
    printf("              directions, respectively, in DECIMAL DEGREES.\n");
    printf("              Will be used as the size of the tesseroids.\n");
    printf("              WARNING: You may get wrong results if -s is \n");
    printf("                       different from the grid spacing!\n");
    printf("  -dDENS      Density of the tesseroids. If ommited will expect\n");
    printf("              a 4th column on the input with DENS values for\n");
    printf("              each point. Tesseroids above the reference will\n");
    printf("              have density DENS, and bellow will have density\n");
    printf("              -DENS.\n");
    printf("  -zREF       Height of the reference level with respect to the\n");
    printf("              mean Earth radius. If bellow the mean Earth\n");
    printf("              radius, use a negative value.\n\n");
    printf("Options:\n");
    printf("  -h          Print instructions.\n");
    printf("  --version   Print version and license information.\n");
    printf("  -v          Enable verbose printing to stderr.\n");
    printf("  -lFILENAME  Print log messages to file FILENAME.\n");
    print_copyright();
}


/** Main */
int main(int argc, char **argv)
{
    char *progname = "tessmodgen";
    TESSMODGEN_ARGS args;
    int rc, line, error_exit = 0, bad_input = 0, size = 0, nchars, nread;
    char buff[10000];
    double lon, lat, height, w, e, s, n, top, bot, dens;
    FILE *logfile = NULL;
    time_t rawtime;
    struct tm * timeinfo;

    log_init(LOG_INFO);

    rc = parse_tessmodgen_args(argc, argv, progname, &args, &print_help);
    if(rc == 2)
    {
        return 0;
    }
    if(rc == 1)
    {
        log_warning("Terminating due to bad input");
        log_warning("Try '%s -h' for instructions", progname);

        return 1;
    }

    /* Set the appropriate logging level and log to file if necessary */
    if(!args.verbose)
    {
        log_init(LOG_WARNING);
    }
    if(args.logtofile)
    {
        logfile = fopen(args.logfname, "w");
        if(logfile == NULL)
        {
            log_error("unable to create log file %s", args.logfname);
            log_warning("Terminating due to bad input");
            log_warning("Try '%s -h' for instructions", progname);
            return 1;
        }
        log_tofile(logfile, LOG_INFO);
    }

    /* Print standard verbose */
    log_info("%s (Tesseroids project) %s", progname, tesseroids_version);
    time(&rawtime);
    timeinfo = localtime(&rawtime);
    log_info("(local time) %s", asctime(timeinfo));

    /* Print a header on the output with provenance information */
    printf("# Tesseroid model generated by %s %s:\n", progname,
           tesseroids_version);
    printf("#   local time: %s", asctime(timeinfo));
    printf("#   grid spacing (size of tesseroids): %g deg lon / %g deg lat\n",
        args.dlon, args.dlat);
    printf("#   reference level (depth): %g\n", args.ref);
    if(args.fix_density)
    {
        printf("#   density: %g\n", args.dens);
        log_info("Using fixed density value: %g", args.dens);
    }
    else
    {
        printf("#   density: read from input\n");
        log_info("Reading density values from input grid");
    }

    /* Read each regular grid from stdin and generate the tesseroids */
    for(line = 1; !feof(stdin); line++)
    {
        if(fgets(buff, 10000, stdin) == NULL)
        {
            if(ferror(stdin))
            {
                log_error("problem encountered reading line %d", line);
                error_exit = 1;
                break;
            }
        }
        else
        {
            /* Check for comments and blank lines */
            if(buff[0] == '#' || buff[0] == '\r' || buff[0] == '\n')
            {
                continue;
            }
            strstrip(buff);
            if(args.fix_density)
            {
                nread = sscanf(buff, "%lf %lf %lf%n", &lon, &lat, &height,
                               &nchars);
                /* The lon != lon looks weird but this checks for NaN values */
                if(nread != 3 || buff[nchars] != '\0' ||
                   lon != lon || lat != lat || height != height)
                {
                    log_warning("bad/invalid grid point at line %d", line);
                    log_warning("skipping this line and continuing");
                    bad_input++;
                    continue;
                }
            }
            else
            {
                nread = sscanf(buff, "%lf %lf %lf %lf%n", &lon, &lat, &height,
                               &dens, &nchars);
                if(nread != 4 || buff[nchars] != '\0' ||
                   lon != lon || lat != lat || height != height || dens != dens)
                {
                    log_warning("bad/invalid grid point at line %d", line);
                    log_warning("skipping this line and continuing");
                    bad_input++;
                    continue;
                }
            }
            w = lon - 0.5*args.dlon;
            e = lon + 0.5*args.dlon;
            s = lat - 0.5*args.dlat;
            n = lat + 0.5*args.dlat;
            if(height >= args.ref)
            {
                top = height;
                bot = args.ref;
                if(args.fix_density)
                    dens = args.dens;
            }
            else
            {
                top = args.ref;
                bot = height;
                if(args.fix_density)
                    dens = -args.dens;
                else
                    dens *= -1;
            }
            printf("%.15g %.15g %.15g %.15g %.15g %.15g %.15g\n", w, e, s, n,
                   top, bot, dens);
            size++;
        }
    }
    if(bad_input)
    {
        log_warning("Encountered %d bad grid points which were skipped",
                    bad_input);
    }
    if(error_exit)
    {
        log_warning("Terminating due to error in input");
        log_warning("Try '%s -h' for instructions", progname);
    }
    else
    {
        log_info("Generated %d tesseroids.", size);
    }
    /* Clean up */
    if(args.logtofile)
        fclose(logfile);
    return 0;
}
