/* 
 * Copyright (c) Tony Bybell 1999-2003.
 *
 * 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.
 */

#include <gtk/gtk.h>
#include <stdio.h>

#ifdef __linux__
			/* need to find getopt_long for non glibc platforms! */
#include <getopt.h>
#else
#include <unistd.h>
#endif

#include "aet.h"
#include "lx2.h"
#include "main.h"
#include "menu.h"
#include "vcd.h"
#include "lxt.h"
#include "lxt2_read.h"
#include "pixmaps.h"
#include "currenttime.h"
#include "fgetdynamic.h"
#include "rc.h"

char *whoami=NULL;

GtkWidget *signalwindow;
GtkWidget *wavewindow;
char paned_pack_semantics=1;	/* 1 for paned_pack, 0 for paned_add */
char zoom_was_explicitly_set=0; /* set on '*' encountered in .sav file read  */
int initial_window_x=700, initial_window_y=400; /* initial window sizes */
int initial_window_xpos=-1, initial_window_ypos=-1; /* initial window position (-1 == WM choice) */
char use_scrollbar_only=0;
char force_toolbars=0;		/* 1 sez use toolbar rendering */


static void print_help(char *nam)
{
#ifdef __linux__

printf(
"Usage: %s [OPTION]... [DUMPFILE] [SAVEFILE] [RCFILE]\n\n"
"  -f, --dump=FILE            specify dumpfile name\n"
"  -a, --save=FILE            specify savefile name\n"
"  -r, --rcfile=FILE          specify override .rcfile name\n"
"  -s, --start=TIME           specify start time for LXT2 block skip\n"    
"  -e, --end=TIME             specify end time for LXT2 block skip\n"    
"  -v, --vcd                  use stdin as a VCD dumpfile\n"
"  -h, --help                 display this help and exit\n"
"  -x  --exit                 exit after loading trace (for loader benchmarks)\n\n"

"VCD files and save files may be compressed with zip or gzip.  LXT and\n"
"LXT2 files must remain uncompressed due to their non-linear access.\n"
"Note that DUMPFILE is optional provided the --dump option is specified.\n"
"SAVEFILE and RCFILE are always optional.\n\n"

"Report bugs to <bybell@linux-workshop.com>.\n",nam);

#else

printf(
"Usage: %s [OPTION]... [DUMPFILE] [SAVEFILE] [RCFILE]\n\n"
"  -f FILE                    specify dumpfile name\n"
"  -a FILE                    specify savefile name\n"
"  -r FILE                    specify override .rcfile name\n"
"  -s TIME                    specify start time for LXT2 block skip\n"    
"  -e TIME                    specify end time for LXT2 block skip\n"    
"  -v                         use stdin as a VCD dumpfile\n"
"  -h                         display this help and exit\n"
"  -x                         exit after loading trace (for loader benchmarks)\n\n"

"VCD files and save files may be compressed with zip or gzip.  LXT and\n"
"LXT2 files must remain uncompressed due to their non-linear access.\n"
"Note that DUMPFILE is optional provided the -f option is specified.\n"
"SAVEFILE and RCFILE are always optional.\n\n"

"Report bugs to <bybell@linux-workshop.com>.\n",nam);

#endif

exit(0);
}


