/*********************************************************************
 *
 *            EZFM---EZWGL based file manager for X11
 *
 *             Copyright (C) 1998  Maorong Zou
 *
 *
 *  This file is part of EZFM.
 *
 *  EZFM 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, or (at your option)
 * any later version.
 *
 * EZFM 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 EZFM; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 *************************************************************************/


#define _MAIN_C_
#include "ezfm.h"

void  exitEzfm               MY_ANSIARGS((void *widget, void *data));

/*---------------------------------------------------------------------*/
static void defaultMessageHandler MY_ANSIARGS ((void *msg, void *client_data));
static void checkRemovableDrives  MY_ANSIARGS ((void *timer, void *client_data));
static void processApplicationResources MY_ANSIARGS ((void));
static void globalEventFilter MY_ANSIARGS ((XEvent *event, void *data));
static void usage MY_ANSIARGS ((char *name));
/*----------------------------------------------------------------------
 *        Global Variables
 */
int                ezfmFontId[16];
char               *ezfmRc = NULL;
int                ezfmDebug = 0;
EZ_LabelPixmap     *ezfmDirPixmaps[8];
removableDrive     ezfmDrives[8];
char               ezfmHostname[64];
char               *ezfmMagicFile = NULL;
char               *ezfmSuffixFile = NULL;
char               *ezfmIconPath = NULL;
int                ezfmShowHiddenFiles = 0;
int                ezfmRbtnCounter = 0;
EZ_Widget          *ezfmToolBox = NULL;
EZ_Widget          *ezfmToolBar = NULL;
EZ_Widget          *ezfmDragIcon = NULL;
EZ_Widget          *renameEntry = NULL;
Cursor             ezfmDragCursor;
int                ezfmFlags = AUTO_UPDATE_BIT;
char               ezfmFolderBgPixmap[128];
Pixmap             rootBgPixmap = None;
EZ_LabelPixmap     *bigPixmap = NULL; 
int                transparent = 0;
Display            *theDisplay;        
Window             theRootWindow;      
int                theScreen, theDepth;
Visual             *theVisual;         

/*----------------------------------------------------------------------
 *           command line options
 */
static XrmOptionDescRec ezfmCommandLineOptions[] = {
  {"-rc",         ".ezfmrc",        XrmoptionSepArg,  NULL},
  {"-magic",      ".magic",         XrmoptionSepArg,  NULL},
  {"-extension",  ".extension",     XrmoptionSepArg,  NULL},
  {"-bgImage",    "*bgImageFile",   XrmoptionSepArg,  NULL},
  {"-bgImageB",   "*bgImageFileB",  XrmoptionSepArg,  NULL},
  {"-transparent",".transparent",   XrmoptionNoArg,   "True"},
  {"-version",    ".version",       XrmoptionNoArg,   "True"},
  {"-dir",        ".openDir",       XrmoptionSepArg,  NULL},
};

/*----------------------------------------------------------------------
 *          fallback resource specfication 
 *    Not really needed, but ...
 */
static char *fallbackResources = 
/* initialization file name */
"ezfm*ezfmrc:    ezfmrc:~/.ezfmrc:/etc/ezfmrc:/usr/lib/ezfm/ezfmrc:/usr/local/lib/ezfm/ezfmrc
"
/* fonts used in display items */
"
ezfm*itemMediumFont:      -*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*
ezfm*itemSlantFont:       -*-helvetica-medium-o-*-*-12-*-*-*-*-*-*-*
ezfm*itemBoldFont:        -*-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*
ezfm*itemBoldSlantFont:   -*-helvetica-bold-o-*-*-12-*-*-*-*-*-*-*
"
/* default font for entries/textWidgets (fixed width font)*/
"
ezfm*textFont:            -*-lucidatypewriter-medium-r-*-*-12-*-*-*-*-*-*-*
ezfm*textBoldFont:        -*-lucidatypewriter-bold-r-*-*-14-*-*-*-*-*-*-*
"
/* default font for button labels */
"
ezfm*labelMediumFont:     -adobe-helvetica-medium-r-normal-*-*-120-*-*-*-*-*-*
ezfm*labelBoldFont:       -adobe-helvetica-bold-r-normal-*-*-120-*-*-*-*-*-*
ezfm*labelLargeFont:      -adobe-helvetica-bold-r-normal-*-*-180-*-*-*-*-*-*
ezfm*labelSmallFont:      -*-helvetica-medium-r-*-*-10-*-*-*-*-*-*-*
"
/* background colors */
"
!!!  text background for folders
!*.textBackground: white

