/*!
  \file lib/gis/parser_help.c
 
  \brief GIS Library - Argument parsing functions (help)
  
  (C) 2001-2009, 2011 by the GRASS Development Team
  
  This program is free software under the GNU General Public License
  (>=v2). Read the file COPYING that comes with GRASS for details.
  
  \author Original author CERL
  \author Soeren Gebbert added Dec. 2009 WPS process_description document
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <grass/gis.h>
#include <grass/glocale.h>

#include "parser_local_proto.h"

static void usage(FILE *fp, int markers);
static void show_options(FILE *fp, int maxlen, const char *str);
static int show(FILE *fp, const char *item, int len);

/*!
  \brief Command line help/usage message.
  
  Calls to G_usage() allow the programmer to print the usage
  message at any time. This will explain the allowed and required
  command line input to the user. This description is given according
  to the programmer's definitions for options and flags. This function
  becomes useful when the user enters options and/or flags on the
  command line that are syntactically valid to the parser, but
  functionally invalid for the command (e.g. an invalid file name.)
  
  For example, the parser logic doesn't directly support grouping
  options. If two options be specified together or not at all, the
  parser must be told that these options are not required and the
  programmer must check that if one is specified the other must be as
  well. If this additional check fails, then G_parser() will succeed,
  but the programmer can then call G_usage() to print the standard
  usage message and print additional information about how the two
  options work together.
*/
void G_usage(void)
{
    usage(stderr, 0);
}

void G__usage_text(void)
{
    usage(stdout, 1);
}

