/* ====================================================================
 * Copyright (c) 2003-2007, Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 */

// sc
#include "config.h"
#include "SettingsDialog.h"
#include "settings/SettingsWidget.h"
#include "SettingsInfo.h"
#include "sublib/Gui.h"
#include "util/Compare.h"

// qt
#include <QtGui/QLayout>
#include <QtGui/QPainter>
#include <QtGui/QStackedWidget>
#include <QtGui/QPushButton>
#include <QtGui/QGroupBox>
#include <QtGui/QTreeWidget>
#include <QtGui/QTreeWidgetItem>


class SettingsLvi : public QTreeWidgetItem
{
  typedef QTreeWidgetItem super;

public:
  SettingsLvi( SettingsInfo* info, QTreeWidget* tw )
    : super( tw, QTreeWidgetItem::UserType ), _info(info)
  {
    setText( 0, info->getTitle() );
  }

  SettingsLvi( SettingsInfo* info, QTreeWidgetItem* twi )
    : super( twi, QTreeWidgetItem::UserType ), _info(info)
  {
    setText( 0, info->getTitle() );
  }

  void updateBackground()
  {
    if( isModified() )
      setBackground( 0, QColor(200,200,230) );
    else
      setBackground( 0, Qt::transparent );

    SettingsLvi* p = dynamic_cast<SettingsLvi*>(parent());
    if( p )
      p->updateBackground();
  }

  SettingsInfo* getInfo() const
  {
    return _info;
  }

  bool isModified() const
  {
    bool modified = _info->isModified();

    if( isExpanded() == false )
    {
      for( int i = 0; i < childCount(); i++ )
      {
        SettingsLvi* item = dynamic_cast<SettingsLvi*>(child(i));

        modified |= item->isModified();
      }
    }

    return modified;
  }

  bool operator<( const QTreeWidgetItem& other ) const
  {
    const SettingsLvi& lvi = dynamic_cast<const SettingsLvi&>(other);
    return getInfo()->getSortIndex() < lvi.getInfo()->getSortIndex();
  }

private:
  SettingsInfo* _info;
};





SettingsDialog::SettingsDialog( const QString& title, QWidget *parent )
  : super( parent), _curInfo(0)
{
  setWindowTitle( title );

  QVBoxLayout *vbl = new QVBoxLayout(this);
  vbl->setContentsMargins(5,5,5,5);
  vbl->setSpacing(10);
  {
    QGridLayout* gl = new QGridLayout();
    vbl->addLayout(gl);
    gl->setMargin(5);
    gl->setSpacing(10);
    {
      _categories = new QTreeWidget(this);
      gl->addWidget( _categories, 0, 0 );
      gl->setColumnStretch( 0, 1 );
      {
        _categories->setRootIsDecorated(true);
        _categories->setIndentation(11);
        _categories->setColumnCount(1);
        _categories->setHeaderLabels( QStringList() << _q("category") );
        _categories->setAllColumnsShowFocus(true);
      }
      connect( 
        _categories, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
        this,        SLOT(itemClicked(QTreeWidgetItem*,int)) );

      _box = new QGroupBox(this);
      _box->setTitle( _q("no settings selected: ") );
      QHBoxLayout* boxl = new QHBoxLayout(_box);
      gl->addWidget( _box, 0, 1 );
      gl->setColumnStretch( 1, 4 );
      {
        _stack = new QStackedWidget(_box);
        _stack->setSizePolicy( QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding) );
        boxl->addWidget(_stack);
        {
          _stack->addWidget( new QWidget() );
        }
      }
    }

    QHBoxLayout* hl = new QHBoxLayout;
    vbl->addLayout( hl );
    {
      // eats up any extra space, so the buttons keep their size
      hl->addStretch(1); 

      _ok = new QPushButton(this);
      _ok->setText( _q("&Ok") );
      //_ok->setDefault(true);
      _ok->setEnabled(false);
      hl->addWidget(_ok);

      _apply = new QPushButton(this);
      _apply->setText( _q("&Apply") );
      _apply->setEnabled(false);
      hl->addWidget(_apply);

      QPushButton* ca = new QPushButton(this);
      ca->setDefault(true);
      ca->setFocus();
      ca->setText( _q("&Close") );
      hl->addWidget(ca);

      hl->addSpacing(getSizeGripSpacing());

      connect( _ok,    SIGNAL(clicked()), SLOT(ok()) );
      connect( _apply, SIGNAL(clicked()), SLOT(apply()) );
      connect( ca,     SIGNAL(clicked()), SLOT(cancel()) );
    }
  }
}