int main(int argc, char *argv[])
{
int i;
int c;
char is_vcd=0;
char fast_exit=0;
char opt_errors_encountered=0;

char *fname=NULL;
char *wname=NULL;
char *override_rc=NULL;
char *winname=NULL;
static char *winprefix="GTKWave - ";
static char *winstd="GTKWave (stdio) ";
static char *vcd_autosave_name="vcd_autosave.sav";
FILE *wave;

GtkWidget *window;
GtkWidget *main_vbox, *top_table, *whole_table;
GtkWidget *menubar;
GtkWidget *text1;
GtkWidget *zoombuttons;
GtkWidget *pagebuttons;
GtkWidget *fetchbuttons;
GtkWidget *discardbuttons;
GtkWidget *shiftbuttons;
GtkWidget *entry;
GtkWidget *timebox;
GtkWidget *panedwindow;
GtkWidget *dummy1, *dummy2;
GtkWidget *toolbar=NULL, *toolhandle=NULL;

char *skip_start=NULL, *skip_end=NULL;

whoami=malloc_2(strlen(argv[0])+1);	/* cache name in case we fork later */
strcpy(whoami, argv[0]);

if(!gtk_init_check(&argc, &argv))
	{
	printf("Could not initialize GTK!  Is DISPLAY env var/xhost set?\n\n");
	print_help(argv[0]);
	}

while (1)
        {
        int option_index = 0;

#ifdef __linux__
        static struct option long_options[] =
                {
                {"dump", 1, 0, 'f'},
                {"save", 1, 0, 'a'},
		{"rcfile", 1, 0, 'r'},
                {"start", 1, 0, 's'},
                {"end", 1, 0, 'e'},
                {"vcd", 0, 0, 'v'},
                {"help", 0, 0, 'h'},
                {"exit", 0, 0, 'x'},
                {0, 0, 0, 0}
                };

        c = getopt_long (argc, argv, "f:a:r:s:e:vhx", long_options, &option_index);
#else
	c = getopt      (argc, argv, "f:a:r:s:e:vhx");
#endif

        if (c == -1) break;     /* no more args */

        switch (c)
                {
                case 'v':
			is_vcd = 1;
			if(fname) free_2(fname);
			fname = malloc_2(4+1);
			strcpy(fname, "-vcd");
                        break;

                case 'h':
			print_help(argv[0]);
                        break;

                case 'x':
			fast_exit = 1;
                        break;

                case 'f':
			is_vcd = 0;
			if(fname) free_2(fname);
			fname = malloc_2(strlen(optarg)+1);
			strcpy(fname, optarg);
			break;

                case 'a':
			if(wname) free_2(wname);
			wname = malloc_2(strlen(optarg)+1);
			strcpy(wname, optarg);
			break;

                case 'r':
			if(override_rc) free_2(override_rc);
			override_rc = malloc_2(strlen(optarg)+1);
			strcpy(override_rc, optarg);
			break;

                case 's':
			if(skip_start) free(skip_start);
			skip_start = malloc_2(strlen(optarg)+1);
			strcpy(skip_start, optarg);
			break;			

                case 'e':
			if(skip_end) free(skip_end);
			skip_end = malloc_2(strlen(optarg)+1);
			strcpy(skip_end, optarg);
                        break;

                case '?':
			opt_errors_encountered=1;
                        break;

                default:
                        /* unreachable */
                        break;
                }
        }

if(opt_errors_encountered)
	{
	print_help(argv[0]);
	}

if (optind < argc)
        {
        while (optind < argc)
		{
		if(!fname)
			{
			is_vcd = 0;
			fname = malloc_2(strlen(argv[optind])+1);
			strcpy(fname, argv[optind++]);
			}
		else if(!wname)
			{
			wname = malloc_2(strlen(argv[optind])+1);
			strcpy(wname, argv[optind++]);
			}
		else if(!override_rc)
			{
			override_rc = malloc_2(strlen(argv[optind])+1);
			strcpy(override_rc, argv[optind++]);
			break; /* skip any extra args */
			}
		}
        }

if(!fname)
	{
	print_help(argv[0]);
	}

read_rc_file(override_rc);
printf("\n%s\n\n",WAVE_VERSION_INFO);

if((!wname)&&(make_vcd_save_file))
	{
	vcd_save_handle=fopen(vcd_autosave_name,"wb");
	errno=0;	/* just in case */
	}

sym=(struct symbol **)calloc_2(SYMPRIME,sizeof(struct symbol *));

/* load either the vcd or aet file depending on suffix then mode setting */
if(is_vcd)
	{
	winname=malloc_2(strlen(winstd)+4+1);
	strcpy(winname,winstd);
	}
	else
	{
	winname=malloc_2(strlen(fname)+strlen(winprefix)+1);
	strcpy(winname,winprefix);
	}

strcat(winname,fname);

if((strlen(fname)>3)&&((!strcmp(fname+strlen(fname)-4,".lxt"))||(!strcmp(fname+strlen(fname)-4,".lx2"))))
	{
	FILE *f = fopen(fname, "rb");
	int typ = 0;

	if(f)
		{
		char buf[2];
		unsigned int matchword;

		fread(buf, 2, 1, f);
		matchword = (((unsigned int)buf[0])<<8) | ((unsigned int)buf[1]);

		if(matchword == LT_HDRID) typ = 1;

		fclose(f);
		}

	if(typ)
		{
		lxt_main(fname);
		}
		else
		{
		lx2_main(fname, skip_start, skip_end);
		if(skip_start)
			{
			free(skip_start); skip_start=NULL;
			}
		if(skip_end)
			{
			free(skip_end); skip_end=NULL;
			}
		}	

	}
else	/* nothing else left so default to "something" */
	{
	vcd_main(fname);
	}

for(i=0;i<26;i++) named_markers[i]=-1;	/* reset all named markers */

tims.last=max_time;
tims.end=tims.last;		/* until the configure_event of wavearea */
tims.first=tims.start=tims.laststart=min_time;
tims.zoom=tims.prevzoom=0;	/* 1 pixel/ns default */
tims.marker=tims.lmbcache=-1;	/* uninitialized at first */

if((wname)||(vcd_save_handle))
	{
	int wave_is_compressed;
        char *str;

	if(vcd_save_handle)
		{
		wname=vcd_autosave_name;
		do_initial_zoom_fit=1;
		}

	if(((strlen(wname)>2)&&(!strcmp(wname+strlen(wname)-3,".gz")))||
	   ((strlen(wname)>3)&&(!strcmp(wname+strlen(wname)-4,".zip"))))
	        {
        	int dlen;
        	dlen=strlen(WAVE_DECOMPRESSOR);
	        str=wave_alloca(strlen(wname)+dlen+1);
	        strcpy(str,WAVE_DECOMPRESSOR);
	        strcpy(str+dlen,wname);
	        wave=popen(str,"r");
	        wave_is_compressed=~0;
	        }
	        else
	        {
	        wave=fopen(wname,"rb");
	        wave_is_compressed=0;
	        }

	if(!wave)
	        {
	        fprintf(stderr, "** WARNING: Error opening .sav file '%s', skipping.\n",wname);
	        }	
	        else
	        {
	        char *iline;
		char any_shadow = 0;

		if(is_lx2)
			{
		        while((iline=fgetmalloc(wave)))
		                {
		                parsewavline_lx2(iline);
				free_2(iline);
		                }

			lx2_import_masked();

			if(wave_is_compressed)
			        {
				pclose(wave);
			        wave=popen(str,"r");
			        }
			        else
			        {
				fclose(wave);
			        wave=fopen(wname,"rb");
			        }

			if(!wave)
			        {
			        fprintf(stderr, "** WARNING: Error opening .sav file '%s', skipping.\n",wname);
				goto savefile_bail;
			        }	
			}

		default_flags=TR_RJUSTIFY;
		shift_timebase_default_for_add=LLDescriptor(0);
	        while((iline=fgetmalloc(wave)))
	                {
	                parsewavline(iline);
			any_shadow |= shadow_active;
			free_2(iline);
	                }
		default_flags=TR_RJUSTIFY;
		shift_timebase_default_for_add=LLDescriptor(0);

		if(wave_is_compressed) pclose(wave); else fclose(wave);

                if(any_shadow)
                        {
                        if(shadow_straces)
                                {
                                shadow_active = 1;

                                swap_strace_contexts();
                                strace_maketimetrace(1);
                                swap_strace_contexts();

				shadow_active = 0;
                                }
                        }
	        }
	}

savefile_bail:
if(fast_exit)
	{
	printf("Exiting early because of --exit request.\n");
	exit(0);
	}

if ((!zoom_was_explicitly_set)&&
	((tims.last-tims.first)<=400)) do_initial_zoom_fit=1;  /* force zoom on small traces */

calczoom(tims.zoom);

window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), winname);
gtk_widget_set_usize(GTK_WIDGET(window), initial_window_x, initial_window_y);
gtk_signal_connect(GTK_OBJECT(window), "destroy", 
			GTK_SIGNAL_FUNC(file_quit_cmd_callback), 
		       	"WM destroy");
