/* This file is part of `mogul'
 * Copyright (c) 1995 David Deaven
 *
 * In the following, "you" and "You" refer to any entity other than 
 * the Microsoft corporation and its subsidiaries.  All rights are
 * reserved by the author in connection with Microsoft and its
 * subsidiaries.  The Microsoft Network is explicity denied the right
 * to copy, reproduce, or transmit this software.
 *
 *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Author: deaven $
 * $Id: filemenu.c,v 2.1 1996/07/11 18:39:57 deaven Exp deaven $
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/SmeLine.h>
#include "FileSelect/FileSelect.h"
#include "CheckBox/CheckBox.h"
#include "dmd/memory.h"
#include "xmogul.h"

enum menu_options {
	mo_open,
	mo_reopen,
	mo_speedy,
	mo_save,
	mo_snapshot,
	mo_clone,
	mo_close,
	mo_quit,
	mo_nothing
};

struct menu_widgets {
	Widget button;	/* The menu button */
	Widget shell;	/* The popup shell */
	Widget w;	/* The active widget, whatever it is */
};

struct FilemenuRec {
	Widget button;	/* File menu heading */
	struct menu_widgets load;
	struct menu_widgets save;
	struct menu_widgets snapshot;
	Widget selectDevice;
	Widget movieSelect;
};

struct box_info {
	MogulPanel mp;
	enum menu_options option;
};

static void load_callback(Widget widget,
  XtPointer client_data, XtPointer call_data)
{
	MogulPanel mp = (MogulPanel) client_data;
	String path = FSCompletePath(mp->filemenu->load.w);

	if(MPLoadFile(mp, path))
	  fprintf(stderr, "cannot open `%s'\n", path);
}

/* Make the shell and widget for the load popup.
 */
static void create_load_popup(MogulPanel mp)
{
	Widget form, button_box, button;
	XtPopdownID id;

        mp->filemenu->load.shell =
	  XtVaCreatePopupShell("LoadPopup", shellWidgetClass, mp->filemenu->button,
	    NULL);

	/* Form to hold it all */

	form =
	  XtVaCreateManagedWidget("form", formWidgetClass, mp->filemenu->load.shell,
	    XtNborderWidth, 0,
	    NULL);

	/* FileSelect widget to get filename */

	mp->filemenu->load.w =
	  XtVaCreateManagedWidget("fileSelect", fileSelectWidgetClass, form,
	    XtNfilename, "",
	    XtNfilter, "*.geo",
	    XtNtop, XawChainTop,
	    XtNbottom, XawChainBottom,
	    XtNleft, XawChainLeft,
	    XtNright, XawChainRight,
	    NULL);
	XtAddCallback(mp->filemenu->load.w, XtNcallback, load_callback, mp);

	/* Button array */

	button_box = 
	  XtVaCreateManagedWidget("buttonBox", boxWidgetClass, form,
	    XtNorientation, XtorientHorizontal,
	    XtNborderWidth, 0,
	    XtNfromVert, mp->filemenu->load.w,
	    XtNtop, XawChainBottom,
	    XtNbottom, XawChainBottom,
	    XtNleft, XawChainLeft,
	    XtNright, XawChainRight,
	    NULL);

	button =
	  XtVaCreateManagedWidget("Open", commandWidgetClass, button_box,
	    NULL);
	XtAddCallback(button, XtNcallback, load_callback, mp);

	/* Button to pop down */

	id = NewPointer(id);
	id->shell_widget = mp->filemenu->load.shell; 
	id->enable_widget = mp->filemenu->load.button;

	button =
	  XtVaCreateManagedWidget("Dismiss", commandWidgetClass, button_box,
	    NULL);
	XtAddCallback(button, XtNcallback, XtCallbackPopdown, id);
}

static int match(char *s, char *begin)
{
	if(strncmp(s, begin, strlen(begin))) return 0;
	return 1;
}