SettingsDialog::~SettingsDialog()
{
}

void SettingsDialog::addSettingsInfo( SettingsInfo* info, const QString& parentTitle )
{
  SettingsLvi* lvi = 0;

  Lvis::iterator it = _lvis.find( parentTitle );
  if( it == _lvis.end() )
  {
    // toplevel..
    lvi = new SettingsLvi( info, _categories );
  }
  else
  {
    // childlevel..
    lvi = new SettingsLvi( info, (*it).second );
  }

  _lvis.insert( Lvis::value_type(info->getTitle(),lvi) );

  if( info->getSelected() )
  {
    lvi->setSelected(true);
    itemClicked(lvi,0);

    QTreeWidgetItem* p = lvi;
    if( (p = p->parent()) )
    {
      p->setExpanded(true);
    }
  }
}

void SettingsDialog::addSettingsWidget( const QString& settingsId, SettingsWidget* sw )
{
  _stack->addWidget( sw );
  _widgets.insert( Widgets::value_type(settingsId,sw) );

  connect( sw, SIGNAL(modified()), SLOT(modified()) );
}


void SettingsDialog::ok()
{
  for( Lvis::iterator it = _lvis.begin(); it != _lvis.end(); it++ )
  {
    SettingsLvi* lvi = (*it).second;
    lvi->getInfo()->ok();
  }

  accept();
}

void SettingsDialog::apply()
{
  _curInfo->apply();
  modified();
}

void SettingsDialog::cancel()
{
  for( Lvis::iterator it = _lvis.begin(); it != _lvis.end(); it++ )
  {
    SettingsLvi* lvi = (*it).second;
    lvi->getInfo()->cancel();
  }

  reject();
}

void SettingsDialog::modified()
{
  _curInfo->storeWidgetData( (SettingsWidget*)_stack->currentWidget() );

  _apply->setEnabled(_curInfo->isModified());
  _ok   ->setEnabled(isModified());

  Lvis::iterator it = _lvis.find( _curInfo->getTitle() );
  if( it != _lvis.end() )
  {
    (*it).second->updateBackground();
  }
}

bool SettingsDialog::isModified()
{
  bool modified = false;

  for( Lvis::iterator it = _lvis.begin(); it != _lvis.end(); it++ )
  {
    SettingsLvi* lvi = (*it).second;

    modified |= lvi->isModified();
  }

  return modified;
}

void SettingsDialog::itemClicked( QTreeWidgetItem* item, int col )
{
  if( ! item )
  {
    return;
  }

  // remember data from current SettingsWidget..
  if( _curInfo )
  {
    SettingsWidget* sw = (SettingsWidget*)_stack->currentWidget();
    _curInfo->storeWidgetData( sw );
  }

  // set new SettingsWidget...
  SettingsLvi*  lvi  = (SettingsLvi*)item;
  SettingsInfo* info = lvi->getInfo();

  _apply->setDisabled( ! info->isModified() );

  Widgets::iterator it = _widgets.find( info->getSettingsId() );
  if( it == _widgets.end() )
  {
    _box->setTitle( _q("no settings selected: ") );
    _stack->setCurrentWidget( _stack->widget(0) );
    _curInfo = 0;
  }
  else
  {
    SettingsWidget* sw = (*it).second;

    _box->setTitle( info->getSettingsId() + ": " );

    _curInfo = info;
    _stack->setCurrentWidget( sw );
    info->initWidgetData( sw );
  }
}
