#include <sys/inotify.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <limits.h>
#include <dirent.h>

static int has_sfx(char *M, char *S)
{
  int Ls, Lm;
  Ls= strlen(S);
  Lm= strlen(M);
  if (Lm<=Ls) return 0;
  return strcasecmp(M+Lm-Ls,S);
}


static int scan_dest_dir(char *dn)
{
   int max_sfx= 1;
   DIR *dir= opendir(dn);
   if (!dir) exit(fprintf(stderr,"can not open destination directory %s: %s\n",
                  dn, strerror(errno)));
   while(1)
   {
     struct dirent *entry= readdir(dir);
     char *digit;
     if (!entry) {
        if (errno) exit(fprintf(stderr,
             "can not read destination directory %s: %s\n",
                   dn, strerror(errno)));
        break;
     }
     for(digit= entry->d_name+strlen(entry->d_name)-1;
                  digit!=entry->d_name;digit--)
         if (isdigit(digit[0])) 
           break;
     if (!isdigit(digit[0])) continue;
     while(digit>entry->d_name && isdigit(digit[-1])) digit--;
     while(*digit=='0') digit++;
     int K= atoi(digit);
     if (K>max_sfx) max_sfx= K;
   }
   closedir(dir);
   return max_sfx;
}

static char *combine(char *dir,char *file)
{
  char *name= malloc(strlen(dir)+strlen(file)+2);
  sprintf(name,"%s/%s",dir,file);
  return name;
}

static void get_sfx(char *fn,char *sfx)
{
  char *K= fn+ strlen(fn);
  while(K>fn && K[-1]!='.') K--;
  if (K==fn) *sfx= 0;
  else strcpy(sfx, K-1);
}

static void move_file(char *srcdir, char *dstdir, char *file,char *pfx, int nr)
{
  char *argv[6];
  char *sfx;
  char *sf, *df;
  
  sfx= malloc(strlen(file)+1);
  get_sfx(file, sfx);

  sf= combine(srcdir, file);

  df= malloc(strlen(dstdir)+1+strlen(pfx)+10+ strlen(sfx) + 1);

  pid_t pp;
  int status;
  sprintf(df, "%s/%s%04d%s", dstdir, pfx, nr, sfx);
  printf("moving %s to %s\n", sf, df);

  pp= fork();
  if (!pp)
  {
    argv[0]= "/bin/mv";
    argv[1]= sf;
    argv[2]= df;
    argv[3]= NULL;
    execv(argv[0], argv);
  }
  if (pp!=-1) waitpid(pp, &status,0);
  free(sf);
  free(df);
}


int main(int argc,char **argv)
{
  char *src_dir, *dst_dir;
  char **sfx;
  int nsfx,i;
  int R,l;
  int last;
  char *pfx;

  if (argc<5)
    exit(fprintf(stderr,"usage: %s source_dir dest_dir "
                         "prefix suffix1 suffix2 ...\n",
                          argv[0]));
  src_dir= argv[1];
  dst_dir= argv[2];
  pfx= argv[3];
  sfx= argv+4;
  nsfx= argc-4;

  last= scan_dest_dir(dst_dir);

  int fd;
  fd= inotify_init(); 
  inotify_add_watch(fd,src_dir,IN_CLOSE_WRITE);// | IN_CREATE |IN_MOVED_TO);

  printf("Watching %s\n", src_dir);

  while(1)
  {
    struct inotify_event *event;
    unsigned char *buf;
    unsigned char stor[ sizeof (struct inotify_event) + NAME_MAX + 1 ];

    buf= stor;
    l= sizeof(stor);
    
    R= read(fd, buf, l);
    if (R<=0) { if (errno==EINTR) continue;
               exit(fprintf(stderr,"can't read from watch: %s\n",
                                    strerror(errno))); }
    event= (void*) stor;

    //printf("event mask= %d (CW= %d)\n", event->mask, IN_CLOSE_WRITE);
    if (!(event->mask&IN_CLOSE_WRITE)) continue;
    if (event->len<=1) continue;
    for(i=0;i<nsfx;i++)
      if (has_sfx(event->name,sfx[i]))
        break;
    if (i==nsfx) continue;

    usleep(100000);
    move_file(src_dir, dst_dir, event->name, pfx, ++last);
  }
}
