/****************************************************************
 ***                                                          ***
 ***    tbrowser.c                                            ***
 ***          A file browser                                  ***
 ***                                                          ***
 ***************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>

#include "EZ.h"

static EZ_Widget *fsframe;         /* the master frame */
static EZ_Widget *fslistbox;       /* the file lister  */
static EZ_Widget *fsbrowser;       /* the browser      */

static EZ_TextProperty *isdir = NULL;
static EZ_TextProperty *bitdir = NULL, *bitascii = NULL;
static EZ_TextProperty *icon1 = NULL, *icon2 = NULL, *icon3 = NULL;

static char *fonts[] = {
  "-*-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*",
  "-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*",
  "-Adobe-Helvetica-Bold-R-Normal--*-120-*-*-*-*-*-*",
  "-Adobe-Times-Bold-I-Normal--*-120-*-*-*-*-*-*",
  "-Adobe-Helvetica-Medium-R-Normal--*-180-*-*-*-*-*-*",
  "-*-Courier-Medium-R-Normal--*-180-*-*-*-*-*-*",
  "-Adobe-Helvetica-Bold-R-Normal--*-180-*-*-*-*-*-*",
  "-Adobe-Times-Bold-I-Normal--*-180-*-*-*-*-*-*",
  "-Adobe-Helvetica-Medium-R-Normal--*-240-*-*-*-*-*-*",
  "-*-Courier-Medium-R-Normal--*-240-*-*-*-*-*-*",
  "-Adobe-Helvetica-Bold-R-Normal--*-240-*-*-*-*-*-*",
  "-Adobe-Times-Bold-I-Normal--*-240-*-*-*-*-*-*",
};
#define NFONTS 12
#define DIR_FONT  fonts[7]
#define ASCII_FONT    fonts[1]
#define BINARY_FONT  fonts[2]

/*************************************************************************/
static char cur_dir[512];          /* holds current directory        */
static char *workingdir;
static void fslistbox_callback();  /* file lister call back          */
static void set_fslistboxitems();  /* update the list in file lister */
static int  selectall();           /* needed in scandir              */

extern int  alphasort();
extern void exit();
/*************************************************************************/
static char *colors[] = {
  "red",
  "green",
  "blue",
  "yellow",
  "cyan",
  "magenta",
  "white",
  "grey62",
  "bisque",
  "yellowgreen",
};
#define REDC         0
#define GREENC       1
#define BLUEC        2
#define YELLOWC      3
#define CYANC        4
#define MAGENTAC     5
#define WHITEC       6
#define GRAYC        7
#define BISQUEC      8
#define YELLOWGREENC 9
/*************************************************************************/
static void colorMCallback(menu)         /* set the foreground of browser */
     EZ_Widget *menu;
{
  int i = EZ_GetWidgetReturnData(menu);
  if( i >= REDC && i <= YELLOWGREENC)
    EZ_ConfigureWidget(fsbrowser, EZ_FOREGROUND, colors[i], 0);
}

static void fontMCallback(menu)          /* set the font of label        */
     EZ_Widget *menu;
{
  int i = EZ_GetWidgetReturnData(menu);
  if( i >= 0 && i < NFONTS)
    {
      EZ_ConfigureWidget(fsbrowser, EZ_FONT_NAME, fonts[i], 0);
      EZ_ConfigureWidget(fslistbox, EZ_FONT_NAME, fonts[i], 0);      
    }
}
/**************************************************************************/

