/*
 *
 *    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
 *
 */
#include "configdialog.h"

#include "partsettings.h"
#include "partwidget.h"
#include "part.h"

#include "displayconfig.h"

#include <kjanuswidget.h>
#include <klistbox.h>
#include <klocale.h>
#include <kdebug.h>
#include <kiconloader.h>
#include <kcombobox.h>

#include <qwidget.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qtabwidget.h>
#include <qvbox.h>


namespace Sonik
{
  class PluginConfigWidget : public QWidget
  {
  public:
    PluginConfigWidget(const PluginList& plugins,
                       QWidget* parent=0, const char* name=0);
    virtual ~PluginConfigWidget() { }

    virtual void apply();

  private:
    PluginList  mPlugins;
  };

  class GeneralConfigPage : public ConfigDialogPage
  {
  public:
    GeneralConfigPage(QWidget* parent=0, const char* name=0);
    virtual ~GeneralConfigPage() { }

    virtual void apply();

  private:
  };

  class DisplayConfigPage : public ConfigDialogPage
  {
  public:
    DisplayConfigPage(const PluginList& plugins, Part& part,
                      QWidget* parent=0, const char* name=0);
    virtual ~DisplayConfigPage() { }

    virtual void apply();

  private:
    PluginList          mPlugins;
    PluginConfigWidget* mPluginConfig;
    Part&               mPart;
    DisplayConfig*      mOptsPage;
  };

  class AudioConfigPage : public ConfigDialogPage
  {
  public:
    AudioConfigPage(const PluginList& plugins,
                    QWidget* parent=0, const char* name=0);
    virtual ~AudioConfigPage() { }

    virtual void apply();

  private:
    PluginConfigWidget* mPluginConfig;
  };

  class FileConfigPage : public ConfigDialogPage
  {
  public:
    FileConfigPage(const PluginList& plugins,
                   QWidget* parent=0, const char* name=0);
    virtual ~FileConfigPage() { }

    virtual void apply();

  private:
    PluginConfigWidget* mPluginConfig;
  };

  class EditConfigPage : public ConfigDialogPage
  {
  public:
    EditConfigPage(const PluginList& plugins,
                   QWidget* parent=0, const char* name=0);
    virtual ~EditConfigPage() { }

    virtual void apply();

  private:
    KListView*          mPluginList;
    PluginConfigWidget* mPluginConfig;
  };
}


using Sonik::PluginConfigWidget;
using Sonik::ConfigDialog;


Sonik::ConfigDialogPage::ConfigDialogPage(QWidget* parent, const char* name)
  : QWidget(parent, name)
{
}

Sonik::ConfigDialogPage::~ConfigDialogPage()
{
}


Sonik::PluginConfigWidget::PluginConfigWidget(const Sonik::PluginList& plugins,
                                              QWidget* parent, const char* name)
  : QWidget(parent, name),
    mPlugins(plugins)
{
  QVBoxLayout* layout = new QVBoxLayout(this,
                                        KDialog::marginHint(),
                                        KDialog::spacingHint());

  QValueList<QWidget*> pages;
  QStringList names;
  Sonik::PluginList::const_iterator it = mPlugins.begin(), e = mPlugins.end();
  for ( ; it != e; ++it)
  {
    QWidget* confPage = (*it)->makeConfigPage(this);
    if (confPage)
    {
      pages.append(confPage);
      names.append((*it)->displayName());
    }
  }

  if (!pages.empty())
  {
    QLabel* label = new QLabel(i18n("Plugin options"), this);
    layout->addWidget(label);
    QTabWidget* tabs = new QTabWidget(this, "plugin_tabs");
    layout->addWidget(tabs);
    QValueList<QWidget*>::iterator itP = pages.begin(), eP = pages.end();
    QStringList::const_iterator itN = names.begin(), eN = names.end();
    for ( ; itP != eP && itN != eN; ++itP, ++itN)
      tabs->addTab(*itP, *itN);
  }
}

void Sonik::PluginConfigWidget::apply()
{
  Sonik::PluginList::const_iterator it = mPlugins.begin();
  Sonik::PluginList::const_iterator e = mPlugins.end();
  for ( ; it != e; ++it)
    (*it)->applyConfigPage();
}


Sonik::GeneralConfigPage::GeneralConfigPage(QWidget* parent, const char* name)
  : ConfigDialogPage(parent, name)
{
//   QVBoxLayout* layout = new QVBoxLayout(this,
//                                         KDialog::marginHint(),
//                                         KDialog::spacingHint());
}