!!! background for bubble help
*bubble.background:        yellow

!!!  selection background
*selectionBackground:      yellow

!!!
*HighlightMode:            2
ezfm.backingStore:         1
"
;

static char *openDir = NULL;

/*----------------------------------------------------------------------
 * main
 */
main(int ac, char **av)
{
  int     i;
  Visual  *vis; 
  /* initialize EZWGL */
  EZ_InitializeXrm("Ezfm",                                 /* class name            */
		   ezfmCommandLineOptions,                 /* cmd line options      */
		   EZ_ArraySize(ezfmCommandLineOptions),   /* # of cmd line options */
		   &ac,                                    /* arg count, in and out */
		   av,                                     /* cmd args, in and out  */
		   fallbackResources,                      /* fallback resources    */
		   0);                                     /* useless junk          */

  /* define ATOMS for DnD and the sort */
  initAtoms();

  EZ_GetDisplayInfo( &theDisplay, &theScreen, &theVisual, &theDepth);
  theRootWindow = RootWindow(theDisplay, theScreen);

  EZ_SetGlobalBackground("gray86");
  EZ_SetGlobalEventFilter(globalEventFilter, NULL);

  /* if there are unparsed command line options left, barf and exit */
  if(ac > 1) 
    {
      fprintf(stderr, "\nUsage: %s \n", av[0]);
      fprintf(stderr, "\t-rc           init_file\n");
      fprintf(stderr, "\t-bgImage      bg_tile_image\n");
      fprintf(stderr, "\t-bgImageB     bg_tile_image_secondary\n");
      fprintf(stderr, "\t-dir          directory_name \n");
      fprintf(stderr, "\t-transparent \n");
      fprintf(stderr, "\t-version \n");
      fprintf(stderr, "\t-help \n");
      EZ_PrintStandardOptions();
      EZ_Shutdown();
      exit(0);
    }
  {
    char *value;
    if(EZ_GetApplicationResource("version", &value)) 
      {
        if(strcmp(value, "True") == 0)
          {
            fprintf(stderr, "%s\n", EZFMVERSIONSTRING);
            EZ_Shutdown();
            exit(0);
          }
      }
  }
  /* labelFont is controled by the *.labelFont resource */

  /* EZ_SetDefaultLabelFont("-Adobe-Helvetica-Medium-R-Normal--*-120-*-*-*-*-*-*");*/

  EZ_Btn2 = Button3;
  EZ_Btn3 = Button2;

  /* process application resources and resources related to global attributes */
  EZ_SetKbdHighlightColor("red");
  EZ_SetDefaultAttributesFromResources();
  processApplicationResources();

  EZ_GlobHiddenFiles(0);
  gethostname(ezfmHostname, 127);

  /* handle DELETE_WINDOW clientMessage event    */
  EZ_SetClientMessageHandler(clientMessageHandler,   NULL);
  /* handle communication between folders or other instances of ezfm */
  EZ_SetDefaultMessageHandler(defaultMessageHandler, NULL);
  /* the default line length for BubbleHelp is too short */
  EZ_ConfigureWidget(EZ_GetBubbleHelp(), EZ_TEXT_LINE_LENGTH, 80, NULL);

  /* readin the root background pixmap and save it. Register
   * an event handler to handle future root bg changes 
   */
  ezfmReadStateA(); /* it is unfortunate we have to read the state file twice */
  setupTransparencyDialogue(transparent);

  /* initialize removable drives, need to do this before reading the rcfile */
  for(i = 0; i < 8; i++)
    {
      ezfmDrives[i].status = -1; 
      ezfmDrives[i].blocked = 0;
      ezfmDrives[i].finfo = NULL;
      ezfmDrives[i].name = NULL;
      ezfmDrives[i].mntPt = NULL;
    } 
  ProcessRCFile(ezfmRc, NULL); 
  atexit(exitHandler);

  {
    char *value;
    if(EZ_GetApplicationResource("magic", &value)) 
      {
	int len = strlen(value);
	if(ezfmMagicFile) EZ_Free(ezfmMagicFile);
	ezfmMagicFile = (char *)EZ_Malloc((len+1)*sizeof(char));
	strcpy(ezfmMagicFile, value);
      }
    if(EZ_GetApplicationResource("extension", &value)) 
      {
	int len = strlen(value);
	if(ezfmSuffixFile) EZ_Free(ezfmSuffixFile);
	ezfmSuffixFile = (char *)EZ_Malloc((len+1)*sizeof(char));
	strcpy(ezfmSuffixFile, value);
      }
    if(EZ_GetApplicationResource("openDir", &value)) 
      openDir = value;
  }
  ProcessMagicFile(ezfmMagicFile); 
  ProcessSuffixFile(ezfmSuffixFile);   

#ifdef REMOVABLE_DRIVES
  /* removable drives again, finish initialization */
  { 
    char *tspec = GetFileTypeInfo("/");
    for(i = 0; i < 8 && ezfmDrives[i].status >= 0; i++)
      ezfmDrives[i].finfo->ezfmData = tspec;
    /* create a timer to check the status of the removable drives */
    EZ_CreateTimer(5, 0, -1, checkRemovableDrives, NULL, 0);
  }
#endif
  /* save state every 60 seconds */
  EZ_CreateTimer(60, 0, -1, ezfmSaveState, NULL, 0);

  /*
   * kluge: 
   * special pixmaps. Used for signaling opened/closed directory items/icons 
   */
  {
    char *ptr, *tspec = GetFileTypeInfo("/");
    char lxpmFile[64], sxpmFile[64], pixmap_file[64];   
    getSpecPixmap(tspec, lxpmFile, sxpmFile);
    if(lxpmFile[0] && sxpmFile[0])
      {
	ezfmDirPixmaps[0] = EZ_CreateLabelPixmapFromXpmFile(lxpmFile);
	ezfmDirPixmaps[2] = EZ_CreateLabelPixmapFromXpmFile(sxpmFile);
	strcpy(pixmap_file, lxpmFile);
	ptr = strrchr(pixmap_file,'.'); 
	if(ptr) strcpy(ptr, "Open.xpm"); 
	ezfmDirPixmaps[1] = EZ_CreateLabelPixmapFromXpmFile(pixmap_file);
	strcpy(pixmap_file, sxpmFile);
	ptr = strrchr(pixmap_file,'.'); 
	if(ptr) strcpy(ptr, "Open.xpm"); 
	ezfmDirPixmaps[3] = EZ_CreateLabelPixmapFromXpmFile(pixmap_file);	
	strcpy(pixmap_file, lxpmFile);
	ptr = strrchr(pixmap_file,'.'); 
	if(ptr) strcpy(ptr, "Parent.xpm"); 
	ezfmDirPixmaps[4] = EZ_CreateLabelPixmapFromXpmFile(pixmap_file);
	strcpy(pixmap_file, sxpmFile);
	ptr = strrchr(pixmap_file,'.'); 
	if(ptr) strcpy(ptr, "Parent.xpm"); 
	ezfmDirPixmaps[5] = EZ_CreateLabelPixmapFromXpmFile(pixmap_file);		
      }
    for(i = 0; i < 6; i++)
      if(ezfmDirPixmaps[i] == NULL) {ezfmDirPixmaps[0] = NULL; break;}
  } 
  /* make a drag icon */
  ezfmDragIcon =  EZ_CreateWidgetXrm(EZ_WIDGET_ICON, NULL,
				     "DragIcon", "dragIcon",
				     NULL);
  EZ_ConfigureWidget(ezfmDragIcon, 
		     EZ_BACKGROUND,    "gray30",
		     EZ_FOREGROUND,    "white",
		     EZ_ORIENTATION, EZ_VERTICAL,
		     EZ_BORDER_WIDTH, 0,
		     EZ_SHAPED_WINDOW, True,
		     EZ_LABELED_ICON,  1,
		     EZ_PADX, 0, EZ_PADY,0,
		     0);

  ezfmDragCursor = EZ_GetCursor(XC_hand2);
  /* setup a signal handler to watch for child processes */
  handleSigChild();
  handleOtherSig();  

  /* read in saved state */
  if(openDir == NULL) ezfmReadState();
  
  /* if there are no opend folders, open the current directory */
  if(countNFolders() == 0)
    {
      char *dir = openDir, buf[256];
      if(dir == NULL) dir = getcwd(buf, 256);
      OpenFolder(dir, NULL, 1, 0);
    }
  EZ_EventMainLoop();
}

