/*  filemenu.c

    Copyright (C) 1994	Lambert Klasen & Detlef Steuer
			klasen@asterix.uni-muenster.de
			steuer@amadeus.statistik.uni-dortmund.de

    This file is free source code; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation.

    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
    COPYING for more details.

    The idea of this popup is lifted from xxgdb and adopted for
    xgammon. Especially the functions ScanDir (), Inlist () and changeDir ()
    are almost literally copied.
    And the copied idea is visible in the functions File () CreateFilePopup ()
    DisplayMenuFile ().

 *  xdbx - X Window System interface to the dbx debugger
 *
 *  Copyright 1989 The University of Texas at Austin
 *  Copyright 1990 Microelectronics and Computer Technology Corporation
 *  Copyright 1990 Thomson Consumer Electronics, Inc.

 */




#include <stdio.h>
#include <unistd.h>
/*#include <sys/dir.h>*/
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/Dialog.h>

#include "xgammon.h"
#include "gammon.h"

char   		cwd[MAXPATHLEN];          /* current working directory */
static char	file_listDir[MAXPATHLEN]; /* current directory of file list */
static char  	**filelist;
static int	file_count = 0;	
static Widget	popupshell, popup_pane, file_list, path_label;
static Widget   popup_form, dialog;

extern Widget	button_shell;

extern void	load ();
extern void	save ();

void		File             (); 
void	        CreateSaveDialog (void);
static void	CreateFilePopup  (char *dir);
static void     save_file        ();
static void	changeDir        ();
static int 	InList           ();
static void 	ScanDir          ();
static void 	DisplayMenuFile  ();
static void 	CreateFilePopup  ();
static void     PopdownPopup     ();

/* Change working directory to 'dir'.
   modify static global variable, cwd, to keep track of 
   current working directory */

static void changeDir (char *dir)
{
    char str[512];
    int i,j;

    if (!strcmp (dir, "./")) return;
    
    if (!strcmp (dir, "../")) {
	 for(i=0, j=0; cwd[i]; i++) if (cwd[i] == '/') j++;
	 if( j == 1 ) strcpy (str, "/");
	 else {
	   char *c;
	   c = rindex (cwd, '/');
	   *c = '\0';
	   strcpy (str, cwd);
	 }
    } else {
	if (!strcmp (cwd, "/")) cwd[0] = '\0';
	sprintf (str, "%s/%s", cwd, dir);
	str[strlen (str) - 1]='\0';
    }
    strcpy(cwd, str);
}


/*  Determines if a directory entry should appear in the file list. 
    The files included in the menu are:
      ..  and directories
      files  not having a .c .h .o .dvi suffix */

static int InList (const struct dirent *directory_entry)
{
    char pathname[512];
    struct stat statbuf;
    struct dirent *entry = (struct dirent *) directory_entry;

    if (entry->d_name[0] == '.' && entry->d_name[1] != '.')
	return False;				/* ignore hidden files */
    if (strcmp (cwd, "")) 			/* give full path name */
    	sprintf (pathname, "%s/%s", cwd, entry->d_name);
    else
    	strcpy (pathname, entry->d_name);
    if (stat (pathname, &statbuf) == -1) return False;

    if (statbuf.st_mode & S_IFDIR) {		/* is directory */
	strcat(entry->d_name, "/");
	++(entry->d_reclen);
	return True;
    }
    if      (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".dvi") + 1, ".dvi") == 0) return False;
    else if (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".c") + 1, ".c") == 0) return False;
    else if (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".o") + 1, ".o") == 0) return False;
    else if (strcmp(entry->d_name + strlen(entry->d_name) - sizeof(".h") + 1, ".h") == 0) return False;
    else if (*(entry)->d_name == '.') return False; /* hidden file */
    else {
	++(entry->d_reclen);
	return True;
    }
    return False;
}


/* Scans the working directory for files selected by InList (), sorted
   alphabetically, and stored in an array of pointers to directory
   entries called namelist.
   The names of the selected files are stored in filelist.  */

static void ScanDir (char *dir)
{
    extern int	    alphasort();
    struct dirent   **name;
    int		    i,j;

    file_count = scandir (dir, &name, InList, alphasort);
    if (file_count == -1) {
	fprintf (stderr,"scandir: cannot open %s", dir);
	return;
    }

    if (filelist) {
	for (i=0; filelist[i]; i++) XtFree((char *)filelist[i]);
	XtFree((char *)filelist);
    }
    filelist = (char **) XtMalloc((file_count+1) * sizeof(char *));

    for (j=0; j<file_count; j++) {
      filelist[j] = XtNewString(name[j]->d_name);
      XtFree((char *)name[j]);
    }
    filelist[j] = NULL;

    XtFree((char *)name);
    return;
}
    

/* Callback for the list widget:
   select a directory, display contents
   select a readable file, try load it */