static void usage(FILE *fp, int markers)
{
    struct Option *opt;
    struct Flag *flag;
    char item[256];
    const char *key_desc;
    int maxlen;
    int len, n;
    int new_prompt = 0;

    new_prompt = G__uses_new_gisprompt();

    if (!st->pgm_name)		/* v.dave && r.michael */
	st->pgm_name = G_program_name();
    if (!st->pgm_name)
	st->pgm_name = "??";

    if (st->module_info.label || st->module_info.description) {
	fprintf(fp, "\n");
	if (markers)
	    fprintf(fp, "{{{DESCRIPTION}}}\n");
	fprintf(fp, "%s\n", _("Description:"));
	if (st->module_info.label)
	    fprintf(fp, " %s\n", st->module_info.label);
	if (st->module_info.description)
	    fprintf(fp, " %s\n", st->module_info.description);
    }
    if (st->module_info.keywords) {
	fprintf(fp, "\n");
	if (markers)
	    fprintf(fp, "{{{KEYWORDS}}}\n");
	fprintf(fp, "%s\n ", _("Keywords:"));
	G__print_keywords(fp, NULL);
	fprintf(fp, "\n");
    }

    fprintf(fp, "\n");
    if (markers)
	fprintf(fp, "{{{USAGE}}}\n");
    fprintf(fp, "%s\n ", _("Usage:"));

    len = show(fp, st->pgm_name, 1);

    /* Print flags */

    if (st->n_flags) {
	item[0] = ' ';
	item[1] = '[';
	item[2] = '-';
	flag = &st->first_flag;
	for (n = 3; flag != NULL; n++, flag = flag->next_flag)
	    item[n] = flag->key;
	item[n++] = ']';
	item[n] = 0;
	len = show(fp, item, len);
    }

    maxlen = 0;
    if (st->n_opts) {
	opt = &st->first_option;
	while (opt != NULL) {
	    if (opt->key_desc != NULL)
		key_desc = opt->key_desc;
	    else if (opt->type == TYPE_STRING)
		key_desc = "string";
	    else
		key_desc = "value";

	    if (!opt->key) {
		fprintf(stderr, "\n%s\n", _("ERROR: Option key not defined"));
		exit(EXIT_FAILURE);
	    }
	    n = strlen(opt->key);
	    if (n > maxlen)
		maxlen = n;

	    strcpy(item, " ");
	    if (!opt->required)
		strcat(item, "[");
	    strcat(item, opt->key);
	    strcat(item, "=");
	    strcat(item, key_desc);
	    if (opt->multiple) {
		strcat(item, "[,");
		strcat(item, key_desc);
		strcat(item, ",...]");
	    }
	    if (!opt->required)
		strcat(item, "]");

	    len = show(fp, item, len);

	    opt = opt->next_opt;
	}
    }
    if (new_prompt) {
	strcpy(item, " [--overwrite]");
	len = show(fp, item, len);
    }

    strcpy(item, " [--verbose]");
    len = show(fp, item, len);

    strcpy(item, " [--quiet]");
    len = show(fp, item, len);

    fprintf(fp, "\n");

    /* Print help info for flags */

    fprintf(fp, "\n");
    if (markers)
	fprintf(fp, "{{{FLAGS}}}\n");
    fprintf(fp, "%s\n", _("Flags:"));

    if (st->n_flags) {
	flag = &st->first_flag;
	while (flag != NULL) {
	    fprintf(fp, "  -%c   ", flag->key);

	    if (flag->label) {
		fprintf(fp, "%s\n", flag->label);
		if (flag->description)
		    fprintf(fp, "        %s\n", flag->description);

	    }
	    else if (flag->description) {
		fprintf(fp, "%s\n", flag->description);
	    }

	    flag = flag->next_flag;
	}
    }

    if (new_prompt)
	fprintf(fp, " --o   %s\n",
		_("Allow output files to overwrite existing files"));

    fprintf(fp, " --v   %s\n", _("Verbose module output"));
    fprintf(fp, " --q   %s\n", _("Quiet module output"));

    /* Print help info for options */

    if (st->n_opts) {
	fprintf(fp, "\n");
	if (markers)
	    fprintf(fp, "{{{PARAMETERS}}}\n");
	fprintf(fp, "%s\n", _("Parameters:"));
	opt = &st->first_option;
	while (opt != NULL) {
	    fprintf(fp, "  %*s   ", maxlen, opt->key);

	    if (opt->label) {
		fprintf(fp, "%s\n", opt->label);
		if (opt->description) {
		    fprintf(fp, "  %*s    %s\n",
			    maxlen, " ", opt->description);
		}
	    }
	    else if (opt->description) {
		fprintf(fp, "%s\n", opt->description);
	    }

	    if (opt->options)
		show_options(fp, maxlen, opt->options);
	    /*
	       fprintf (fp, "  %*s   options: %s\n", maxlen, " ",
	       _(opt->options)) ;
	     */
	    if (opt->def)
		fprintf(fp, _("  %*s   default: %s\n"), maxlen, " ",
			opt->def);

	    if (opt->descs) {
		int i = 0;

		while (opt->opts[i]) {
		    if (opt->descs[i])
			fprintf(fp, "  %*s    %s: %s\n",
				maxlen, " ", opt->opts[i], opt->descs[i]);

		    i++;
		}
	    }

	    opt = opt->next_opt;
	}
    }
}

static void show_options(FILE *fp, int maxlen, const char *str)
{
    char *buff = G_store(str);
    char *p1, *p2;
    int totlen, len;

    fprintf(fp, _("  %*s   options: "), maxlen, " ");
    totlen = maxlen + 13;
    p1 = buff;
    while ((p2 = strchr(p1, ','))) {
	*p2 = '\0';
	len = strlen(p1) + 1;
	if ((len + totlen) > 76) {
	    totlen = maxlen + 13;
	    fprintf(fp, "\n %*s", maxlen + 13, " ");
	}
	fprintf(fp, "%s,", p1);
	totlen += len;
	p1 = p2 + 1;
    }
    len = strlen(p1);
    if ((len + totlen) > 76)
	fprintf(fp, "\n %*s", maxlen + 13, " ");
    fprintf(fp, "%s\n", p1);

    G_free(buff);
}

static int show(FILE *fp, const char *item, int len)
{
    int n;

    n = strlen(item) + (len > 0);
    if (n + len > 76) {
	if (len)
	    fprintf(fp, "\n  ");
	len = 0;
    }
    fprintf(fp, "%s", item);
    return n + len;
}