gtk_widget_show(window);
if((initial_window_xpos>=0)||(initial_window_ypos>=0))
	{
	if (initial_window_xpos<0) { initial_window_xpos = 0; }
	if (initial_window_ypos<0) { initial_window_ypos = 0; }
#ifdef WAVE_USE_GTK2
	gtk_window_move(GTK_WINDOW(window), initial_window_xpos, initial_window_ypos);
#else
	gtk_window_reposition(GTK_WINDOW(window), initial_window_xpos, initial_window_ypos);
#endif
	}
make_pixmaps(window);

main_vbox = gtk_vbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
gtk_container_add(GTK_CONTAINER(window), main_vbox);
gtk_widget_show(main_vbox);
    
get_main_menu(window, &menubar);
gtk_widget_show(menubar);

if(force_toolbars)
	{
	toolhandle=gtk_handle_box_new();
	gtk_widget_show(toolhandle);
	gtk_container_add(GTK_CONTAINER(toolhandle), menubar);
	gtk_box_pack_start(GTK_BOX(main_vbox), toolhandle, FALSE, TRUE, 0);
	}
	else
	{
	gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
	}

top_table = gtk_table_new (1, 256, FALSE);

if(force_toolbars)
	{
	toolhandle=gtk_handle_box_new();
	gtk_widget_show(toolhandle);
	gtk_container_add(GTK_CONTAINER(toolhandle), top_table);
	}

whole_table = gtk_table_new (256, 16, FALSE);

text1 = create_text ();
gtk_table_attach (GTK_TABLE (top_table), text1, 0, 141, 0, 1,
                      	GTK_FILL | GTK_EXPAND,
                      	GTK_FILL | GTK_SHRINK, 0, 0);
gtk_widget_set_usize(GTK_WIDGET(text1), 200, -1);
gtk_widget_show (text1);