static void set_snapshot_suffix(MogulPanel mp)
{
	int i;
	String curfn;
	char buf[FILENAME_MAX];
	XawListReturnStruct *l = XawListShowCurrent(mp->filemenu->selectDevice);

	XtVaGetValues(mp->filemenu->snapshot.w, XtNfilename, &curfn, NULL);
	if(!curfn) curfn = "";

	strcpy(buf, curfn);
	for(i=strlen(buf); i>=0; i--) {
	  if(buf[i] == '.') {
	    buf[i] = '\0';
	    break;
	  }
	}

	if(match(l->string, "ps")) strcat(buf, ".ps");
	else if(match(l->string, "eps")) strcat(buf, ".eps");
	else if(match(l->string, "ppm")) strcat(buf, ".ppm");
	else if(match(l->string, "jpeg")) strcat(buf, ".jpg");
	else if(match(l->string, "gif")) strcat(buf, ".gif");
	else strcat(buf, ".dat");

	XtVaSetValues(mp->filemenu->snapshot.w, XtNfilename, mystrdup(buf), NULL);
}

static void snapshot_callback(Widget widget,
  XtPointer client_data, XtPointer call_data)
{
	MogulPanel mp = (MogulPanel) client_data;
	String path = FSCompletePath(mp->filemenu->snapshot.w);
	XawListReturnStruct *l = XawListShowCurrent(mp->filemenu->selectDevice);
	MogulDevice d;
	Boolean movie;
	char *deviceName, buf[FILENAME_MAX + 64];

	{ FILE *f;
	  if((f = fopen(path, "r"))) {
	    fclose(f);
	    sprintf(buf, "Overwrite existing file `%s'?", path);
	    if(!MPVerifyDialog(mp->app, mp->frame, buf)) return;
	  }
	}

	XtVaGetValues(mp->filemenu->movieSelect, XtNvalue, &movie, NULL);

	if(movie && !strstr(path, "%f") &&
	   !MPVerifyDialog(mp->app, mp->frame,
	     "Write multiple frames to filename with no `%f' part?"))
	{
	  return;
	}

	deviceName = mystrdup(l->string);
	{ char *s;
	  for(s=deviceName; *s != '\0'; s++)
	    if(*s == ':') *s = '\0';
	}
	sprintf(buf, "file=%s", path);
	d = MogulGetDevice(deviceName, buf);
	if(d == NULL)
	  MogulPerror("getting snapshot device");
	else {
	  if(movie)
	  {
	    int target;
	    for(target = 0; MPSetFrame(mp, target) == target; target++) {
	      if(MogulRender(mp->plot, d))
		MogulPerror("rendering snapshot");
	    }
	  }
	  else
	  {
	    if(MogulRender(mp->plot, d))
	      MogulPerror("rendering snapshot");
	  }
	  MogulFreeDevice(d);
	}
	myfree(deviceName);
}

static void print_callback(Widget widget,
  XtPointer client_data, XtPointer call_data)
{
	MogulPanel mp = (MogulPanel) client_data;
	MogulDevice d;
	char tmpfile[128], buf[256];
	static int serial = 0;

	sprintf(tmpfile, "/tmp/mogul.%d%d.print.ps", getpid(), serial++);
	sprintf(buf, "file=%s", tmpfile);
	d = MogulGetDevice("ps", buf);
	if(d == NULL)
	  MogulPerror("getting print device");
	else {
	  if(MogulRender(mp->plot, d))
	    MogulPerror("rendering print");
	  else {
	    sprintf(buf, "lpr -sr %s", tmpfile); 
	    if(system(buf) < 0) {
	      perror("printing file");
	    }
	  }
	  MogulFreeDevice(d);
	}
}

/* Handle a selection within the scrollable list of snapshot devices.
 */
static void list_callback(Widget widget, XtPointer client_data, XtPointer call_data)
{
	MogulPanel mp = (MogulPanel) client_data;
	set_snapshot_suffix(mp);
}