void Sonik::GeneralConfigPage::apply()
{
}


Sonik::DisplayConfigPage::DisplayConfigPage(const Sonik::PluginList& plugins,
                                            Part& part,
                                            QWidget* parent, const char* name)
  : ConfigDialogPage(parent, name),
    mPlugins(plugins),
    mPluginConfig(new PluginConfigWidget(plugins,
                                         this, "display_plugin_config")),
    mPart(part)
{
  QVBoxLayout* layout = new QVBoxLayout(this,
                                        KDialog::marginHint(),
                                        KDialog::spacingHint());
  mOptsPage = new DisplayConfig(this, "display_config");
  int activeIndex = -1;
  Sonik::PluginList::const_iterator it = mPlugins.begin(), e = mPlugins.end();
  for (int i = 0; it != e; ++it, ++i)
  {
    mOptsPage->defaultPlugin->insertItem((*it)->displayName());
    if ((*it)->pluginName() == PartSettings::defaultDisplay())
      activeIndex = i;
  }
  if (activeIndex != -1)
    mOptsPage->defaultPlugin->setCurrentItem(activeIndex);

  int timeFormatIndex;
  switch (PartSettings::defaultTimeFormat())
  {
    case kSamples:     timeFormatIndex = 0; break;
    case kH_M_S_Ms:    timeFormatIndex = 1; break;
    case kMs:          timeFormatIndex = 2; break;
    case kH_M_S_FCDDA: timeFormatIndex = 3; break;
    case kH_M_S_FPAL:  timeFormatIndex = 4; break;
    case kH_M_S_FNTSC: timeFormatIndex = 5; break;
    default:           timeFormatIndex = 0; break;
  }
  mOptsPage->defaultTimeFormat->setCurrentItem(timeFormatIndex);

  // TODO: disable according to display plugin
  int valueFormatIndex;
  switch (PartSettings::defaultValueScaleType())
  {
    case Sonik::kNormalised: valueFormatIndex = 0; break;
    case Sonik::kValue:      valueFormatIndex = 1; break;
    case Sonik::kValueDB:    valueFormatIndex = 2; break;
    default:                 valueFormatIndex = 0; break;
  }
  mOptsPage->defaultValueFormat->setCurrentItem(valueFormatIndex);

  layout->addWidget(mOptsPage);

  layout->addWidget(mPluginConfig);
}

void Sonik::DisplayConfigPage::apply()
{
  mPluginConfig->apply();

  mPart.setDefaultDisplay(
    mPlugins[mOptsPage->defaultPlugin->currentItem()]->pluginName()
    );

  TimeFormat timeFormat;
  switch (mOptsPage->defaultTimeFormat->currentItem())
  {
    case 0:  timeFormat = kSamples;     break;
    case 1:  timeFormat = kH_M_S_Ms;    break;
    case 2:  timeFormat = kMs;          break;
    case 3:  timeFormat = kH_M_S_FCDDA; break;
    case 4:  timeFormat = kH_M_S_FPAL;  break;
    case 5:  timeFormat = kH_M_S_FNTSC; break;
    default: timeFormat = kSamples;     break;
  }
  mPart.setTimeFormat(timeFormat);
  PartSettings::setDefaultTimeFormat(static_cast<int>(mPart.timeFormat()));


  ValueFormat valueFormat;
  switch (mOptsPage->defaultValueFormat->currentItem())
  {
    case 0:  valueFormat = kNormalised; break;
    case 1:  valueFormat = kValue;      break;
    case 2:  valueFormat = kValueDB;    break;
    default: valueFormat = kNormalised; break;
  }
  mPart.setValueFormat(valueFormat);
  PartSettings::setDefaultValueScaleType(static_cast<int>(mPart.valueFormat()));

  static_cast<Sonik::PartWidget*>(mPart.widget())->updateAll();
}


Sonik::AudioConfigPage::AudioConfigPage(const Sonik::PluginList& plugins,
                                        QWidget* parent, const char* name)
  : ConfigDialogPage(parent, name),
    mPluginConfig(new PluginConfigWidget(plugins,
                                         this, "audio_plugin_config"))
{
  QVBoxLayout* layout = new QVBoxLayout(this,
                                        KDialog::marginHint(),
                                        KDialog::spacingHint());
  layout->addWidget(mPluginConfig);
}

void Sonik::AudioConfigPage::apply()
{
  mPluginConfig->apply();
}


