/*********************************************************************
 *
 *            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 _ITEMS_C_
#include "ezfm.h"

EZ_Item   *createFileItem MY_ANSIARGS((char *pathname, char *label, Folder *folder, 
				     EZ_Item **ret_array));
void setupDnDForItem MY_ANSIARGS((EZ_Item *item, FileInfo *finfo, int isDir));
int  ezfmSetDragIconEncoder MY_ANSIARGS((EZ_Item *i, void *v, char **c, int *n, int *t));
/********************************************************/

static void itemDestroyCallback MY_ANSIARGS((EZ_Item *item, void *data));
/********************************************************
 *
 */
EZ_Item *createFileItem(pathname, label, folder, items_ret_array)
     char *pathname; char *label; Folder *folder;
     EZ_Item **items_ret_array;
{
  char         *tspec = GetFileTypeInfo(pathname);
  FileInfo     *finfo;
  char         lxpmFile[64], sxpmFile[64], *pixmap_file;
  char         *clr = "black", color[256];
  EZ_Item      *mainitem;
  struct stat  stat_buf, rstat_buf;
  int          status, type, fontId, isDir, plen, bwidth=0;
  EZ_LabelPixmap *labPixmap;
  
  finfo = (FileInfo *)EZ_Malloc( sizeof(FileInfo));
  memset(finfo, 0, sizeof(FileInfo));
  plen = strlen(pathname);
  finfo->ezfmData = tspec;  /* perm string */
  finfo->pathname = (char *)EZ_Malloc( (1 + plen) * sizeof(char));
  strcpy(finfo->pathname, pathname);
  finfo->type = ITEM;
  finfo->host = folder;
  if(folder) type = folder->type;
  else type = ICON_FOLDER;

  /* find the file stat info */
  status = lstat(pathname, &stat_buf);
  finfo->size = stat_buf.st_size;
  isDir = (status == 0 && S_ISDIR(stat_buf.st_mode));		
  if(S_ISLNK(stat_buf.st_mode))
    {
      if(stat(pathname, &rstat_buf) == 0)
	isDir = S_ISDIR(rstat_buf.st_mode);
    }
  
  finfo->mtime = (status == 0? stat_buf.st_ctime: 0);
  /* extract icon pixmap */
  getSpecPixmap(tspec, lxpmFile, sxpmFile);
  getSpecColor(tspec, color); if(color[0]) clr = color;
  fontId = getSpecFontId(tspec);


  if(type == ICON_FOLDER)
    {
      pixmap_file = lxpmFile;
      labPixmap = EZ_CreateLabelPixmapFromXpmFile(pixmap_file);
      if(!labPixmap) labPixmap = EZ_CreateLabelPixmapFromXpmFile("unknown32.xpm");
    }
  else 
    {
      if(sxpmFile[0])  pixmap_file = sxpmFile;
      else if(isDir) pixmap_file = "dir_s.xpm";
      else pixmap_file = "file.xpm";
      labPixmap = EZ_CreateLabelPixmapFromXpmFile(pixmap_file);
      if(!labPixmap) labPixmap = EZ_CreateLabelPixmapFromXpmFile("unknown16.xpm");
    }
  

  /* if(type == LIST_FOLDER) bwidth = 1;*/
  /* need to process pixmap_file */

  mainitem = EZ_CreateItem(EZ_LABEL_ITEM, 
			   EZ_PADX,              type == ICON_FOLDER ? 6 : 0, 
			   EZ_PADY,              type == ICON_FOLDER ? 4 : 0, 
			   EZ_ORIENTATION,       (type == ICON_FOLDER ? EZ_VERTICAL: EZ_HORIZONTAL),
			   EZ_LABEL_STRING,      (label == NULL? pathname : label),
			   EZ_FOREGROUND,        clr,
			   EZ_LABEL_PIXMAP,      labPixmap,
			   EZ_FONT_ID,           ezfmFontId[fontId],
			   EZ_CLIENT_PTR_DATA,   finfo,
			   EZ_BORDER_WIDTH,      bwidth,
			   EZ_BORDER_TYPE,       EZ_BORDER_TB_UP,
			   EZ_TEXT_LINE_LENGTH,  32,
			   EZ_CALLBACK,          itemOrIconCallback, finfo,
			   EZ_DESTROY_CALLBACK,  itemDestroyCallback,   NULL,
			   NULL);
  if(isDir && ezfmDirPixmaps[0] != NULL)
    {
      if(label && label[0]=='.' && label[1]=='.' && label[2]=='\0')
	{
	  int idx = (type == ICON_FOLDER ? 4 : 5);
	  EZ_ConfigureItem(mainitem, EZ_LABEL_PIXMAP,  ezfmDirPixmaps[idx], NULL);	
	}
      if(findFolder(pathname) != NULL)
	{
	  int idx = (type == ICON_FOLDER ? 1 : 3);
	  EZ_ConfigureItem(mainitem, EZ_LABEL_PIXMAP,  ezfmDirPixmaps[idx], NULL);
	}
      else findOpenedFolderOtherClients(pathname, &stat_buf);
    }
  
  finfo->obj = mainitem; /* cross link to finfo */
  setupDnDForItem(mainitem, finfo, isDir);
  
  /* for LIST_FOLDER, find more about 'pathname' */
  if(type == LIST_FOLDER)
    {
      int j;  char *ptr, tstr[256];
      for(j = 0; j < EZFM_FLISTBOX_N_ENTRIES; j++) items_ret_array[j] = NULL;
      items_ret_array[0] = mainitem; 
      if(status >= 0)
	{
	  time_t currentTime = time(NULL);

	  sprintf(tstr, "%d", stat_buf.st_size);
	  items_ret_array[1] = EZ_CreateItem(EZ_LABEL_ITEM,
					     EZ_LABEL_STRING,      tstr,
					     EZ_FOREGROUND,        clr,
					     EZ_LABEL_POSITION,    EZ_RIGHT,
					     EZ_FONT_ID,           ezfmFontId[fontId],
					     EZ_CLIENT_PTR_DATA,   finfo,
					     EZ_PADX,3, EZ_PADY, 0,
					     EZ_BORDER_WIDTH,      bwidth,
					     EZ_BORDER_TYPE,       EZ_BORDER_TB_UP,
					     NULL);
	  strcpy(tstr, ctime(&(stat_buf.st_ctime)));
	  if( (int)(currentTime - stat_buf.st_ctime) < SECONDS_IN_YEAR) tstr[20] = '\0';
	  items_ret_array[2] = EZ_CreateItem(EZ_LABEL_ITEM,
					     EZ_LABEL_STRING,      tstr+4,
					     EZ_FOREGROUND,        clr,
					     EZ_FONT_ID,           ezfmFontId[fontId],
					     EZ_CLIENT_PTR_DATA,   finfo,
					     EZ_PADX,3, EZ_PADY, 0,
					     EZ_BORDER_WIDTH,      bwidth,
					     EZ_BORDER_TYPE,       EZ_BORDER_TB_UP,
					     NULL);
	  items_ret_array[3] = EZ_CreateItem(EZ_LABEL_ITEM,
					     EZ_LABEL_STRING,      getFileOwnerString(tstr, &stat_buf),
					     EZ_FOREGROUND,        clr,
					     EZ_FONT_ID,           ezfmFontId[fontId],
					     EZ_CLIENT_PTR_DATA,   finfo,
					     EZ_PADX,3, EZ_PADY, 0,
					     EZ_BORDER_WIDTH,      bwidth,
					     EZ_BORDER_TYPE,       EZ_BORDER_TB_UP,
					     NULL);
	  items_ret_array[4] = EZ_CreateItem(EZ_LABEL_ITEM,
					     EZ_LABEL_STRING,      getFileGroupString(tstr, &stat_buf),
					     EZ_FOREGROUND,        clr,
					     EZ_FONT_ID,           ezfmFontId[fontId],
					     EZ_CLIENT_PTR_DATA,   finfo,
					     EZ_PADX,3, EZ_PADY, 0,
					     EZ_BORDER_WIDTH,      bwidth,
					     EZ_BORDER_TYPE,       EZ_BORDER_TB_UP,
					     NULL);
	  ptr = getFilePermiString(tstr, &stat_buf);
	  if(S_ISLNK(stat_buf.st_mode))
	    {
	      char tmpstr[256];
	      int  len = readlink(pathname, tmpstr, 255);
	      strcat(ptr, " -> ");
	      if(len > 0) { tmpstr[len] = 0;  strcat(ptr, tmpstr);}
	      else strcat(ptr, "broken link");
	    }
	  items_ret_array[5] = EZ_CreateItem(EZ_LABEL_ITEM,
					     EZ_LABEL_STRING,      ptr,
					     EZ_FOREGROUND,        clr,
					     EZ_FONT_ID,           ezfmFontId[fontId],
					     EZ_CLIENT_PTR_DATA,   finfo,
					     EZ_PADX,0, EZ_PADY, 0,
					     EZ_BORDER_WIDTH,      bwidth,
					     EZ_BORDER_TYPE,       EZ_BORDER_TB_UP,
					     NULL);
	}
    }
  return(mainitem);
}
/*****************************************************************************/
void setupDnDForItem(mainitem, finfo, isDir)
     EZ_Item *mainitem; FileInfo *finfo; int isDir;
{
  if(mainitem)
    {
      /* What to do if item is droped to the root window */
      EZ_ItemAddDnDDataEncoder(mainitem, ezfmFileNameAtom, (~0), 
			       ezfmDropOnRootWin, finfo, NULL, NULL);


      EZ_ItemAddDnDDataEncoder(mainitem, EZ_DND_DRAG_INIT_ATOM, 
			       0, ezfmSetDragIconEncoder, finfo, NULL, NULL);

      /* 
       * When an item is droped to a dropsite, we append pathname
       * and stat info to the initial handshaking message. The dropsite
       * will decide which target it wants. We do this to avoid uncessary
       * conversion for local files.
       */
      EZ_ItemAddDnDDataEncoder(mainitem, EZ_DND_DRAG_START_ATOM,  /* drag setup    */
			       0, ezfmIIEncodeStartFilter, finfo, NULL, NULL);
      EZ_ItemAddDnDDataEncoder(mainitem, EZ_DND_DRAG_FINISH_ATOM, /* drag clean up */ 
			       0, ezfmIIEncodeFinishFilter, finfo, NULL, NULL);

      /*
       * Normal Encoders
       */
      /* encode filename, content and tared content */
      EZ_ItemAddDnDDataEncoder(mainitem, ezfmFileNameAtom, 0, 
			       ezfmEncodeFileName, finfo, NULL, NULL);
      if(!isDir)
	EZ_ItemAddDnDDataEncoder(mainitem, ezfmFileContentAtom, 0,
				 ezfmEncodeFileContent, finfo,  NULL, NULL);

      EZ_ItemAddDnDDataEncoder(mainitem, ezfmFileTaredContentAtom, 0,
			       ezfmEncodeTaredFileContent, finfo, NULL, NULL);

      EZ_ItemAddDnDDataEncoder(mainitem, ezfmFileInfoAtom, 0,
			       ezfmEncodeFileInfo, finfo, NULL, NULL);
      /* move file (by name only) */
      EZ_ItemAddDnDDataEncoder(mainitem, ezfmMoveFileByNameAtom, 0, 
			       ezfmEncodeFileName, finfo, NULL, NULL);

      /* copy file */
      EZ_ItemAddDnDDataEncoder(mainitem, ezfmCopyFileByNameAtom, ControlMask,
			       ezfmEncodeFileName, finfo, NULL, NULL);
      EZ_ItemAddDnDDataEncoder(mainitem, ezfmCopyFileByContentAtom, ControlMask,
			       ezfmEncodeFileContent, finfo, NULL, NULL);
      EZ_ItemAddDnDDataEncoder(mainitem, ezfmCopyFileByTarAtom, ControlMask,
			       ezfmEncodeTaredFileContent, finfo, NULL, NULL);  
      /* link file */
      EZ_ItemAddDnDDataEncoder(mainitem, ezfmLinkFileByNameAtom, ShiftMask,
			       ezfmEncodeFileName, finfo, NULL, NULL);

      /* tool execution on mainitem */

      EZ_ItemAddDnDDataDecoder(mainitem, ezfmToolExecutionAtom, 0,
			       ezfmDecodeToolInfo, finfo, NULL, NULL);

      /*
       * decoders
       */
      if(isDir)
	{
	  /*
	   * For directory items, the setup does two things if drag src
	   * is a local file:
	   *  1. sanity check, abort drop if src is parent or drop to its current dir;
	   *  2. eliminate all targets except FILE_NAME.
	   */
	  EZ_ItemAddDnDDataDecoder(mainitem, EZ_DND_DROP_START_ATOM, /* drop setup    */
				   0, dirDnDTargetStartFilter, finfo, NULL, NULL);
	  EZ_ItemAddDnDDataDecoder(mainitem, EZ_DND_DROP_FINISH_ATOM,/* drag clean up */
				   0,dirDnDTargetFinishFilter, finfo, NULL, NULL);

	  /*
	   * Normal Decoders
	   */
	  /* move file (by name only) */
	  EZ_ItemAddDnDDataDecoder(mainitem, ezfmMoveFileByNameAtom, 0,
				   ezfmMoveToDirByName, finfo, NULL, NULL);
	  
	  /* copy file */
	  EZ_ItemAddDnDDataDecoder(mainitem, ezfmCopyFileByNameAtom, ControlMask,
				   ezfmCopyToDirByName, finfo, NULL, NULL);
	  EZ_ItemAddDnDDataDecoder(mainitem, ezfmCopyFileByContentAtom, ControlMask,
				   ezfmCopyToDirByContent, finfo, NULL, NULL);
	  EZ_ItemAddDnDDataDecoder(mainitem, ezfmCopyFileByTarAtom, ControlMask,
				   ezfmCopyToDirByTar, finfo, NULL, NULL);
	  
	  /* link file */	      
	  EZ_ItemAddDnDDataDecoder(mainitem, ezfmLinkFileByNameAtom, ShiftMask,
				   ezfmLinkToDirByName, finfo, NULL, NULL);

	  /* move multiple files (by name only) */
	  EZ_ItemAddDnDDataDecoder(mainitem, ezfmMoveMultipleFilesAtom, 0,
				   ezfmMoveMultipleFilesD, finfo, NULL, NULL);
	  /* copy multiple files (by name only) */
	  EZ_ItemAddDnDDataDecoder(mainitem, ezfmCopyMultipleFilesAtom, ControlMask,
				   ezfmCopyMultipleFilesD, finfo, NULL, NULL);
	  /* link multiple file */	      
	  EZ_ItemAddDnDDataDecoder(mainitem, ezfmLinkMultipleFilesAtom, ShiftMask,
				   ezfmLinkMultipleFilesD, finfo, NULL, NULL);
	}
      else /* non-directory items */
	{
	  
	}
    }
}
/********************************************************
 * Free allocated memory for item when the item is being
 * destroyed.
 */
