#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <pwd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <sys/stat.h>

#include <X11/X.h>
#include <X11/xpm.h>

#include <fvwm/fvwmlib.h>
#include "GoodyLoadable.h"

/* Be careful to avoid name collisions.
 * It's best to name all symbols used for external reference as
 * MailCheckModuleNameSymbol, where MailCheckModuleName is the name of the
 * MailCheckModule and Symbol is the name you would rather use.
 * More then one MailCheckModule may want to use a proc called Load !
 */


#define HasNoMail  0
#define HasMail    1
#define HasNewMail 4
#define HasUnreadMail 2

struct MyInfo{
         char *id;
/* other stuff */
         char *command;  /* action to execute on double click */
         char *NewMailcommand; /* action to execute when mail arrives */

         char *icon;  /* icon to show when there is mail */
         char *tip;
         Pixmap icon_pix;
         Pixmap icon_mask;
         XpmAttributes icon_attr;      

         char *newicon; /* icon to show when there are new mail */
         char *newtip;
         Pixmap newicon_pix;
         Pixmap newicon_mask;
         XpmAttributes newicon_attr;

         char *unreadicon; /* icon to show when there is unread mail */
         char *unreadtip;
         Pixmap unreadicon_pix;
         Pixmap unreadicon_mask;
         XpmAttributes unreadicon_attr;
         
         int offset;
         int visible;
         Time lastclick;
         int show; /* status of mailbox. 0 not to show anything */
         time_t lastchecked;
         char *lock;
         off_t mailsize;         
};
 
void MailCheckModule_getstatus(struct MyInfo *);


void *MailCheckModuleInit(char *id);
int MailCheckModuleParseResource(struct MyInfo *mif,char *tline,char *MailCheckModule,int Clength);
void MailCheckModuleLoad(struct MyInfo *mif,Display *dpy,Drawable win,int *goodies_width);
void MailCheckModuleDraw(struct MyInfo *mif,Display *dpy,Window win);
int MailCheckModuleSeeMouse(struct MyInfo *mif,int x,int y);
void MailCheckModuleCreateIconTipWindow_(struct MyInfo *mif);
void MailCheckModuleIconClick(struct MyInfo *mif,XEvent event);

struct GoodyLoadable MailCheckModuleSymbol={&MailCheckModuleInit,
                                        &MailCheckModuleParseResource,
                                        &MailCheckModuleLoad,
                                        &MailCheckModuleDraw,
                                        &MailCheckModuleSeeMouse,
                                        &MailCheckModuleCreateIconTipWindow_,
                                        &MailCheckModuleIconClick};

extern int win_width,stwin_width;
extern int RowHeight;

        
void *MailCheckModuleInit(char *id)
{
  struct MyInfo *mif;

#ifdef __DEBUG__
  printf("FvwmTaskBar.MailCheckModule.Init(\"%s\")\n", id);
  fflush(stdout);
#endif

  (void *) mif = calloc(1, sizeof(struct MyInfo));
  if (mif == NULL) {
    perror("FvwmTaskBar.MailCheckModule.Init()");
    return NULL;
  }
  mif->id = id;
  mif->command = NULL;
  mif->NewMailcommand = NULL;
  mif->icon = NULL;
  mif->newicon = NULL;
  mif->unreadicon = NULL;
  mif->tip = "You have mail";
  mif->newtip = "You have new mail";
  mif->unreadtip = "You have unread mail";
  mif->lastclick = 0;
  mif->show = HasNoMail; /* don't show by default */
  mif->lastchecked = 0;
  mif->lock = NULL;
  return mif;
}


void MailCheckModuleSetIcon(struct MyInfo *mif, char *i)
{
#ifdef __DEBUG__
  fprintf(stderr, "FvwmTaskBar.MailCheckModule.AddIcon(*,\"%s\")\n", i);
#endif

  if (mif == NULL) return;
  if (mif->icon != NULL) free(mif->icon);
  mif->icon = i;
}


#define SetIcon MailCheckModuleSetIcon

void MailCheckModuleSetNewIcon(struct MyInfo *mif, char *i)
{
#ifdef __DEBUG__
  fprintf(stderr, "FvwmTaskBar.MailCheckModule.AddIcon(*,\"%s\")\n", i);
#endif

  if (mif == NULL) return;
  if (mif->newicon != NULL) free(mif->newicon);
  mif->newicon = i;
}


#define SetNewIcon MailCheckModuleSetNewIcon