dummy1=gtk_label_new("");
gtk_table_attach (GTK_TABLE (top_table), dummy1, 141, 171, 0, 1,
                      	GTK_FILL | GTK_EXPAND,
                      	GTK_SHRINK, 0, 0);
gtk_widget_show (dummy1);

zoombuttons = create_zoom_buttons ();
gtk_table_attach (GTK_TABLE (top_table), zoombuttons, 171, 173, 0, 1,
                      	GTK_FILL | GTK_EXPAND,
                      	GTK_SHRINK, 0, 0);
gtk_widget_show (zoombuttons);

if(!use_scrollbar_only)
	{
	pagebuttons = create_page_buttons ();
	gtk_table_attach (GTK_TABLE (top_table), pagebuttons, 173, 174, 0, 1,
	                      	GTK_FILL | GTK_EXPAND,
	                      	GTK_SHRINK, 0, 0);
	gtk_widget_show (pagebuttons);
	fetchbuttons = create_fetch_buttons ();
	gtk_table_attach (GTK_TABLE (top_table), fetchbuttons, 174, 175, 0, 1,
	                      	GTK_FILL | GTK_EXPAND,
	                      	GTK_SHRINK, 0, 0);
	gtk_widget_show (fetchbuttons);
	discardbuttons = create_discard_buttons ();
	gtk_table_attach (GTK_TABLE (top_table), discardbuttons, 175, 176, 0, 1,
	                      	GTK_FILL | GTK_EXPAND,
	                      	GTK_SHRINK, 0, 0);
	gtk_widget_show (discardbuttons);
	
	shiftbuttons = create_shift_buttons ();
	gtk_table_attach (GTK_TABLE (top_table), shiftbuttons, 176, 177, 0, 1,
	                      	GTK_FILL | GTK_EXPAND,
	                      	GTK_SHRINK, 0, 0);
	gtk_widget_show (shiftbuttons);
	}

dummy2=gtk_label_new("");
gtk_table_attach (GTK_TABLE (top_table), dummy2, 177, 215, 0, 1,
                      	GTK_FILL | GTK_EXPAND,
                      	GTK_SHRINK, 0, 0);
gtk_widget_show (dummy2);

entry = create_entry_box();
gtk_table_attach (GTK_TABLE (top_table), entry, 215, 216, 0, 1,
                      	GTK_SHRINK,
                      	GTK_SHRINK, 0, 0);
gtk_widget_show(entry);

timebox = create_time_box();
gtk_table_attach (GTK_TABLE (top_table), timebox, 216, 256, 0, 1,
                      	GTK_FILL | GTK_EXPAND,
                      	GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
gtk_widget_show (timebox);

wavewindow = create_wavewindow();
load_all_fonts(); /* must be done before create_signalwindow() */
gtk_widget_show(wavewindow);
signalwindow = create_signalwindow();

if(do_resize_signals) 
                {
                int os;
                os=max_signal_name_pixel_width;
                os=(os<30)?30:os;
                gtk_widget_set_usize(GTK_WIDGET(signalwindow),
                                os+30, -1);
                }

gtk_widget_show(signalwindow);

panedwindow=gtk_hpaned_new();

#ifdef HAVE_PANED_PACK
if(paned_pack_semantics)
	{
	gtk_paned_pack1(GTK_PANED(panedwindow), signalwindow, 0, 0); 
	gtk_paned_pack2(GTK_PANED(panedwindow), wavewindow, ~0, 0);
	}
	else
#endif
	{
	gtk_paned_add1(GTK_PANED(panedwindow), signalwindow);
	gtk_paned_add2(GTK_PANED(panedwindow), wavewindow);
	}

gtk_widget_show(panedwindow);

gtk_widget_show(top_table);

gtk_table_attach (GTK_TABLE (whole_table), force_toolbars?toolhandle:top_table, 0, 16, 0, 1,
                      	GTK_FILL | GTK_EXPAND,
                      	GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
gtk_table_attach (GTK_TABLE (whole_table), panedwindow, 0, 16, 1, 256,
                      	GTK_FILL | GTK_EXPAND,
                      	GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
gtk_widget_show(whole_table);
gtk_container_add (GTK_CONTAINER (main_vbox), whole_table);

update_markertime(time_trunc(tims.marker));

if((initial_window_xpos>=0)||(initial_window_ypos>=0))
	{
	if (initial_window_xpos<0) { initial_window_xpos = 0; }
	if (initial_window_ypos<0) { initial_window_ypos = 0; }
#ifdef WAVE_USE_GTK2
	gtk_window_move(GTK_WINDOW(window), initial_window_xpos, initial_window_ypos);
#else
	gtk_window_reposition(GTK_WINDOW(window), initial_window_xpos, initial_window_ypos);
#endif
	}

gtk_main();
    
return(0);
}