static void create_snapshot_popup(MogulPanel mp)
{
	Widget form, button_box, movie_box, button;
	XtPopdownID id;

        mp->filemenu->snapshot.shell =
	  XtVaCreatePopupShell("SnapshotPopup", shellWidgetClass, mp->filemenu->button,
	    NULL);

	form =
	  XtVaCreateManagedWidget("form", formWidgetClass, mp->filemenu->snapshot.shell,
	    NULL);

	mp->filemenu->snapshot.w =
	  XtVaCreateManagedWidget("fileSelect", fileSelectWidgetClass, form,
	    XtNtop, XtChainTop,
	    XtNbottom, XtChainBottom,
	    XtNleft, XtChainLeft,
	    XtNright, XtChainRight,
	    XtNresizable, True,
	    NULL);

	movie_box =
	  XtVaCreateManagedWidget("ButtonBox", boxWidgetClass, form,
	    XtNborderWidth, 0,
	    XtNorientation, XtorientHorizontal,
	    XtNfromVert, mp->filemenu->snapshot.w,
	    NULL);

	button = 
	  XtVaCreateManagedWidget("movieLabel", labelWidgetClass, movie_box,
	    XtNlabel, "make movie (render all frames)",
	    XtNborderWidth, 0,
	    NULL);

	{ Dimension h;
	  XtVaGetValues(button, XtNheight, &h, NULL);
	  mp->filemenu->movieSelect =
	    XtVaCreateManagedWidget("movieSelect", checkBoxWidgetClass, movie_box,
	      XtNwidth, h,
	      XtNheight, h,
	      NULL);
	}

	button_box =
	  XtVaCreateManagedWidget("ButtonBox", boxWidgetClass, form,
	    XtNborderWidth, 0,
	    XtNfromVert, movie_box,
	    NULL);

	button =
	  XtVaCreateManagedWidget("Snapshot", commandWidgetClass, button_box,
	    NULL);
	XtAddCallback(button, XtNcallback, snapshot_callback, mp);

	button =
	  XtVaCreateManagedWidget("Print", commandWidgetClass, button_box,
	    NULL);
	XtAddCallback(button, XtNcallback, print_callback, mp);

	id = NewPointer(id);
	id->shell_widget = mp->filemenu->snapshot.shell; 
	id->enable_widget = mp->filemenu->snapshot.button;
	button =
	  XtVaCreateManagedWidget("Dismiss", commandWidgetClass, button_box,
	    NULL);
	XtAddCallback(button, XtNcallback, XtCallbackPopdown, id);

	{ char **devices, **all_devices = MogulListDevices();
	  int n, ndef;

	  for(n=0; all_devices[n]; n++);
	  devices = NewPointerArray(devices, n + 1);
	  for(n=ndef=0; all_devices[n]; n++) {
	    if(strncmp(all_devices[n], "x11", 3)) devices[ndef++] = all_devices[n];
	  }
	  devices[ndef++] = NULL;
	  myfree(all_devices);

	  for(ndef=0; devices[ndef + 1] && strncmp(devices[ndef], "ps", 2); ndef++);

	  mp->filemenu->selectDevice =
	    XtVaCreateManagedWidget("list", listWidgetClass, form,
	      XtNdefaultColumns, 1,
	      XtNforceColumns, True,
	      XtNlist, devices,
	      XtNfromVert, movie_box,
	      XtNfromHoriz, button_box,
	      NULL);
	  XtAddCallback(mp->filemenu->selectDevice, XtNcallback, list_callback, mp);
	  XawListHighlight(mp->filemenu->selectDevice, ndef);
	}
}