void MailCheckModuleSetUnreadIcon(struct MyInfo *mif, char *i)
{
#ifdef __DEBUG__
  fprintf(stderr, "FvwmTaskBar.MailCheckModule.AddIcon(*,\"%s\")\n", i);
#endif

  if (mif == NULL) return;
  if (mif->unreadicon != NULL) free(mif->unreadicon);
  mif->unreadicon = i;
}


#define SetUnreadIcon MailCheckModuleSetUnreadIcon

void MailCheckModuleSetIconCommand(struct MyInfo *mif, char *c)
{
  if (mif == NULL) return;
  if (mif->command != NULL) free(mif->command);
  mif->command = c;
}


#define SetIconCommand MailCheckModuleSetIconCommand

void MailCheckModuleSetNewMailCommand(struct MyInfo *mif, char *c)
{
  if (mif == NULL) return;
  if (mif->NewMailcommand != NULL) free(mif->NewMailcommand);
  mif->NewMailcommand = c;
}

#define SetNewMailCommand MailCheckModuleSetNewMailCommand


void MailCheckModuleSetIconTip(struct MyInfo *mif, char *c)
{
  if (mif == NULL) return;
  /*if (mif->tip != NULL) free(mif->tip);*/
  mif->tip = c;
}

#define SetIconTip MailCheckModuleSetIconTip


void MailCheckModuleSetLock(struct MyInfo *mif, char *c)
{
  if (mif == NULL) return;
  if (mif->lock != NULL) free(mif->lock);
  mif->lock = EnvExpand(c);
  free(c);
}

#define SetLock MailCheckModuleSetLock


int MailCheckModuleParseResource(struct MyInfo *mif, char *tline,
                                 char *Module, int Clength)
{
  char *s;

#ifdef __DEBUG__
  printf("FvwmTaskBar.MailCheckModule.ParseResource(\"%s\",\"%s\",*)\n",
         mif->id,tline);
  fflush(stdout);
#endif

  if (mif == NULL) return 0;
  s = (char *) calloc(256, sizeof(char));
  if (s == NULL) {
    perror("FvwmTaskBar.MailCheckModule.ParseGoodyIconResource()");
    return 0;
  }

  if(strncasecmp(tline,CatString3(Module, "MailCheckModuleMailIcon",mif->id),
                               Clength+23+strlen(mif->id))==0) {
    CopyString(&s, &tline[Clength+24+strlen(mif->id)]);
    SetIcon(mif,s);
    return(1);
  } else if(strncasecmp(tline,CatString3(Module, "MailCheckModuleUnreadMailIcon",mif->id),
                               Clength+29+strlen(mif->id))==0) {
    CopyString(&s, &tline[Clength+30+strlen(mif->id)]);
    SetUnreadIcon(mif,s);
    return(1);
  } else if(strncasecmp(tline,CatString3(Module, "MailCheckModuleNewMailIcon",mif->id),
                               Clength+26+strlen(mif->id))==0) {
    CopyString(&s, &tline[Clength+27+strlen(mif->id)]);
    SetNewIcon(mif,s);
    return(1);
  } else if(strncasecmp(tline,CatString3(Module, "MailCheckModuleCommand",mif->id),
                               Clength+22+strlen(mif->id))==0) {
    CopyString(&s, &tline[Clength+23+strlen(mif->id)]);
    SetIconCommand(mif,s);
    return(1);
  } else if(strncasecmp(tline,CatString3(Module, "MailCheckModuleNewMailCommand",mif->id),
                               Clength+29+strlen(mif->id))==0) {
    CopyString(&s, &tline[Clength+30+strlen(mif->id)]);
    SetNewMailCommand(mif,s);
    return(1);
  } else if(strncasecmp(tline,CatString3(Module, "MailCheckModuleMailFile",mif->id),
                               Clength+23+strlen(mif->id))==0) {
    CopyString(&s, &tline[Clength+24+strlen(mif->id)]);
    SetLock(mif,s);
    return(1);
  } else if(strncasecmp(tline,CatString3(Module, "MailCheckModuleTip",mif->id),
                               Clength+18+strlen(mif->id))==0) {
    CopyString(&s, &tline[Clength+19+strlen(mif->id)]);
    SetIconTip(mif,s);
    return(1);
  } else if(strncasecmp(tline,CatString3(Module, "MailCheckModuleNewMailTip",mif->id),
                               Clength+25+strlen(mif->id))==0) {
    CopyString(&s, &tline[Clength+26+strlen(mif->id)]);
    mif->newtip=s;
    return(1);
  } else if(strncasecmp(tline,CatString3(Module, "MailCheckModuleUnreadMailTip",mif->id),
                               Clength+28+strlen(mif->id))==0) {
    CopyString(&s, &tline[Clength+29+strlen(mif->id)]);
    mif->unreadtip=s;
    return(1);
  } else return 0;
}


