/* coollistbox.c - simple example usage of the coolwidget X API
   Copyright (C) 1997 Paul Sheer

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307, USA.
 */

#include <coolwidget.h>
#include "cmdlineopt.h"
#include "pool.h"
#include "mad.h"

/* {{{ command-line options */

#ifdef HAVE_DND
extern int option_dnd_version;
#endif

/* main and first window */
Window main_window = 0;

/* shell command to run */
extern char *option_man_cmdline;

/* argv[0] */
char *argv_nought = 0;

int delim = '&';

char *option_delim = 0;

int print_field = 0;

int columns = 80, rows = 25;

/* font from the library */
extern char *init_font;

/* server from command line */
char *option_display = 0;

/* font from the command line */
char *option_font = "-*-helvetica-bold-r-*--14-*-*-*-p-*-iso8859-1";

static int get_help = 0;
static int print_error = 0;
static int get_version = 0;

static int max_fields = 999999;
static int chop_fields = 999999;

/* other things on the command line */
static char *command_line_args[] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

void usage (void)
{
    printf (\
	    _ ("Coollistbox version %s\nUsage:\n" \
	       "Coollistbox [options] <Message-Header>\n" \
	       "-d, -display <display>            the X server to display on\n" \
	 "-f, -fn, -font <font-name>        default: 8x13bold\n" \
	       "-e, -error                        print `error' to stdout if data\n" \
	     "                                  is not empty.\n" \
	       "--rows <n>                        height of window in mean chars\n" \
	       "--columns <n>                     width of window in mean chars\n" \
	       "--field <n>                       print out field, else prints line number\n" \
	       "--delimeter, -delim <c>           use <c> as a delimeter: default is &\n" \
	       "--max-fields <n>                  limit number of fields,\n" \
	       "                                  rest of line goes in one field\n" \
	       "--chop-fields <n>                 limit number of fields,\n" \
	       "                                  rest of line is ignored\n" \
	       "-h, -H, -?, --help                print this message to stdout\n" \
	"-V, -v, --version                 print versiom info\n" \
	       "\n" \
	    "Coollistbox reads from stdin and displays the result in\n" \
      "a scrollable fielded message box from the coolwidgets X Window widget\n" \
	    "library. If no data is read from stdin then coollistbox\n" \
	"does nothing.\n" \
	"Coollistbox uses the delimeter to seperate the text into fields and displays\n" \
	"it in spreadsheat style.\n" \
	"It prints out the line number double clickled on, or a field in that line\n" \
	"if the field option is set. If the cancel button or escape is\n" \
	"pressed, it prints -1\n" \
	"as an example, try:  ps | sed -e 's/^[ ]*//g' -e 's/[ ][ ]*/ /g' \n | coollistbox -delim ' ' --max-fields 5\n" \
	       "\n"), \
	    VERSION);
}

void version (void)
{
    printf (_ ("Coollistbox version %s\n"), VERSION);
}

struct prog_options coollistbox_options[] =
{
    {' ', "", "", ARG_STRINGS, 0, command_line_args, 0},
#ifdef HAVE_DND
    {0, "-dnd-old", "--dnd-old", ARG_CLEAR, 0, 0, &option_dnd_version},
#endif
    {'f', "-fn", "-font", ARG_STRING, &option_font, 0, 0},
    {'e', "-error", "", ARG_SET, 0, 0, &print_error},
    {'h', "-?", "--help", ARG_SET, 0, 0, &get_help},
    {'H', "-help", "--help", ARG_SET, 0, 0, &get_help},
    {'V', "-v", "--version", ARG_SET, 0, 0, &get_version},
    {0, "", "--field", ARG_INT, 0, 0, &print_field},
    {0, "", "--columns", ARG_INT, 0, 0, &columns},
    {0, "", "--rows", ARG_INT, 0, 0, &rows},
    {0, "-delim", "--delimiter", ARG_STRING, &option_delim, 0, 0},
    {'d', "", "-display", ARG_STRING, &option_display, 0, 0},
    {0, "", "--max-fields", ARG_INT, 0, 0, &max_fields},
    {0, "", "--chop-fields", ARG_INT, 0, 0, &chop_fields},
    {0, 0, 0, 0, 0, 0, 0}
};

/* here we use our own function (which is better than get_opt() or get_opt_long()) */
static void process_command_line (int argc, char **argv)
{
    int error;
    error = get_cmdline_options (argc, argv, coollistbox_options);

    if (option_delim)
	delim = *option_delim;

    if (error) {
	fprintf (stderr, _ ("%s: error processing commandline argument %d\n"), argv[0], error);
	usage ();
	exit (1);
    }
    if (get_help)
	usage ();
    if (get_version)
	version ();
    if (get_help || get_version)
	exit (0);
}

/* }}} command-line options */


void load_trivial_options (void);

Window find_mapped_window (Window in);

