/*
 *
 *    soniK digital audio editor
 *    Copyright (C) 2003-2006  Robert Walker <rob@tenfoot.org.uk>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
#ifndef SONIK_LADSPA_PLUGIN_H
#define SONIK_LADSPA_PLUGIN_H

#include "edit.h"

#include <kxmlguiclient.h>

#include <ladspa.h>

class QDomElement;

typedef void* LADSPA_LibraryHandle;
typedef unsigned long LADSPA_PortIndex;
typedef QValueVector<LADSPA_PortIndex> LADSPA_PortIndexVector;
typedef QValueList<const LADSPA_Descriptor*> LADSPA_DescriptorList;

namespace Sonik
{
  class UiControl;

  struct LadspaControlInfo
  {
    static const uint32_t VALUE     = 0x01;
    static const uint32_t LOWER     = 0x02;
    static const uint32_t UPPER     = 0x04;
    static const uint32_t ISINTEGER = 0x08;
    static const uint32_t ISLOG     = 0x10;
    static const uint32_t UITYPE    = 0x20;

    LadspaControlInfo()
      : flags(0), value(0.0f), lower(0.0f), upper(0.0f),
        isInteger(false), isLog(false), uiType(UiControl::NONE)
    {
    }

    uint32_t        flags;

    QString         name;
    LADSPA_Data     value;
    LADSPA_Data     lower;
    LADSPA_Data     upper;
    bool            isInteger;
    bool            isLog;
    UiControl::Type uiType;
  };


  class LadspaControlInfoList : public QValueList<LadspaControlInfo>
  {
  public:
    LadspaControlInfoList()
      : QValueList<LadspaControlInfo>() { }
    LadspaControlInfoList(const LadspaControlInfoList& l)
      : QValueList<LadspaControlInfo>(l) { }
    LadspaControlInfoList(const QValueList<LadspaControlInfo>& l)
      : QValueList<LadspaControlInfo>(l) { }

    LadspaControlInfoList::const_iterator findByName(const QString& name) const
    {
      LadspaControlInfoList::const_iterator it = begin();
      for ( ; it != end(); ++it)
        if ((*it).name == name)
          return it;

      return end();
    }
  };


  enum PluginChannelType
  {
    UNKNOWN,
    GENERATE,
    TRANSFORM_SAME,
    TRANSFORM_MAP_UP,
    TRANSFORM_MAP_DOWN
  };


  struct LadspaPlugin
  {
    unsigned long         id;
    QString               lib;
    QString               label;      // identifier
    QString               name;       // user visible name
    QStringList           category;

    bool                  ignore;

    PluginChannelType     type;

    QStringList           inputPorts;
    QStringList           outputPorts;

    LadspaControlInfoList controlPorts;
  };
  typedef QMap<QString, LadspaPlugin> LadspaPluginMap;


  class Ladspa : public Edit
  {
    Q_OBJECT
  public:
    Ladspa(QObject* parent, const char* name, const QStringList& args);
    virtual ~Ladspa();

    virtual QWidget* makeConfigPage(QWidget* parent=0);
    virtual void     applyConfigPage();

  private slots:
    void handleAction(const QString& action);
    void setupActions();

    void applyPlugin(Sonik::Edit::PluginContext* context);

  private:
    struct LadspaPluginContext : public PluginContext
    {
      virtual ~LadspaPluginContext();

      LadspaPlugin plugin;
      LADSPA_LibraryHandle lib;
      const LADSPA_Descriptor* descriptor;
      LADSPA_PortIndexVector inputPorts;
      LADSPA_PortIndexVector outputPorts;
      LADSPA_PortIndexVector nullPorts;
      LADSPA_PortIndexVector sinkPorts;
    };

    void scanPlugins();
    void scanPluginLibraries();
    void scanPluginRdfs();
    void scanPluginOverrides();
    void processPluginOverride(QDomElement& e, LadspaPlugin& plugin);
    void determinePluginTypes();
    UiControl* processControl(const LadspaPlugin& plugin,
                              const LADSPA_Descriptor* descriptor,
                              const QString& portName,
                              LADSPA_PortIndex i,
                              QWidget* parent);

    QString         mSearchPath;
    LadspaPluginMap mPlugins;
  };

}

#endif // SONIK_LADSPA_PLUGIN_H