/*----------------------------------------------------------------------------------
 *  Default message handler.
 */
static void defaultMessageHandler(msgIn, cdata)
     void *msgIn; void *cdata;
{
  EZ_Message *msg = (EZ_Message *)msgIn;
  if(msg->messageLength > 0)
    {
      if(msg->messageType == ezfmMsgFolderInqueryAtom)
	{
	  /* this message is sent by another ezfm who wants to know
	   * if this client has a folder open for the specified
	   * directory. Answer it only if it has.
	   */
	  if(msg->replyId &&  msg->senderIsSelf == 0)
	    {
	      /* someone is asking whether I have opened 'path' */
	      char     *message = msg->message;
	      char     *path = message+PATHNAME_OFFSET;
	      if(canSeeTheFile(path, message)) /* it is a local file */
		{
		  Folder *folder = findFolder(path);
		  if(folder != NULL) /* reply the message */
		    {
		      EZ_Widget *widget = NULL;
		      char      str[1024];
		      int       length;
		      if(folder->type == ICON_FOLDER)       widget = folder->workarea;
		      else if(folder->type == LIST_FOLDER)  widget = folder->flistbox;
		      else if(folder->type == TREE_FOLDER)  widget = folder->listtree;
                      else if(folder->type == ICON_FOLDER_SMALL) widget = folder->workareaS;
		      if(EZ_WidgetIsViewable(widget))
			{
			  int       x, y, w, h;
			  Window    window = EZ_GetWidgetWindow(widget);
			  EZ_GetWidgetAbsoluteGeometry(widget,&x,&y, &w, &h);
			  sprintf(str,"WindowId %lx, geom=[%dx%d+%d+%d], viewable",window,w,h,x,y);
			}
		      else
			{
			  Window    window = EZ_GetWidgetWindow(widget);
			  sprintf(str,"WindowId %lx, not currently viewable",window);
			}
		      length = strlen(str) + 1;
		      strcpy(str + length, path);
		      EZ_ReplyMessage(msg, str, length + strlen(path)+1); /* include the NULL byte!! */
		    }
		}
	    }
	}
      else if(msg->messageType == ezfmMsgFolderOpenedAtom)
	{
	  char *message, *path;

	  if(ezfmDirPixmaps[0] == NULL) return;
	  message = msg->message;
	  path = message+PATHNAME_OFFSET;
	  if(canSeeTheFile(path, message)) /* it is a local file */
	    {
	      OpenCloseDirItemInFolder(path, 1);
	      OpenCloseIcon(path, 1);
	    }
	}
      else  if(msg->messageType == ezfmMsgFolderClosedAtom)
	{
	  char *message, *path;

	  if(ezfmDirPixmaps[0] == NULL) return;
	  message = msg->message;
	  path = message+PATHNAME_OFFSET;
	  if(canSeeTheFile(path, message)) /* it is a local file */
	    {
	      OpenCloseDirItemInFolder(path, 0);
	      OpenCloseIcon(path, 0);
	    }
	}
#ifdef REMOVABLE_DRIVES
      else  if(msg->messageType == ezfmMsgMountTbChangeAtom)
	{
	  char *message = msg->message;
	  char *host = message + 128;
	  if(!strcmp(host, ezfmHostname))
	    ezfmUpdateMountTable1(message+1);
	}
#endif
    }
}