Sonik::FileConfigPage::FileConfigPage(const Sonik::PluginList& plugins,
                                      QWidget* parent, const char* name)
  : ConfigDialogPage(parent, name),
    mPluginConfig(new PluginConfigWidget(plugins,
                                         this, "file_plugin_config"))
{
  QVBoxLayout* layout = new QVBoxLayout(this,
                                        KDialog::marginHint(),
                                        KDialog::spacingHint());
  layout->addWidget(mPluginConfig);
}

void Sonik::FileConfigPage::apply()
{
  mPluginConfig->apply();
}


Sonik::EditConfigPage::EditConfigPage(const Sonik::PluginList& plugins,
                                      QWidget* parent, const char* name)
  : ConfigDialogPage(parent, name),
//     mPluginList(new KListView(this, "edit_plugins")),
    mPluginConfig(new PluginConfigWidget(plugins,
                                         this, "edit_plugin_config"))
{
  QVBoxLayout* layout = new QVBoxLayout(this,
                                        KDialog::marginHint(),
                                        KDialog::spacingHint());

//   mPluginList->addColumn(i18n("Enabled"));
//   mPluginList->addColumn(i18n("Name"));
//   mPluginList->setResizeMode(QListView::LastColumn);
//   Sonik::PluginList::const_iterator it = plugins.begin(), e = plugins.end();
//   for (; it != e; ++it)
//   {
//     QCheckListItem* item =
//       new QCheckListItem(mPluginList, QString::null,
//                          QCheckListItem::CheckBoxController);
//     QStringList::const_iterator f = PartSettings::disabledEditPlugins().find((*it)->pluginName());
//     item->setOn(f == PartSettings::disabledEditPlugins().end());
//     item->setText(1, (*it)->displayName());
//     item->setText(2, (*it)->pluginName());
//   }
//   layout->addWidget(mPluginList);

  layout->addWidget(mPluginConfig);
}

void Sonik::EditConfigPage::apply()
{
//   QStringList disabledPlugins;
//   for (QListViewItemIterator it(mPluginList); it.current(); ++it)
//   {
//     QCheckListItem *item = static_cast<QCheckListItem*>(it.current());
//     if (!item->isOn())
//       disabledPlugins.push_back(item->text(2));
//   }
//   PartSettings::setDisabledEditPlugins(disabledPlugins);
  // TODO: warn that changes won't take effect until next restart

  mPluginConfig->apply();
}


ConfigDialog::ConfigDialog(Part& p, QWidget* parent, const char* name)
  : KDialogBase(IconList, i18n("Preferences"),
                Help|Default|Ok|Apply|Cancel, Ok, parent, name, false),
    mPart(p)
{
  QVBox* page;

//   // General config
//   page = addVBoxPage(i18n("General"), i18n("General options"),
//                      SmallIcon("configure", KIcon::SizeMedium,
//                                KIcon::DefaultState, p.instance()));
//   mPages.push_back(new GeneralConfigPage(page, "general_config"));

  // Display plugins
  page = addVBoxPage(i18n("Display"), i18n("Display options"),
                     SmallIcon("konsole", KIcon::SizeMedium,
                               KIcon::DefaultState, p.instance()));
  mPages.push_back(new DisplayConfigPage(p.displayPlugins(), p,
                                         page, "display_config"));

//   // Audio plugins
//   page = addVBoxPage(i18n("Audio"), i18n("Audio options"),
//                      SmallIcon("kmix", KIcon::SizeMedium,
//                                KIcon::DefaultState, p.instance()));
//   mPages.push_back(new AudioConfigPage(p.audioIOPlugins(),
//                                        page, "audio_config"));

//   // File plugins
//   page = addVBoxPage(i18n("File"), i18n("File options"),
//                      SmallIcon("fileopen", KIcon::SizeMedium,
//                                KIcon::DefaultState, p.instance()));
//   mPages.push_back(new FileConfigPage(p.fileIOPlugins(),
//                                       page, "file_config"));

//   // Edit plugins
//   page = addVBoxPage(i18n("Edit"), i18n("Edit options"),
//                      SmallIcon("edit", KIcon::SizeMedium,
//                                KIcon::DefaultState, p.instance()));
//   mPages.push_back(new EditConfigPage(p.editPlugins(),
//                                       page, "edit_config"));
}

ConfigDialog::~ConfigDialog()
{
}

void ConfigDialog::slotOk()
{
  apply();
  QDialog::accept();
}

void ConfigDialog::slotApply()
{
  apply();
}

void ConfigDialog::apply()
{
  for (QValueList<ConfigDialogPage *>::iterator it = mPages.begin();
       it != mPages.end();
       ++it)
    (*it)->apply();

  PartSettings::writeConfig();
}
