/*****************************************************************************
 * asprint.c
 * version 0.5
 * file selection dialog that enables a user to traverse a directory tree
 * select a file and spool it to the printer.
 ****************************************************************************/

#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Viewport.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>

#define DIRS_LIST 0
#define FILES_LIST 1
#define PRINT_PB 0
#define CANCEL_PB 1
#define FILTER_PB 2

String **files_list, **dirs_list;
Widget dir_lw, files_lw, filter_tw, select_tw, list_view, lv2, main_form;
XFontStruct *the_Font;

int num_dirs = 0, num_files = 0;
char curdir[PATH_MAX+3];

/*  Load the directories list widget */
void load_dirs_list(void)
{
     char *tmp_elem;
     int i, new_size, name_len, ret;
     struct stat stbuf;
     struct dirent *dirbuf;
     DIR *dir;
     char *retbuf;
     
	 /* free the current list */
     if (dirs_list) {
          i = 0;
          while(dirs_list[i]) {
               free(dirs_list[i++]);
          }
          free(dirs_list);
     }

	 /* get the current working directory and reset the 
		filter text widget */
     retbuf = getwd(curdir);
     if (filter_tw != (Widget)NULL) {
          XtVaSetValues(filter_tw,
                        XtNstring, curdir,
                        NULL);
     }

	 /* create the list */
     dir = opendir(".");
     dirs_list = (String **)calloc(1, sizeof(char *));
     i = 0;
     while((dirbuf = readdir(dir)) != NULL) {
          if (dirbuf->d_ino == 0) {
               continue;
          } else {
               lstat(dirbuf->d_name, &stbuf);
               if (S_ISDIR(stbuf.st_mode)) {
                    name_len = strlen(dirbuf->d_name);
                    tmp_elem = (char *)calloc(name_len+1, sizeof(char));
                    strncpy(tmp_elem, dirbuf->d_name, name_len);
                    tmp_elem[name_len] = '\0';
                    dirs_list[i] = (String *)tmp_elem;
                    new_size = (++i)*sizeof(char *) + sizeof(char *);
                    dirs_list = (String **)realloc(dirs_list, new_size);
               }
          }
     }
     dirs_list[i] = '\0';
     num_dirs = i;
     closedir(dir);
}

/* Loads the files list widget */
void load_files_list(void)
{
     char *tmp_elem;
     int i, new_size, name_len, ret;
     struct stat stbuf;
     struct dirent *dirbuf;
     DIR *dir;

	 /* free the current list */
     if (files_list) {
          i = 0;
          while(files_list[i]) {
               free(files_list[i++]);
          }
          free(files_list);
     }

	 /* fill the list in */
     dir = opendir(".");
     files_list = (String **)calloc(1, sizeof(char *));
     i = 0;
     while((dirbuf = readdir(dir)) != NULL) {
          if (dirbuf->d_ino == 0) {
               continue;
          } else {
               lstat(dirbuf->d_name, &stbuf);
               if (!S_ISDIR(stbuf.st_mode)) {
                    name_len = strlen(dirbuf->d_name);
                    tmp_elem = (char *)calloc(name_len+1, sizeof(char));
                    strncpy(tmp_elem, dirbuf->d_name, name_len);
                    tmp_elem[name_len] = '\0';
                    files_list[i] = (String *)tmp_elem;
                    new_size = (++i)*sizeof(char *) + sizeof(char *);
                    files_list = (String **)realloc(files_list, new_size);
               }
          }
     }
     files_list[i] = '\0';
     num_files = i;
     closedir(dir);
     if (select_tw != (Widget)NULL)
          XtVaSetValues(select_tw, XtNstring, " ", NULL);
}

/* List widget callback */
void list_cb(Widget w, XtPointer client_data, XtPointer call_data)
{
     int which_list = (int)client_data;
     int longest;
     XawListReturnStruct *item = 
          (XawListReturnStruct *)call_data;

     switch(which_list) {
     case DIRS_LIST:
		  /* change directory to one selected */
          chdir(item->string);
		  /* reload the lists */
          load_dirs_list();
          load_files_list();
          XawListChange(dir_lw, (String *)dirs_list, 0, 0, False);
          XawListChange(files_lw, (String *)files_list, 0, 0, False);
		  /* try to resize the dialog */
          XtVaGetValues(dir_lw,
                        XtNlongest, &longest,
                        NULL);
          XtVaSetValues(list_view,
                        XtNwidth, longest+30,
                        NULL);
          XtVaGetValues(files_lw,
                        XtNlongest, &longest,
                        NULL);
          XtVaSetValues(lv2,
                        XtNwidth, longest+30,
                        NULL);

          break;
     case FILES_LIST:
		  /* set the selection text widget with item selected */
          XtVaSetValues(select_tw, XtNstring, item->string, NULL);
          break;
     }
	 XawFormDoLayout(main_form, True);
}