static void DisplayMenuFile (Widget w, Widget popupshell, XawListReturnStruct *call_data)
{
    char *filename, path_and_filename[MAXPATHLEN];

    XtPopdown (popupshell);
    filename = call_data->string;
    if (filename == NULL) return;
    if (filename[ strlen (filename) - 1] == '/') {
	changeDir (filename);
	XtDestroyWidget (popupshell);
	CreateFilePopup (cwd);	/* create new list */
	File ();			/* pop it up */
    } else {
	char *v[2], *flag = "m";
	sprintf(path_and_filename,"%s/%s", cwd, filename);
	v[0] = flag;
	v[1] = path_and_filename;
	load (0L, 0L, v, 0);
    }
}

static void PopdownPopup(Widget w, XtPointer calldata, XtPointer clientdata)
{
    XtPopdown (popupshell);
}


/*  Creates a popup shell with its child being a vpane widget containing
 *  a file menu label, a file menu containing file names returned from 
 *  ScanDir(), and a cancel command button.
 *  When an item in the list is selected, DisplayMenuFile is called.
 */

static void CreateFilePopup(char *dir) 
{
    Widget	toplevel = Player[0].X11Set.toplevel;
    Widget	cancel;
    Arg 	args[1];

    popupshell = XtCreatePopupShell ("Select File", transientShellWidgetClass, toplevel, NULL, 0);

    popup_pane = XtCreateManagedWidget ("popup_pane", panedWidgetClass, popupshell, NULL, 0);

    ScanDir (dir);
    strcpy  (file_listDir, dir);

    path_label = XtCreateManagedWidget (dir, labelWidgetClass, popup_pane, NULL, 0);

    XtSetArg (args[0], XtNlist, filelist);
    file_list = XtCreateManagedWidget ("file_list", listWidgetClass, popup_pane, args, 1);
    XtAddCallback(file_list, XtNcallback, (XtCallbackProc) DisplayMenuFile, popupshell);

    XtSetArg (args[0], XtNresize, False);
    cancel = XtCreateManagedWidget ("cancel", commandWidgetClass, popup_pane, args, 1);
    XtAddCallback(cancel, XtNcallback, PopdownPopup, popupshell);
}

/*  called by MenuSelect (xgammon.c) */

void File(void)
{
    Widget	text_display = Player[0].X11Set.text_display;
    Arg 	args[2];
    Position	x, y, offset;
    Dimension	width, path_width, border_width, text_display_width;
    static int  have_cwd = 0;

    if (!have_cwd) {
	getcwd ((char *) cwd, MAXPATHLEN);
	have_cwd = 1;
    }

    CreateFilePopup (cwd);

    XtSetArg (args[0], XtNwidth, &width);
    XtSetArg (args[1], XtNborderWidth, &border_width);
    XtGetValues (file_list, args, 2);

    XtSetArg (args[0], XtNwidth, &path_width);
    XtGetValues (path_label, args, 1);

    XtSetArg (args[0], XtNwidth, &text_display_width);
    XtGetValues (text_display, args, 1);

    if (path_width > width) width = path_width;
    offset = (Position) (text_display_width - width - border_width);
    XtTranslateCoords (text_display, offset, 0, &x, &y);

    x = (0 > x) ? 0 : x;
    y = (0 > y) ? 0 : y;

    XtSetArg (args[0], XtNx, x);
    XtSetArg (args[1], XtNy, y);	
    XtSetValues (popupshell, args, 2);

    XtPopup (popupshell, XtGrabNonexclusive);
}

void CreateSaveDialog(void)
{
	Widget	toplevel = Player[0].X11Set.toplevel;
	Arg args[3];
	Position x, y;
	
	XtSetArg (args[0], XtNx, &x);
	XtSetArg (args[1], XtNy, &y);	
	XtGetValues (Player[turn-1].X11Set.button_shell, args, 2);
	
	XtSetArg (args[0], XtNx, x+50);		/* pure arbitrary */
	XtSetArg (args[1], XtNy, y+40);	
	
	popupshell = XtCreatePopupShell ("XGammon-Save", transientShellWidgetClass, toplevel, args, 2);
	popup_form = XtCreateManagedWidget ("popup_form", formWidgetClass, popupshell, NULL, 0);
	
	XtSetArg (args[0], XtNlabel, "save as:");
	XtSetArg (args[1], XtNvalue, "");
	dialog = XtCreateManagedWidget ("dialog", dialogWidgetClass, popup_form, args, 2);
	
	XawDialogAddButton(dialog, "save", save_file, (XtPointer) dialog);
	XawDialogAddButton(dialog, "don't", PopdownPopup, NULL);
	
	XtPopup (popupshell, XtGrabExclusive);
}
	
void save_file (Widget w, XtPointer calldata, XtPointer clientdata)
{
	char *v[2], *flag = "m";

	v[0] = flag;
	v[1] = XawDialogGetValueString(dialog);

	XtPopdown (popupshell);

	if (!strlen (v[1])) return;
	else save (0L, 0L, v, 0);
}