static void itemDestroyCallback(item, data)
     EZ_Item *item; void *data;
{
  if(item)
    {
      FileInfo *p = (FileInfo *)EZ_GetItemPtrData(item);
      if(p) 
	{
	  (void) EZ_Free( (void *)p->pathname);
	  (void) EZ_Free( (void *)p);
	}
    }
}
/*********************************************************************************/
int ezfmSetDragIconEncoder(item, data, message, len, nFree)
     EZ_Item *item, *data; char **message; int *len, *nFree;
{
  FileInfo *finfo = (FileInfo *)data;
  if(finfo)
    {
      char     lxpmFile[64], sxpmFile[64];
      char     *clr = "black", color[256];
      char     *tspec =  finfo->ezfmData;
      int      fontId = getSpecFontId(tspec);
      char     *ptr, *pathname = finfo->pathname;
      ptr = strrchr(pathname, '/');
      if(ptr) ptr++; else ptr = pathname;

      getSpecColor(tspec, color); if(color[0]) clr = color;
      getSpecPixmap(tspec, lxpmFile, sxpmFile);
      EZ_ConfigureWidget(ezfmDragIcon, 
			 EZ_PIXMAP_FILE,   lxpmFile,
			 EZ_LABEL_STRING,  ptr,
			 EZ_FOREGROUND,    clr,
			 0);
      EZ_SetDragCursor(ezfmDragCursor);
      EZ_SetDragIcon(ezfmDragIcon, 1);
    }
  return(EZ_DND_SUCCESS);
}
/*********************************************************************************/
#undef _ITEMS_C_