void MailCheckModuleLoad(struct MyInfo *mif, Display *dpy,
                         Drawable win, int *goodies_width)
{
  int k;

#ifdef __DEBUG__
  fprintf(stderr, "FvwmTaskBar.MailCheckModule.LoadMailCheckModule()\n");
#endif

  MailCheckModule_getstatus(mif);

  mif->visible = False;

  if (XpmReadFileToPixmap(dpy, win, mif->icon,
                          &(mif->icon_pix), &(mif->icon_mask),
                          &(mif->icon_attr)) != XpmSuccess) {
    fprintf(stderr,"FvwmTaskBar.MailCheckModule.LoadMailCheckModule(): error loading %s\n"
                   "  (FvwmTaskBarMailCheckModuleIcon%s)\n",
                    mif->icon, mif->id);
    return;
  }

  if (XpmReadFileToPixmap(dpy, win, mif->newicon,
                          &(mif->newicon_pix), &(mif->newicon_mask),
                          &(mif->newicon_attr)) != XpmSuccess) {
    fprintf(stderr,"FvwmTaskBar.MailCheckModule.LoadMailCheckModule(): error loading %s\n"
                   "  (FvwmTaskBarMailCheckModuleIcon%s)\n",
                    mif->newicon, mif->id);
    return;
  }

  if (XpmReadFileToPixmap(dpy, win, mif->unreadicon,
                          &(mif->unreadicon_pix), &(mif->unreadicon_mask),
                          &(mif->unreadicon_attr)) != XpmSuccess) {
    fprintf(stderr,"FvwmTaskBar.MailCheckModule.LoadMailCheckModule(): error loading %s\n"
                   "  (FvwmTaskBarMailCheckModuleIcon%s)\n",
                    mif->unreadicon, mif->id);
    return;
  }

  mif->visible = True;

  if ((mif->icon_attr.valuemask & XpmSize) == 0) {
    mif->icon_attr.width = 16;
    mif->icon_attr.height = 16;
  }                                                    
  *goodies_width += mif->icon_attr.width + 2;
  mif->offset = icons_offset;
  icons_offset += mif->icon_attr.width + 2;

#ifdef __DEBUG__
    fprintf(stderr,"       Loaded %s width=%d height=%d\n",
            mif->icon, mif->icon_attr.width, mif->icon_attr.height);
#endif   

}

/*-----------------------------------------------------*/
/* Get file modification time                          */
/* (based on the code of 'coolmail' By Byron C. Darrah */
/*-----------------------------------------------------*/
#define get_status MailCheckModule_getstatus

void get_status(struct MyInfo *mif)
{
  
   off_t  newsize;
   struct stat st;
   int fd;

   fd = open (mif->lock, O_RDONLY, 0);
   if (fd < 0)
   {
      
      mif->show=HasNoMail;
      newsize = 0;
   }
   else
   {
      fstat(fd, &st);
      close(fd);
      newsize = st.st_size;
      mif->show=0;
      if (newsize > 0)
         mif->show=mif->show | HasMail;
      

      if (st.st_mtime >= st.st_atime && newsize > 0)
         mif->show=mif->show | HasUnreadMail;
     
        

      if (newsize > mif->mailsize && (mif->show & HasUnreadMail)) {
         mif->show=mif->show | HasNewMail;
         RenewGoodies=1;
      }
      
   }

   mif->mailsize = newsize;
}

/*---------------------------------------------------------------------------*/

void MailCheckModule_check_lock(struct MyInfo *mif)
{
  int lock_status;

  if (mif == NULL) return;
  if (mif->lock == NULL) return;
  lock_status = mif->show;
  get_status(mif);
  if (lock_status != mif->show) { 
    RenewGoodies = 1;
    if (mif->show & HasNewMail) {
      if (mif->NewMailcommand != NULL)
        SendFvwmPipe(mif->NewMailcommand,0);
    }               
  }
}

#define check_lock MailCheckModule_check_lock
         
#define start (win_width-stwin_width)

extern GC statusgc;

