#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/stat.h>
/* #include <fnmatch.h> */
#include <errno.h>

#include "connap.h"
#include "connect.h"
#include "message.h"
#include "shared.h"
#include "mp3info.h"
#include "util.h"


SHARED *shared_files = NULL;
SHAREDDIR *shared_dirs = NULL;

static char *init_dir = NULL;

#if 0

static char *map_shared_name(String name)
{
   static String mappedName = NULL;
   String p;

   if (mappedName)
       XtFree(mappedName);

   mappedName = XtMalloc(strlen(name) + 5);
   sprintf(mappedName, "C:%s", name);

   for (p = (mappedName + 2); *p; p++) {
       if ((*p) == '/')
           (*p) = '\\';
   }

   return mappedName;
}


static void NotifySharedFile(SHARED *shared)
{
   String tmp;

   if (! srvConn)
       return;

   tmp = XtMalloc(512);
   sprintf(tmp, "\"%s\" 00000000000000000000000000000000 %d %d %d %d",
               MapSharedName(shared->fileName), shared->size,
               shared->bitRate, shared->freq, shared->sec);

   if (SendMsg(MSG_CLIENT_ADD_FILE, tmp))
       Disconnect(strerror(errno));

   XtFree(tmp);
}


void NotifySharedFiles(void)
{
   SHARED *shared;

   if (! sharedFiles)
       return;

   SimpleMsg("Notifying shared files...");

   for (shared = sharedFiles; shared; shared = shared->next) {
       NotifySharedFile(shared);
   }

   SimpleMsgRemove();
}


static void AddSharedFile(String name, int size)
{
   SHARED *newShared, *rec;
   MP3INFO *info;

   info = MP3Info(name);
   if (! info) {
       ErrMsg("Error reading MP3 info");
       return;
   }

   newShared = XtNew(SHARED);
   newShared->fileName = XtNewString(name);
   newShared->size = size;
   newShared->bitRate = info->bitrate;
   newShared->freq = info->freq;
   newShared->sec = info->seconds;
   newShared->next = NULL;

   if (! sharedFiles) {
       sharedFiles = newShared;
   } else {
       for (rec = sharedFiles; rec->next; rec = rec->next);
       rec->next = newShared;
   }

   if (srvConn)
       NotifySharedFile(newShared);
}


void RemoveSharedFile(String name)
{
   SHARED *shared, *prevShared = NULL;

   for (shared = sharedFiles; shared; shared = shared->next) {
       if (! strcmp(shared->fileName, name))
           break;
       prevShared = shared;
   }

   if (! shared)
       return;

   if (prevShared)
       prevShared->next = shared->next;
   else
       sharedFiles = sharedFiles->next;

   if (srvConn) {
       if (SendMsg(MSG_CLIENT_REMOVE_FILE,
               MapSharedName(shared->fileName)))
           Disconnect(strerror(errno));
   }

   XtFree(shared->fileName);
   XtFree((char*)shared);
}


static void AddSharedDir(String name)
{
   SHAREDDIR *newDir, *dirPtr, *prevPtr = NULL;

   newDir = XtNew(SHAREDDIR);
   newDir->dirName = XtNewString(name);

   for (dirPtr = sharedDirs; dirPtr; dirPtr = dirPtr->next) {
       if (strcasecmp(dirPtr->dirName, newDir->dirName) > 0)
           break;
       prevPtr = dirPtr;
   }

   if (prevPtr) {
       newDir->next = prevPtr->next;
       prevPtr->next = newDir;
   } else {
       newDir->next = sharedDirs;
       sharedDirs = newDir;
   }
}


int RemoveSharedDir(String name)
{
   SHAREDDIR *dir, *prevDir = NULL;
   SHARED *shared;
   String tmp;

   for (dir = sharedDirs; dir; dir = dir->next) {
       if (! strcmp(dir->dirName, name))
           break;
       prevDir = dir;
   }
   if (! dir) {
       ErrMsg("Directory is not shared");
       return 0;
   }

   tmp = XtMalloc(PATH_MAX + 2);
   sprintf(tmp, "%s*", name);

   for (shared = sharedFiles; shared; shared = shared->next) {
       if (! fnmatch(tmp, shared->fileName, 0))
           RemoveSharedFile(shared->fileName);
   }
   XtFree(tmp);

   if (prevDir)
       prevDir->next = dir->next;
   else
       sharedDirs = sharedDirs->next;

   XtFree(dir->dirName);
   XtFree((char*)dir);
   return 1;
}