main(ac, av) int ac; char **av;
{
  EZ_Widget *tmp, *tmpa, *mbar;
  EZ_Widget *colorM, *fontM, *miscM;
  int       i;
  char      str[32];

  /* create menus */
  EZ_Initialize(ac,av,0);
/*  EZ_SetGlobalLabelFont(fonts[7]);
  EZ_SetGlobalEntryTextFont(fonts[6]);
  EZ_SetGlobalMenuTitleFont(fonts[8]); */
  colorM = EZ_CreatePopupMenu("Colors");
  EZ_SetWidgetCallBack(colorM, colorMCallback, NULL);
  for(i = REDC; i <= YELLOWGREENC; i++)
    {
      tmp = EZ_CreateMenuNormalButton(colorM, colors[i], -1 , i);
      sprintf(str, "Ctrl-%c", *colors[i]);
      EZ_ConfigureWidget(tmp, EZ_SHORTCUT_KEY, str,0);
      if(i == WHITEC) (void) EZ_CreateMenuSeparator(colorM);
    }
  fontM = EZ_CreatePopupMenu("Font");
  EZ_SetWidgetCallBack(fontM, fontMCallback, NULL);
  for(i = 0; i < NFONTS; i++)
    {
      tmp = EZ_CreateMenuRadioButton(fontM, fonts[i], -1, 2, i, i);
      EZ_ConfigureWidget(tmp, EZ_TEXT_LINE_LENGTH, 80, 0);
    }
  miscM = EZ_CreatePopupMenu("Misc");
  tmp = EZ_CreateMenuNormalButton(miscM, "Exit", 0, -1);
  EZ_SetWidgetCallBack(tmp, (EZ_CallBack)exit, NULL);


  fsframe = EZ_CreateFrame(NULL,                          /* toplevel widget */
			   NULL
			   );
  EZ_ConfigureWidget(fsframe, EZ_STACKING, EZ_VERTICAL,EZ_PADY, 0,
		     EZ_FILL_MODE, EZ_FILL_BOTH, EZ_WIDTH,300,EZ_HEIGHT,400, 0);
  
  mbar = EZ_CreateFrame(fsframe, NULL);
  EZ_ConfigureWidget(mbar, EZ_PADY, 0, EZ_EXPAND, True, EZ_HEIGHT, 0,
		     EZ_STACKING, EZ_HORIZONTAL_LEFT, EZ_PADX, 0, EZ_PADY, 0,
		     EZ_BORDER_TYPE, EZ_BORDER_UP, EZ_BORDER_WIDTH, 2,0);  
  tmp = EZ_CreateMenuButton(mbar, "Colors", 0);
  EZ_SetMenuButtonMenu(tmp, colorM);
  tmp = EZ_CreateMenuButton(mbar, "Fonts", 0);
  EZ_SetMenuButtonMenu(tmp, fontM);
  tmp = EZ_CreateMenuButton(mbar, "Misc", 0);
  EZ_SetMenuButtonMenu(tmp, miscM);

  tmpa = EZ_CreateFrame(fsframe, NULL);
  EZ_ConfigureWidget(tmpa, 
		     EZ_FILL_MODE, EZ_FILL_BOTH,          /* expand children to fit in exactly  */
		     EZ_IPADX, 10,                        /* h spacing between children widgets */
		     0);

  fslistbox = EZ_CreateTextWidget(tmpa,0,1,1);            /* the file lister */
  EZ_ConfigureWidget(fslistbox, 
		     EZ_CALLBACK, fslistbox_callback, NULL,
		     EZ_WIDTH, 200,0);
  tmp = EZ_CreatePaneHandle(tmpa);
  fsbrowser = EZ_CreateTextWidget(tmpa, 1,1,1);           /* the file browser            */
  /*EZ_ConfigureWidget(fsbrowser,EZ_TEXT_SPACING, 10,0);*/

  EZ_DisplayWidget(fsframe);                              /* display the toplevel widget */ 
  (void)getcwd(cur_dir,512);                              /* start with the current dir  */
  (void)strcat(cur_dir,"/");                              /* append a / for visual purp  */
  workingdir = cur_dir;
  isdir = EZ_GetTextProperty(EZ_FONT_NAME,DIR_FONT,
			     EZ_FOREGROUND, "red",0);
  icon1 = EZ_GetTextProperty(EZ_PIXMAP_FILE, "a1.xpm",0);
  icon2 = EZ_GetTextProperty(EZ_PIXMAP_FILE, "a2.xpm",0);
  icon3 = EZ_GetTextProperty(EZ_PIXMAP_FILE, "a3.xpm",0);
  set_fslistboxitems(cur_dir);                            /* fill in the file lister     */

  EZ_EventMainLoop();                                     /* and enter the event loop    */
}

/************************************************************************
 *
 *  fslistbox callback
 */