/* push buttons callback */
void button_cb(Widget w, XtPointer client_data, XtPointer call_data)
{
     int the_button = (int)client_data, i;
     char *buf;
     int len = 0;
     XawListReturnStruct *item;

     switch (the_button) {
     case PRINT_PB:
          /* Ok, print the file */
          item = XawListShowCurrent(files_lw);
          if (item->list_index > -1) {
               len = strlen(item->string) + strlen(curdir)+6;
               buf = (char *)calloc(len, sizeof(char));
               if (buf != (char *)NULL) {
                    strcpy(buf, "lpr ");
                    strcat(buf, curdir);
                    strcat(buf, "/");
                    strcat(buf, item->string);
                    system(buf); 
                    free(buf);
               }
          }
          break;
     case CANCEL_PB:
          /* Cancel, free list memory and exit */
          if (dirs_list) {
               i = 0;
               while(dirs_list[i]) {
                    free(dirs_list[i++]);
               }
               free(dirs_list);
          }
          if (files_list) {
               i = 0;
               while(files_list[i]) {
                    free(files_list[i++]);
               }
               free(files_list);
          }
          exit(0);
          break;
     case FILTER_PB:
          /* Filter, reparse directory according to filter */
          load_dirs_list();
          XawListChange(dir_lw, (String *)dirs_list, 0, 0, True);
          break;
     }
}