/* draws a scrollable text box with a button to clear. Can be used to give long help messages */
int CFieldedTextboxMessageDialog (Window in, int x, int y, int cols, int lines, const char *heading,
	       void *data, char **(*get_line) (void *, int, int *, int *))
{
    Window win;
    CWidget *w;
    CEvent cwevent;
    CState s;
    int width, height;
    int line = -1;

    width = cols * FONT_MEAN_WIDTH;
    height = lines * FONT_PIX_PER_LINE;

    if (!in) {
	x = 20;
	y = 20;
    }
    in = find_mapped_window (in);

    CBackupState (&s);
    CDisable ("*");
    win = CDrawHeadedDialog ("_error", in, x, y, heading);
    CGetHintPos (&x, &y);

    w = CDrawFieldedTextbox ("_textmessbox", win, x, y,
			 width, height, 0, 0,
			 get_line,
			 0, data);

    w->position |= POSITION_WIDTH | POSITION_HEIGHT;
    w = CIdent ("_textmessbox.vsc");
    if (w)
	w->position |= POSITION_HEIGHT | POSITION_RIGHT;
    w = CIdent ("_textmessbox.hsc");
    if (w)
	w->position |= POSITION_WIDTH | POSITION_BOTTOM;

/*
   CDrawTextbox ("_textmessbox", win, x, y, width, height, line, 0, text, 0);
 */

    CGetHintPos (0, &y);
    (CDrawPixmapButton ("_clickhere", win, x, y, PIXMAP_BUTTON_TICK))->position |= POSITION_BOTTOM;
    CGetHintPos (&x, 0);
    (CDrawPixmapButton ("_crosshere", win, x, y, PIXMAP_BUTTON_CROSS))->position |= POSITION_BOTTOM;

    CSetSizeHintPos ("_error");
    CMapDialog ("_error");
    CSetWindowResizable ("_error", FONT_MEAN_WIDTH * 40, min (FONT_PIX_PER_LINE * 5 + 210, y), 1600, 1200);	/* minimum and maximum sizes */
    CFocus (CIdent ("_textmessbox"));
    for (;;) {
	CNextEvent (NULL, &cwevent);
	if (!CIdent ("_error"))
	    break;
	if (!strcmp (cwevent.ident, "_crosshere") || cwevent.command == CK_Cancel) {
	    line = -1;
	    break;
	}
	if (!strcmp (cwevent.ident, "_clickhere") || cwevent.command == CK_Enter || cwevent.double_click) {
	    line = (CIdent ("_textmessbox"))->cursor;
	    break;
	}
    }
    CDestroyWidget ("_error");
    CRestoreState (&s);
    return line;
}

char **get_list_line (void *data, int line_number, int *num_fields, int *tagged)
{
    char ***e;
    e = (char ***) data;
    *num_fields = 0;
    if (e[line_number]) {
	while (e[line_number][*num_fields])
	    (*num_fields)++;
    }
    *tagged = 0;
    return e[line_number];
}


int main (int argc, char **argv)
{
    POOL *pool;
    CInitData coollistbox_startup;
    char *header = 0;
    char ***entry;
    char *data, *p, *q;
    int c;

    int i, lines = 0, fields = 1, line, field, f;

    setlocale (LC_CTYPE, "");
    setlocale (LC_TIME, "");
    setlocale (LC_MESSAGES, "");
    bindtextdomain (PACKAGE, LOCALEDIR);
    textdomain (PACKAGE);

    load_trivial_options ();

    process_command_line (argc, argv);

/* initialise the library */
    memset (&coollistbox_startup, 0, sizeof (coollistbox_startup));
    coollistbox_startup.name = argv[0];
    coollistbox_startup.display = option_display;
    coollistbox_startup.font = option_font;
    CInitialise (&coollistbox_startup);
    CDrawMainWindow ("dummy", "dummy");

    pool = pool_init ();
    for (;;) {
	char ch;
	c = fgetc (stdin);
	if (c < 0)
	    break;
	ch = c;
	pool_write (pool, (unsigned char *) &c, 1);
    }
    c = '\0';

    if (!pool_length (pool))
	exit (0);

    pool_write (pool, (unsigned char *) &c, 1);
    pool_null (pool);

    data = (char *) pool_break (pool);
    i = strlen (data);
    if (data[i - 1] != '\n')
	data[i] = '\n';

/* count lines */
    f = 1;
    lines = 0;
    for (p = data; *p; p++) {
	if (*p == '\n') {
	    lines++;
	    if (f > fields)
		fields = f;
	    f = 1;
	}
	if (*p == delim) {
	    if (f <= max_fields && f <= chop_fields)
		f++;
	}
    }

    entry = malloc ((lines + 2) * sizeof (char *));
    p = data;
    for (line = 0; line < lines; line++) {
	entry[line] = malloc ((fields + 2) * sizeof (char *));
    }
    entry[lines] = 0;

    line = 0;
    field = 0;
    for (q = p = data; *p; p++) {
	if (*p == '\n') {
	    *p = '\0';
	    entry[line][field++] = q;
	    entry[line][field] = '\0';
	    line++;
	    field = 0;
	    q = p + 1;
	} else if (*p == delim) {
	    if (field == chop_fields) {
		*p = '\0';
		field++;
		q = p + 1;
	    } else if (field < max_fields - 1) {
		*p = '\0';
		entry[line][field++] = q;
		entry[line][field] = '\0';
		q = p + 1;
	    }
	}
    }

    if (command_line_args[0]) {
	int l = 0;
	i = 0;
	while (command_line_args[i]) {
	    l += strlen (command_line_args[i]) + 1;
	    i++;
	}
	i = 0;
	header = CMalloc (l + 16);
	strcpy (header, " ");
	while (command_line_args[i]) {
	    strcat (header, command_line_args[i]);
	    strcat (header, " ");
	    i++;
	}
    } else {
	header = (char *) strdup (" Message ");
    }


    i = CFieldedTextboxMessageDialog (CRoot, 20, 20, columns, rows, header, (char *) entry, get_list_line);
    if (i == -1) {
	printf ("-1\n");
    } else {
	if (print_field)
	    printf ("%s\n", entry[i][print_field - 1]);
	else
	    printf ("%d\n", i + 1);
    }

    if (print_error)
	printf ("error\n");
/* close connection to the X display */
    CShutdown ();
    exit (1);
    return 0;
}