static void fslistbox_callback(widget)
     EZ_Widget *widget;
{
  struct stat   fstat;
  int           i,length;
  char          tmpname[512];
  char          tmpnamea[512];

  /*-------------------------------------
   * first, get the corrected path name.
   *------------------------------------*/
  (void) strcpy(tmpname,cur_dir);

  {
    int pos = EZ_TextGetPosition(fslistbox);
    EZ_FreezeWidget(fslistbox);
    EZ_TextBeginningOfLine(fslistbox);
    EZ_TextSetMarker(fslistbox);
    EZ_TextEndOfLine(fslistbox);
    (void) strcpy(tmpnamea, EZ_TextGetRegionString(fslistbox) + 2);
    EZ_TextGotoPosition(fslistbox, pos);
    EZ_UnFreezeWidget(fslistbox);
  }
  
  length = strlen(tmpnamea);

  /*----------------------------------------
   * deal with two special case, ./ and ../
   *--------------------------------------*/
  if(length == 2)
    {
      if(! (tmpnamea[0] == '.'  && tmpnamea[1] == '/'))
	(void)strcat(tmpname, tmpnamea);
    }
  else if(length == 3)
    {
      if(tmpnamea[0] == '.' &&
	 tmpnamea[1] == '.'  &&
	 tmpnamea[2] == '/' )
	{
	  int len = strlen(tmpname);

	  if(len > 1 )
	    {
	      i = len - 2;
	      while( i > 0)
		{
		  if(tmpname[i] == '/') break;
		  i--;
		}
	      if(i > 0) tmpname[i] = '\0';
	      else {tmpname[0] = '/'; tmpname[1] = '\0';}
	    }
	  (void)strcpy(cur_dir, tmpname);
	}
      else
	(void)strcat(tmpname, tmpnamea);
    }
  else
    (void)strcat(tmpname, tmpnamea);
  
  /*------------------------------------
   * check the file type, if its a dir
   * update fslistbox; if its a regular
   * file, send it to the browser.
   *-----------------------------------*/
  stat(tmpname, &fstat);
  if(fstat.st_mode & S_IFDIR)
    {
      workingdir = tmpname;
      set_fslistboxitems(tmpname);
    }
  else if(fstat.st_mode & S_IFREG)
    {
      if(access(tmpname, X_OK) == 0)
	{
	  (void)strcpy(tmpnamea, tmpname);
	  (void)strcat(tmpnamea, " & ");
	  (void) system(tmpnamea);
	}
      else if(access(tmpname, R_OK) == 0)
	EZ_TextLoadFile(fsbrowser, tmpname);
    }
}
/***************************************************************
 *
 *  Update the items in fslistbox.
 *     for directories, append a / to distinguish them from
 *     regular files.
 */
static void set_fslistboxitems(dir)
     char *dir;
{
  struct dirent **namelist;
  struct stat   fstat;
  int           i, length;
  char          tmpname[512];


  stat(workingdir, &fstat);
  if(fstat.st_mode & S_IFDIR)
    {
      length = scandir(workingdir, &namelist, selectall, alphasort);
      if(length < 0)
	{
	  (void)fprintf(stderr, "Cannot open directory %s ",workingdir);
	  return;
	}
      (void)strcpy(cur_dir,workingdir);
      i = strlen(cur_dir);
      if(i == 0 || cur_dir[i-1] != '/') strcat(cur_dir, "/");
      EZ_FreezeWidget(fslistbox); /* block display */

      EZ_TextClear(fslistbox);
      for(i=0; i < length; i++)
	{
	  (void)strcpy(tmpname,cur_dir);
	  (void)strcat(tmpname, namelist[i]->d_name);
	  stat(tmpname,&fstat);
	  if(fstat.st_mode & S_IFDIR) 
	    {
	      (void)strcpy(tmpname, namelist[i]->d_name);
	      (void)strcat(tmpname,"/");
	      EZ_TextBeginningOfLine(fslistbox);
	      EZ_TextInsertStringWithProperty(fslistbox, " ", icon1);
	      EZ_TextInsertStringWithProperty(fslistbox, " ", NULL);	      
	      EZ_TextInsertStringWithProperty(fslistbox, tmpname, isdir);
	      EZ_TextInsertString(fslistbox, "\n");
	    }
	  else
	    {
	      EZ_TextBeginningOfLine(fslistbox);
	      EZ_TextInsertStringWithProperty(fslistbox, " ", icon2);
	      EZ_TextInsertStringWithProperty(fslistbox, " ", NULL);	      
	      EZ_TextInsertStringWithProperty(fslistbox, namelist[i]->d_name, NULL);
	      EZ_TextInsertString(fslistbox, "\n");
	    }
	  free(namelist[i]);
	}
      (void) free(namelist);
      EZ_TextBeginningOfBuffer(fslistbox);
      EZ_UnFreezeWidget(fslistbox); /* unblock display */
    }
}
/**************************************************************************/
static int selectall() { return(1);}
/**************************************************************************/