static void mo_callback(Widget widget,
  XtPointer client_data, XtPointer call_data)
{
	struct box_info *bi = (struct box_info *) client_data;
	static int num_panels = 0;

	switch(bi->option) {


	  case mo_open:
	    XtSetSensitive(bi->mp->filemenu->load.button, False);

	    XtVaSetValues(bi->mp->filemenu->load.w,
	      XtNfilename, MPCurrentFile(bi->mp), NULL);

	    XtPopup(bi->mp->filemenu->load.shell, XtGrabNone);
	    XStoreName(XtDisplay(bi->mp->filemenu->load.shell),
		       XtWindow(bi->mp->filemenu->load.shell), "xmogul load");
	    break;


	  case mo_reopen:
	    MPReopenFile(bi->mp);
	    break;


	  case mo_save:
	    {
	      String fn;
	      FILE *f;

	      fn = MPGetFilenameDialog(bi->mp->app, bi->mp->frame, "Save", "mogul.geo", "*.geo");
	      if(fn) {
		f = fopen(fn, "r");
		if(f) {
		  char buf[FILENAME_MAX];
		  fclose(f);
		  sprintf(buf, "Overwrite existing `%s'?", fn);
		  if(!MPVerifyDialog(bi->mp->app, bi->mp->frame, buf)) break;
		}

		f = fopen(fn, "w");
		if(f == NULL)
		  fprintf(stderr, "Cannot open \"%s\"\n", fn);
		else {
		  MPWriteTransformed(bi->mp, f);
		  fclose(f);
		  fprintf(stderr, "wrote transformed geometry to `%s'\n", fn);
		}
	      }
	    }
	    break;


	  case mo_snapshot:
	    { String curfn;
	      XtSetSensitive(bi->mp->filemenu->snapshot.button, False);
	      XtVaGetValues(bi->mp->filemenu->snapshot.w, XtNfilename, &curfn, NULL);
	      if(strlen(curfn) < 1)
		XtVaSetValues(bi->mp->filemenu->snapshot.w,
		  XtNfilename, MPCurrentFile(bi->mp), NULL);
	      set_snapshot_suffix(bi->mp);
	      XtPopup(bi->mp->filemenu->snapshot.shell, XtGrabNone);
	      XStoreName(XtDisplay(bi->mp->filemenu->snapshot.shell),
			 XtWindow(bi->mp->filemenu->snapshot.shell), "xmogul snapshot");
	    }
	    break;


	  case mo_clone:
	    {
	      MogulPanel new_mp;
	      Widget new_toplevel = XtVaAppCreateShell(NULL, APPCLASS,
		applicationShellWidgetClass, XtDisplay(bi->mp->frame), NULL);
	      new_mp = MPCreatePanel(bi->mp->app, new_toplevel);
	      XtRealizeWidget(new_mp->toplevel);
	      MPSetProgram(new_mp, MPGetProgram(bi->mp));
	      MPLoadFile(new_mp, MPCurrentFile(bi->mp));
	      num_panels++;
	    }
	    break;


	  case mo_close:
	    MPDeletePanel(bi->mp);
	    num_panels--;
	    if(num_panels < 0) exit(0);
	    break;


	  case mo_quit:
	    exit(0);
	    break;


	  default:
	  case mo_nothing:
	    break;
	}
}

static Widget menu_entry(String name, WidgetClass class,
	Widget shell, MogulPanel mp, enum menu_options option)
{
	Widget w;
	Arg args[10];
	Cardinal n;
	struct box_info *bi;

	n = 0;
	w = XtCreateManagedWidget(name, class, shell, args, n);

	if(option != mo_nothing) {
	  bi = mymalloc(sizeof(*bi));
	  bi->mp = mp;
	  bi->option = option;
	  XtAddCallback(w, XtNcallback, mo_callback, bi);
	}

	return w;
}

void MPCreateFileMenu(Widget parent, MogulPanel mp)
{
	Widget shell;
	Arg args[10];
	Cardinal n;

	mp->filemenu = mymalloc(sizeof(*(mp->filemenu)));

	n = 0;
	XtSetArg(args[n], XtNmenuName, "FileMenu"); ++n;
	mp->filemenu->button =
	  XtCreateManagedWidget("File", menuButtonWidgetClass,
	  parent, args, n);

	n = 0;
        shell = XtCreatePopupShell("FileMenu", simpleMenuWidgetClass,
	  mp->filemenu->button, args, n);

	mp->filemenu->load.button = 
	  menu_entry("Open", smeBSBObjectClass, shell, mp, mo_open);
	create_load_popup(mp);

	menu_entry("Reopen", smeBSBObjectClass, shell, mp, mo_reopen);

	menu_entry("Save", smeBSBObjectClass, shell, mp, mo_save);

	menu_entry("line1", smeLineObjectClass, shell, mp, mo_nothing);

	menu_entry("Clone", smeBSBObjectClass, shell, mp, mo_clone);

	menu_entry("line2", smeLineObjectClass, shell, mp, mo_nothing);

	mp->filemenu->snapshot.button = 
	  menu_entry("Snapshot", smeBSBObjectClass, shell, mp, mo_snapshot);
	create_snapshot_popup(mp);

	menu_entry("line3", smeLineObjectClass, shell, mp, mo_nothing);

	menu_entry("Close", smeBSBObjectClass, shell, mp, mo_close);

	menu_entry("Quit", smeBSBObjectClass, shell, mp, mo_quit);
}

