/* (PD) 2001 The Bitzi Corporation
 * Please see file COPYING or http://bitzi.com/publicdomain 
 * for more info.
 *
 * $Id: plugin_win32.c,v 1.1 2001/04/12 21:01:16 robert Exp $
 */
/*------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <windows.h>

#include "bitcollider.h"
#include "plugin_man.h"

/*------------------------------------------------------------------------- */
#ifndef MAX_PATH
   #define MAX_PATH    1024
#endif
#define DB printf("%s:%d\n", __FILE__, __LINE__);
#define ERROR_FILENOTFOUND   "File not found."

/*------------------------------------------------------------------------- */
typedef PluginMethods *(CALLBACK* InitFunction)(void);
/*------------------------------------------------------------------------- */

Bitcollider *init_plugins(void)
{
   Bitcollider *bc;

   bc = malloc(sizeof(Bitcollider));
   memset(bc, 0, sizeof(Bitcollider));

   return bc;
}

void shutdown_plugins(Bitcollider *bc)
{
   free(bc);
}

int load_plugins(Bitcollider *bc, const char *path, b_bool printDebugInfo)
{
   WIN32_FIND_DATA  find;
   HANDLE           hFind;
   int              count = 0, j;
   char            *ptr, file[MAX_PATH];
   InitFunction     init_function;

   sprintf(file, "%s\\*.bcp", path);
   hFind = FindFirstFile(file, &find);
   if (hFind == INVALID_HANDLE_VALUE)
      return 0;

   for(j = 0;; j++)
   {
       if (j > 0)
          if (!FindNextFile(hFind, &find))
              break;

       ptr = strrchr(find.cFileName, '.');
       if (!ptr || strcasecmp(ptr, ".bcp"))
          continue;

       if (printDebugInfo)
           printf("  %s: ", find.cFileName);
       sprintf(file, "%s/%s", path, find.cFileName);

       /* Found one, lets open it */
       bc->plugins[bc->numPluginsLoaded].handle = LoadLibrary(file);
       if (bc->plugins[bc->numPluginsLoaded].handle == NULL)
       {
           if (printDebugInfo)
               printf("Cannot load plugin %s.\n", file);
           continue;
       }
       bc->plugins[bc->numPluginsLoaded].file = strdup(find.cFileName);

       /* Opened plugin ok, now locate our entry function */
       init_function = (InitFunction)GetProcAddress(
                                 bc->plugins[bc->numPluginsLoaded].handle, "init_plugin");
       if (init_function == NULL)
       {
           FreeLibrary(bc->plugins[bc->numPluginsLoaded].handle);
           if (printDebugInfo)
               printf("Cannot find entry point in %s.\n", file);
           continue;
       }

       /* Init the plugin and get the methods provided by the plugin */
       bc->plugins[bc->numPluginsLoaded].methods = init_function();
       if (bc->plugins[bc->numPluginsLoaded].methods == NULL)
       {
           FreeLibrary(bc->plugins[bc->numPluginsLoaded].handle);
           if (printDebugInfo)
               printf("Cannot retrieve supported methods from %s.\n", file);
           continue;
       }

       /* Now get the formats handled by the plugin */
       bc->plugins[bc->numPluginsLoaded].formats = 
           bc->plugins[bc->numPluginsLoaded].methods->get_supported_formats();

       if (printDebugInfo)
       {
           printf("%s ",bc-> plugins[bc->numPluginsLoaded].methods->get_name());
           printf("(%s)\n", bc->plugins[bc->numPluginsLoaded].methods->
                               get_version());

       }

       /* Check to make sure that the given plugin hasnt already been loaded */
       for(j = 0; j < bc->numPluginsLoaded; j++)
       {
           if (!strcmp(bc->plugins[j].file, 
                       bc->plugins[bc->numPluginsLoaded].file))
           {
               if (printDebugInfo)
                  printf("  [Plugin %s has alaready been loaded. Skipping.]\n",
                    bc->plugins[bc->numPluginsLoaded].file);
                
               bc->plugins[bc->numPluginsLoaded].methods->shutdown_plugin();
               FreeLibrary(bc->plugins[bc->numPluginsLoaded].handle);
               bc->plugins[bc->numPluginsLoaded].handle = NULL;
               bc->plugins[bc->numPluginsLoaded].methods = NULL;
               free(bc->plugins[bc->numPluginsLoaded].file);
               bc->plugins[bc->numPluginsLoaded].file = NULL;

               break;
           }
       }

       /* If we didn't already this plugin loaded, increment our counters */
       if (j == bc->numPluginsLoaded)
       {
          bc->numPluginsLoaded++;
          count++;
       }

   }
   FindClose(hFind);

   return count;
}

void unload_plugins(Bitcollider *bc)
{
   for(;;)
   {
       bc->numPluginsLoaded--;
       if (bc->numPluginsLoaded < 0)
          break;

       if (bc->plugins[bc->numPluginsLoaded].handle)
       {
           bc->plugins[bc->numPluginsLoaded].methods->shutdown_plugin();
           FreeLibrary(bc->plugins[bc->numPluginsLoaded].handle);
           bc->plugins[bc->numPluginsLoaded].handle = NULL;
           bc->plugins[bc->numPluginsLoaded].methods = NULL;
           free(bc->plugins[bc->numPluginsLoaded].file);
           bc->plugins[bc->numPluginsLoaded].file = NULL;
       }
   }
}

int get_num_plugins(Bitcollider *bc)
{
   return bc->numPluginsLoaded;
}

PluginMethods *get_plugin(Bitcollider *bc, const char *extension)
{
   int              i;
   SupportedFormat *format;

   for(i = 0; i < bc->numPluginsLoaded; i++)
   {
      for(format = bc->plugins[i].formats; format && 
          format->fileExtension; format++)
      {
         if (strcasecmp(format->fileExtension, extension) == 0)
             return bc->plugins[i].methods;
      }
   }

   return NULL;
}

void set_plugin_dir(char *path)
{
   char *ptr;
   HKEY  hKey;
   DWORD action;
   LONG  ret;

   GetModuleFileName(NULL, path, MAX_PATH);
   ptr = strrchr(path, '\\');
   if (ptr)
   {
       *ptr = 0;
       strcat(path, "\\plugins");
   }

   ret = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Software\\Bitzi", 0, NULL, 
                        REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, &action);
   if (ret != ERROR_SUCCESS)
      return;

   RegSetValueEx(hKey, "PluginDir", 0, REG_SZ, path, strlen(path));

   RegCloseKey(hKey);
}