//=-- Plugin.h - Abstract base class for plugins to derive from --------------=
//
// Plugin Class:
//   The Plugin class is the common base class of all of the pluggable 
//   components in MagicStats.  All plugins have a name, a type, and a number
//   of implementation defined behaviors.  Plugins may be either statically 
//   linked into MagicStats, or dynamically loaded at runtime.
//
// PluginTemplate Class:
//   Template wrapper class that should be used by plugins to expose the 
//   important interface layer, without defining a ton of functions.  Is it a 
//   way to get something for nothing?  I think so!  The first class is the 
//   superclass that you want to derive from (ex AccessFilterPlugin), and the 
//   second is the name of the class you are deriving.
//
// PluginDesc Class:
//   The Descriptor Class for a plugin...  This class holds all of the 
//   information neccesary to create a named plugin and tell what type it is.  
//   "Hey plugin, what's your type?"
//
// PluginInit Class:
//   This class is intended to be used once for each plugin to register it into
//   available plugins table.  With the aid of the INIT_PLUGIN macro, all that 
//   a plugin has to do is write INIT_PLUGIN(PluginName); once in the source 
//   code.
//
//=---------------------------------------------------------------------------=
//  This file is copyright (c) 1997-2000 Chris Lattner
//=---------------------------------------------------------------------------=

#ifndef PLUGIN_H
#define PLUGIN_H

class PluginDesc;
class VTExp;
template <class Key, class Value> class Table;

#include "MSString.h"
#include "MSFilename.h"

// Plugin - The Plugin class is the common base class of all of the pluggable 
//   components in MagicStats.  All plugins have a name, a type, and a number
//   of implementation defined behaviors.  Plugins may be either statically 
//   linked into MagicStats, or dynamically loaded at runtime.
//
class MSAPI Plugin {
  friend class PluginDesc;
public :

  enum PluginType {           // Accepted types of plugins...
    NONE = -1,                // It's NOT a plugin!  (e.g. terminating null)

    PAGE_PLUGIN = 0,
    ACCESS_FORMAT_PLUGIN = 1,
    ACCESS_FILTER_PLUGIN = 2,
    BROWSER_TYPE_PLUGIN = 3,
    FILE_STREAM_PLUGIN = 4,
    ENGINE_PLUGIN = 5,

    NUMPLUGINTYPES = 6        // 0-NUMPLUGINTYPES-1 are valid PluginTypes...
  };

  // PluginTypeNames contain alphanumeric names for PluginTypes.  This array
  // is defined from 0 -> (NUMPLUGINTYPES-1)
  static const char *PluginTypeNames[NUMPLUGINTYPES];

  enum {
    UpdateAll     =-1,
    UpdateAlways  = 0,
    UpdateDaily   = 1,
    UpdateWeekly  = 2,
    UpdateMonthly = 3,
    UpdateYearly  = 4,
    UpdateNever   = 5,

    UpdateMaximum = 5   // Maximum update value...  Must be kept up to date
                        //  with MAXUPDATEFREQ in Options.h
  };

  Plugin(const String &name) 
                         : Name(name), Descriptor(*Plugin::CurCreatingDesc) {
    UpdateFreq = Plugin::UpdateNever; 
  }

  virtual ~Plugin();
  
  virtual void LoadSettings(Table<CSString,VTExp*> *) {}

  virtual void LoadState(Serialize &) {}
  virtual void SaveState(Serialize &) {}
  virtual void ResetState()           {}

  virtual const String GetName() const { return Name; }
  virtual const String GetPluginFullName() const { return Name; }

  virtual PluginType GetType() const { return Plugin::NONE; }

  // Create a plugin of a specified type.
  static Plugin *CreatePlugin(PluginType Type, const String &Name);

  // SetPluginSource - Set the resource location to point to a specific resource
  // location.  Any plugins loaded while this is set will have their resource
  // locations set to the specified values.
  //
  static void SetPluginSource(const String &Path, const String &URL);

  // ClearPluginSource - Resets them to their BuiltIn Settings...
  //
  static void ClearPluginSource();
  
  // Print out the plugin list... nice for debugging and stuff.
  static void PrintPlugins();

  int UpdateFreq;       // How often is the data from this plugin purged?

  // The current resource location that we are loading plugins from...  this
  // information gets copied into each plugin as it is loaded...
  //
  static String PluginSourcePath;
  static String PluginSourceURL;

  // When creating a new plugin, this pointer is set to the plugin descriptor 
  // that corresponds to it.  Practically, this is always set to the descriptor
  // of the latest plugin created...
  //
  static PluginDesc *CurCreatingDesc;

protected :
  static Plugin *CreatePlugin(PluginType Type, void *Data);
  
        String      Name;
  const PluginDesc &Descriptor;

private :
  static void AddPluginDescriptor(const PluginDesc &D);
  static Table<CSString, PluginDesc> &GetPlugins();
};

 
// PluginTemplate - Template wrapper class that should be used by plugins to 
//   expose the important interface layer, without defining a ton of functions.
//   Is it a way to get something for nothing?  I think so!  The first class is
//   the superclass that you want to derive from (ex AccessFilterPlugin), and 
//   the second is the name of the class you are deriving.
//
template <class SuperClass, class SubClass>
class PluginTemplate : public SuperClass {
public:
  PluginTemplate<SuperClass, SubClass>() 
    : SuperClass(SubClass::GetPluginName()) {}

  virtual Plugin::PluginType GetType() const { 
    return GetPluginType(); 
  }

  inline static Plugin::PluginType GetPluginType() { 
    return SuperClass::GetPluginType(); 
  }

  static Plugin *CreateInstance() {
    int CreateError = 0;
    Plugin *P = new SubClass(CreateError);
    if (!CreateError) return P;
    delete P;
    return 0;
  }

  static Plugin *CreateInstanceData(void *) {
    char *c = 0;
    *c = 1; // Self destruct.  Should never be here because priority is -1.
    return 0;
  }
  inline static int GetPriority() { return -1; } // default to never create.
};


// PluginDesc - The Descriptor Class for a plugin...  This class holds all of 
//   the information neccesary to create a named plugin and tell what type it
//   is.  "Hey plugin, what's your type?"
//
class MSAPI PluginDesc : public Object {
public :
  PluginDesc();
  PluginDesc(Plugin *(*CI)(void) , const char *N, 
             Plugin::PluginType T, int version,
             Plugin *(*CID)(void *), int Priority);

  int Compare(const class Object &O) const;
  ostream &print(ostream &O) const;

  void RegisterPlugin() const;

  // Data Members...
  Plugin *(*CreateInstance    )(void);    // No parameter
  Plugin *(*CreateInstanceData)(void *);  // Plugin defined type...

  // Priority when creating with Data... or -1 to have never be created.
  int Priority; 

  const char *Name;
  MSFilename PluginSourcePath;
  String     PluginSourceURL;
  Plugin::PluginType Type;
  int Version;
};


// PluginInit - This class is intended to be used once for each plugin to 
//   register it into available plugins table.  With the aid of the 
//   INIT_PLUGIN macro, all that a plugin has to do is write 
//   INIT_PLUGIN(PluginName); once in the source code.
//
template <class T> class MSAPI PluginInit {
public :
  PluginInit<T>() {
    PluginDesc D = PluginDesc(T::CreateInstance, T::GetPluginName(), 
                              T::GetPluginType(), T::GetCurrentVersion(),
                              T::CreateInstanceData, T::GetPriority());
    D.RegisterPlugin();
  }
};

#define INIT_PLUGIN(Name) static PluginInit<Name> _init_Plugin##Name;

#endif