void MailCheckModuleDraw(struct MyInfo *mif, Display *dpy, Window win)
{
  XGCValues gcv;
  GC copy;
  time_t now;

  unsigned long MailCheckModulegcm = GCClipMask |
                                     GCClipXOrigin | GCClipYOrigin;
#define gcm MailCheckModulegcm

  if (mif == NULL) return;

  now = time(NULL);
  if ((now-mif->lastchecked > 2)) {
    mif->lastchecked = now;
    check_lock(mif);
  }
                       
  if (mif->visible)
    switch (mif->show) {
      case HasMail:
              gcv.clip_mask = mif->icon_mask;
              gcv.clip_x_origin=start + icons_offset+3;
              gcv.clip_y_origin=((RowHeight - mif->icon_attr.height) >> 1);
             
              XChangeGC(dpy,statusgc,gcm,&gcv);      
              XCopyArea(dpy,mif->icon_pix, win, statusgc, 0, 0,
	      mif->icon_attr.width, mif->icon_attr.height,
	      gcv.clip_x_origin,
	      gcv.clip_y_origin);
	     
	     
	      mif->offset=icons_offset;
	      icons_offset+=mif->icon_attr.width+2;
	      break;

      case HasMail | HasUnreadMail:
      case HasUnreadMail:
              gcv.clip_mask = mif->unreadicon_mask;
              gcv.clip_x_origin=start + icons_offset+3;
              gcv.clip_y_origin=((RowHeight - mif->unreadicon_attr.height) >> 1);
             
              XChangeGC(dpy,statusgc,gcm,&gcv);      
              XCopyArea(dpy,mif->unreadicon_pix, win, statusgc, 0, 0,
	      mif->unreadicon_attr.width, mif->unreadicon_attr.height,
	      gcv.clip_x_origin,
	      gcv.clip_y_origin);
	     
	     
	      mif->offset=icons_offset;
	      icons_offset+=mif->unreadicon_attr.width+2;
	      break;      

      case HasMail | HasUnreadMail | HasNewMail:      
      case HasMail | HasNewMail:	      
      case HasNewMail:
              gcv.clip_mask = mif->newicon_mask;
              gcv.clip_x_origin=start + icons_offset+3;
              gcv.clip_y_origin=((RowHeight - mif->newicon_attr.height) >> 1);
             
              XChangeGC(dpy,statusgc,gcm,&gcv);      
              XCopyArea(dpy,mif->newicon_pix, win, statusgc, 0, 0,
	      mif->newicon_attr.width, mif->newicon_attr.height,
	      gcv.clip_x_origin,
	      gcv.clip_y_origin);
	     
	     
	      mif->offset=icons_offset;
	      icons_offset+=mif->newicon_attr.width+2;
	      break;

    }
}


int MailCheckModuleSeeMouse(struct MyInfo *mif, int x, int y)
{
  int xl, xr;

  if (mif == NULL) return 0;
  if (mif->show == 0) return 0;
  xl = win_width-stwin_width + mif->offset;
  xr = win_width-stwin_width + mif->offset;
  if (mif->show == HasMail)
    xr += mif->icon_attr.width;
  else
    xr += mif->newicon_attr.width;
  return (x>=xl && x<xr && y>1 && y<RowHeight-2);
}


void MailCheckModuleCreateIconTipWindow_(struct MyInfo *mif)
{
  if (mif == NULL) return;
    switch (mif->show) {
      case HasMail:
        if (mif->tip == NULL) return;
        PopupTipWindow(win_width-stwin_width+mif->offset, 0,mif->tip );
        break;

      case HasUnreadMail:
      case HasMail | HasUnreadMail:
        if (mif->unreadtip == NULL) return;
        PopupTipWindow(win_width-stwin_width+mif->offset,0,mif->unreadtip);
        break;

      case HasNewMail:
      case HasMail | HasNewMail:
      case HasMail | HasUnreadMail | HasNewMail:
      case HasUnreadMail | HasNewMail:
        if (mif->newtip == NULL) return;
        PopupTipWindow(win_width-stwin_width+mif->offset,0,mif->newtip);
        break;
    } 
}


#undef __DEBUG__

void MailCheckModuleIconClick(struct MyInfo *mif, XEvent event)
{
  if (mif == NULL) return;
  if (mif->command == NULL) return;
  if (event.xbutton.time - mif->lastclick < 250) {
    SendFvwmPipe(mif->command, 0);
#ifdef __DEBUG__
    printf("\"%s\"\n",mif->command);
    fflush(stdout);
#endif
  }
  mif->lastclick = event.xbutton.time;
}