/*----------------------------------------------------------------------------------
 * 
 *  exit and save current layout to rc files.
 */
void   exitEzfm(widget, data)
     EZ_Widget *widget; void *data;
{
  /* later */
  ezfmSaveState(NULL, NULL);
  EZ_Shutdown();
  exit(0);
}

/*----------------------------------------------------------------------------------
 * 
 *   update the status of removable drives.
 */
#ifdef REMOVABLE_DRIVES
static void checkRemovableDrives(timer, data)
     void *timer; void *data;
{
  ezfmUpdateMountTable();
}
#endif
/*----------------------------------------------------------------------------------
 * use application resources. This is a ugly ..., but there is no other way 
 */
static void processApplicationResources()
{
  char *value;
  if(EZ_GetApplicationResource("ezfmrc", &value)) 
    ezfmRc = value;

  if(EZ_GetApplicationResource("debug", &value)) 
    ezfmDebug = (strcmp(value, "True") == 0);
    
  if(EZ_GetApplicationResource("itemMediumFont", &value)) 
    ezfmFontId[ITEM_MEDIUM_FONT] = EZ_LoadXFont(value);
  if(EZ_GetApplicationResource("itemSlantFont", &value)) 
    ezfmFontId[ITEM_SLANT_FONT] = EZ_LoadXFont(value);
  if(EZ_GetApplicationResource("itemBoldFont", &value)) 
    ezfmFontId[ITEM_BOLD_FONT] = EZ_LoadXFont(value);
  if(EZ_GetApplicationResource("itemBoldSlantFont", &value)) 
    ezfmFontId[ITEM_BOLD_SLANT_FONT] = EZ_LoadXFont(value);
  if(EZ_GetApplicationResource("labelMediumFont", &value)) 
    ezfmFontId[LABEL_MEDIUM_FONT] = EZ_LoadXFont(value);
  if(EZ_GetApplicationResource("labelBoldFont", &value)) 
    ezfmFontId[LABEL_BOLD_FONT] = EZ_LoadXFont(value);
  if(EZ_GetApplicationResource("labelLargeFont", &value)) 
    ezfmFontId[LABEL_LARGE_FONT] = EZ_LoadXFont(value);
  if(EZ_GetApplicationResource("labelSmallFont", &value)) 
    ezfmFontId[LABEL_SMALL_FONT] = EZ_LoadXFont(value);
  if(EZ_GetApplicationResource("textFont", &value)) 
    ezfmFontId[TEXT_FONT] = EZ_LoadXFont(value);
  if(EZ_GetApplicationResource("textBoldFont", &value)) 
    ezfmFontId[TEXT_BOLD_FONT] = EZ_LoadXFont(value);
  if(EZ_GetApplicationResource("transparent", &value)) 
    transparent = (strcmp(value, "True") == 0);
}
/*----------------------------------------------------------------------------------*/
static void globalEventFilter(event, data)
     XEvent *event; void *data;
{
  if(EZ_WidgetIsViewable(renameEntry))
    {
      Window window = event->xany.window;
      EZ_Widget *widget = (EZ_Widget *)EZ_LookupWidgetFromMappedHT(window);
      if(widget != renameEntry)
        {
          if(event->type == ButtonPress || event->type == KeyPress ||
             event->type == ConfigureNotify )
            EZ_HideWidget(renameEntry);
        }
    }
      
}

/*----------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------*/
#undef _MAIN_C_