int
main(int argc, char *argv[])
{
     XtAppContext app_context;
     Widget toplevel, button_form;
     Widget ok_pb, w;
     int longest;
     Dimension width;
     char *retbuf;

     toplevel = XtVaAppInitialize(&app_context,
                                   "Xexample1", NULL, 0,
                                   &argc, argv, NULL,
                                   NULL);
     load_files_list();
     load_dirs_list();
     main_form = XtVaCreateManagedWidget("mainform", 
                                         formWidgetClass, toplevel,
										 XtNresizable, True,
                                         NULL);
     w = XtVaCreateManagedWidget("w",
                                 labelWidgetClass, main_form,
                                 XtNlabel, "Filter:",
                                 XtNleft, XawChainLeft,
                                 XtNright, XawChainLeft,
                                 XtNtop, XawChainTop,
                                 XtNbottom, XawChainTop,
                                 NULL);
     filter_tw = XtVaCreateManagedWidget("filter_tw",
                                         asciiTextWidgetClass, main_form,
                                         XtNfromVert, w,
                                         XtNleft, XawChainLeft,
/*                                         XtNright, XawChainRight, */
                                         XtNtop, XawChainTop,
                                         XtNbottom, XawChainTop,
                                         XtNeditType, XawtextRead,
										 XtNresize, XawtextResizeWidth,
                                         NULL);

     list_view = XtVaCreateManagedWidget("listview", 
                                         viewportWidgetClass, main_form,
                                         XtNborderWidth, 0,
                                         XtNforceBars, True,
                                         XtNallowVert, True,
                                         XtNuseRight, True,
                                         XtNleft, XawChainLeft,
                                         XtNbottom, XawChainBottom,
                                         XtNtop, XawChainTop,
										 XtNhorizDistance, 5,
										 XtNvertDistance, 5,
/*                                         XtNright, XawRubber, */
                                         XtNfromVert, filter_tw,
                                         NULL);

     dir_lw = XtVaCreateManagedWidget("listw", 
									  listWidgetClass, list_view,
									  XtNdefaultColumns, 1,
									  XtNheight, 200,
									  XtNforceColumns, True,
									  XtNborderWidth, 1,
									  XtNlist, dirs_list,
									  NULL);
     XtAddCallback(dir_lw, XtNcallback, list_cb, (XtPointer)DIRS_LIST);
     XtVaGetValues(dir_lw,
                   XtNlongest, &longest,
                   NULL);
     XtVaSetValues(list_view,
                   XtNwidth, longest+30,
                   NULL);
     lv2 = XtVaCreateManagedWidget("listview", 
                                   viewportWidgetClass, main_form, 
                                   XtNborderWidth, 0,
                                   XtNforceBars, True,
                                   XtNallowVert, True,
                                   XtNuseRight, True,
                                   XtNright, XawChainRight,
                                   XtNbottom, XawChainBottom,
                                   XtNtop, XawChainTop,
/*                                   XtNleft, XawRubber, */
								   XtNhorizDistance, 5,
								   XtNvertDistance, 5,
                                   XtNfromVert, filter_tw,
                                   XtNfromHoriz, list_view,
                                   NULL);

     files_lw = XtVaCreateManagedWidget("listw", 
                                 listWidgetClass, lv2,
                                 XtNdefaultColumns, 1,
                                 XtNheight, 200,
                                 XtNforceColumns, True,
                                 XtNborderWidth, 1,
                                 XtNlist, files_list,
                                 NULL);
     XtAddCallback(files_lw, XtNcallback, list_cb,(XtPointer)FILES_LIST);
     XtVaGetValues(files_lw,
                   XtNlongest, &longest,
                   NULL);
     XtVaSetValues(lv2,
                   XtNwidth, longest+30,
                   NULL);

     w = XtVaCreateManagedWidget("w1",
                                 labelWidgetClass, main_form,
                                 XtNlabel, "Selection:",
                                 XtNfromVert, lv2,
                                 XtNleft, XawChainLeft,
                                 XtNright, XawChainLeft,
                                 XtNtop, XawChainBottom,
                                 XtNbottom, XawChainBottom,
                                 NULL);
     select_tw = XtVaCreateManagedWidget("select_tw",
                                         asciiTextWidgetClass, main_form,
                                         XtNfromVert, w,
                                         XtNleft, XawChainLeft,
                                         XtNright, XawChainRight,
                                         XtNtop, XawChainBottom,
                                         XtNbottom, XawChainBottom,
                                         XtNeditType, XawtextRead,
										 XtNresize, XawtextResizeBoth,
                                         NULL);
     retbuf = getwd(curdir);

     XtVaGetValues(list_view,
                   XtNwidth, &width,
                   NULL);
     XtVaGetValues(lv2,
                   XtNwidth, &longest,
                   NULL);
     XtVaSetValues(filter_tw,
                   XtNwidth, (width+longest+20),
                   XtNstring, curdir,
                   NULL);
     XtVaSetValues(select_tw,
                   XtNwidth, (width+longest+20),
                   NULL);

     button_form = XtVaCreateManagedWidget("buttonform",
                                           formWidgetClass, main_form,
                                           XtNleft, XawChainLeft,
                                           XtNright, XawChainLeft,
                                           XtNbottom, XawChainBottom,
                                           XtNtop, XawChainBottom,
                                           XtNfromVert, select_tw,
                                           NULL);
     ok_pb = XtVaCreateManagedWidget("okpb",
                                     commandWidgetClass, button_form,
                                     XtNleft, XawChainLeft,
                                     XtNbottom, XawChainBottom,
                                     XtNtop, XawChainTop,
                                     XtNlabel, "Print",
                                     NULL);
     XtAddCallback(ok_pb, XtNcallback, button_cb, (XtPointer)PRINT_PB);

     ok_pb = XtVaCreateManagedWidget("cancelpb",
                                     commandWidgetClass, button_form,
                                     XtNleft, XawChainLeft,
                                     XtNbottom, XawChainBottom,
                                     XtNtop, XawChainTop,
                                     XtNlabel, "Cancel",
                                     XtNfromHoriz, ok_pb,
                                     NULL);
     XtAddCallback(ok_pb, XtNcallback, button_cb, (XtPointer)CANCEL_PB);
     ok_pb = XtVaCreateManagedWidget("cancelpb",
                                     commandWidgetClass, button_form,
                                     XtNleft, XawChainLeft,
                                     XtNbottom, XawChainBottom,
                                     XtNtop, XawChainTop,
                                     XtNlabel, "Filter",
                                     XtNfromHoriz, ok_pb,
                                     NULL);
	 XawFormDoLayout(main_form, False);
     XtAddCallback(ok_pb, XtNcallback, button_cb, (XtPointer)FILTER_PB);
     XtRealizeWidget(toplevel);
	 
     XtAppMainLoop(app_context);
}