static void RecurseDir(String dir)
{
   struct stat st;
   String tmp = XtMalloc(4096);
   SHARED *shared;
   int match;
   FILE *fd;

   sprintf(tmp, "find '%s' -type f -name '*.[mM][pP]3' 2>/dev/null", dir);
   if (! (fd = popen(tmp, "r"))) {
       ErrMsg("popen failed");
       return;
   }

   while (fgets(tmp, 4096, fd)) {
       tmp[strlen(tmp) - 1] = 0;
       if (stat(tmp, &st) == -1)
           continue;
       if (strchr(tmp, '\"'))
           continue;
       match = 0;
       for (shared = sharedFiles, match = 0; shared;
               shared = shared->next) {
           if (! strcmp(shared->fileName, tmp)) {
               match = 1;
               break;
           }
       }
       if (match)
           continue;
       AddSharedFile(tmp, st.st_size);
   }

   pclose(fd);
   XtFree(tmp);
}


int AddSharedFiles2(String dir)
{
   SHAREDDIR *sharedDir;
   SHARED *shared;
   String tmp;
   int newDir = 1, sameDir = 0;
   FILE *fd;

   tmp = XtMalloc(PATH_MAX + 2);
   for (sharedDir = sharedDirs; sharedDir; sharedDir = sharedDir->next) {
       sprintf(tmp, "%s*", sharedDir->dirName);
       if (! fnmatch(tmp, dir, 0)) {
           newDir = 0;
           if (! strcmp(sharedDir->dirName, dir))
               sameDir = 1;
           break;
       } else {
           sprintf(tmp, "%s*", dir);
           if (! fnmatch(tmp, sharedDir->dirName, 0)) {
               newDir = -1;
               break;
           }
       }
   }
   XtFree(tmp);

   if (newDir == -1) {
       ErrMsg("Please remove the children directories first");
       return 0;
   } else if (newDir) {
       AddSharedDir(dir);
   } else if (! sameDir) {
       ErrMsg("A shared parent directory already exists");
       return 0;
   }

   SimpleMsg("Updating File List");

   if (! newDir) {
       for (shared = sharedFiles; shared; shared = shared->next) {
           if (! (fd = fopen(shared->fileName, "r"))) {
               RemoveSharedFile(shared->fileName);
           } else
               fclose(fd);
       }
   }

   RecurseDir(dir);
   SimpleMsgRemove();
   return 1;
}


int AddSharedFiles(void)
{
   String dir;

   if (! initDir)
       initDir = XtNewString(".");

   dir = ChooseSharedDir(initDir);
   if (! strlen(dir))
       return 0;
   if (*(dir + 1))
       *(strrchr(dir, '/')) = 0;
   XtFree(initDir);
   initDir = XtNewString(dir);

   if (! AddSharedFiles2(dir))
       return 0;
   return 1;
}


int RemoveSharedFiles(String dir)
{
   if(! RemoveSharedDir(dir))
       return 0;
   return 1;
}


static void AddSharedListFile(String s)
{
   SHARED *newShared, *rec;
   String p;

   newShared = XtNew(SHARED);
   p = strtok(s, "\"");
   newShared->fileName = XtNewString(p);
   newShared->size = atoi(strtok(NULL, " "));
   newShared->bitRate = atoi(strtok(NULL, " "));
   newShared->freq = atoi(strtok(NULL, " "));
   newShared->sec = atoi(strtok(NULL, " "));
   newShared->next = NULL;

   if (! sharedFiles) {
       sharedFiles = newShared;
   } else {
       for (rec = sharedFiles; rec->next; rec = rec->next);
       rec->next = newShared;
   }
}


void ReadFileList(FILE *fd)
{
   String line;
   int i, numFiles;

   fscanf(fd, "%d\n", &numFiles);
   if (! numFiles)
       return;

   line = XtMalloc(512);
   for (i = 0; i < numFiles; i++) {
       fgets(line, 512, fd);
       line[strlen(line) - 1] = 0;
       AddSharedListFile(line);
   }
   XtFree(line);
}


void SaveFileList(FILE *fd)
{
   SHARED *shared;
   int i;

   for (shared = sharedFiles, i = 0; shared;
        shared = shared->next, i++);
   fprintf(fd, "%d\n", i);
   if (! i)
       return;

   for (shared = sharedFiles; shared; shared = shared->next) {
       fprintf(fd, "\"%s\" %d %d %d %d\n",
               shared->fileName, shared->size, shared->bitRate,
               shared->freq, shared->sec);
   }
}

#endif