/* ====================================================================
 * 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 "MergeDialog.h"
#include "MergeViewModel.h"
#include "RevisionWidget.h"
#include "ExternProvider.h"
#include "Settings.h"
#include "sublib/Gui.h"
#include "sublib/ExternButton.h"
#include "sublib/settings/LayoutSettings.h"

// qt
#include <QtGui/QLayout>
#include <QtGui/QPushButton>
#include <QtGui/QLabel>
#include <QtGui/QComboBox>
#include <QtGui/QFileDialog>
#include <QtGui/QToolTip>
#include <QtGui/QCheckBox>
#include <QtGui/QRadioButton>
#include <Qt3Support/Q3GroupBox>
#include <Qt3Support/Q3HBox>

// sys
#include <assert.h>



MergeDialog::MergeDialog( MergeViewModel* model, ExternProvider* p, QWidget *parent )
: super(parent,0), _model(model), _p(p)
{
  setWindowFlags( windowFlags() | Qt::WDestructiveClose );

  setName( "MergeDialog" );
  setCaption( _q("subcommander:merge") );

  QVBoxLayout *vbl = new QVBoxLayout(this,5,8);
  vbl->setSpacing(10);
  {
    Q3GroupBox* gb = new Q3GroupBox(1,Qt::Vertical,this);
    gb->setTitle( _q("merge options: ") );
    gb->setInsideMargin(0);
    gb->setFlat(true);
    vbl->addWidget(gb);

    QGridLayout* gl = new QGridLayout(vbl,4,4);
    gl->setMargin(0);
    gl->setColStretch( 0, 0 );
    gl->setColStretch( 1, 0 );
    gl->setColStretch( 2, 2 );
    gl->setColStretch( 3, 0 );
    {
      {
        _rep1L = new QLabel(this);
        _rep1  = new QComboBox(this);
        _rep1B = new ExternButton(this);

        _rep1L->setBuddy(_rep1);
        _rep1L->setText( _q("&source:") );
        _rep1->setEditable(true);
        _rep1->setAutoCompletion(true);

        gl->addWidget( _rep1L, 1, 1 );
        gl->addWidget( _rep1,  1, 2 ); 
        gl->addWidget( _rep1B, 1, 3 ); 

        connect( _rep1, SIGNAL(activated(const QString&)),   SLOT(checkOk(const QString&)) );
        connect( _rep1, SIGNAL(highlighted(const QString&)), SLOT(checkOk(const QString&)) );
        connect( _rep1, SIGNAL(textChanged(const QString&)), SLOT(checkOk(const QString&)) );
        connect( _rep1, SIGNAL(textChanged(const QString&)), SLOT(rep1Changed(const QString&)) );
        connect( _rep1B, SIGNAL(clicked()), SLOT(selectRep1Url()) );

        QToolTip::add( _rep1, _q("source for a merge of a revision range") );
      }
      {
        _type  = new QCheckBox(this);
        _rep2L = new QLabel(this);
        _rep2  = new QComboBox(this);
        _rep2B = new ExternButton(this);

        _rep2L->setBuddy(_rep2);
        _rep2L->setText( _q("&second source:") );
        _rep2->setEditable(true);
        _rep2->setAutoCompletion(true);

        gl->addWidget( _type,  2, 0 );
        gl->addWidget( _rep2L, 2, 1 );
        gl->addWidget( _rep2,  2, 2 ); 
        gl->addWidget( _rep2B, 2, 3 ); 

        connect( _type, SIGNAL(toggled(bool)), SLOT(changedMergeType(bool)) );
        connect( _rep2, SIGNAL(activated(const QString&)),   SLOT(checkOk(const QString&)) );
        connect( _rep2, SIGNAL(highlighted(const QString&)), SLOT(checkOk(const QString&)) );
        connect( _rep2, SIGNAL(textChanged(const QString&)), SLOT(checkOk(const QString&)) );
        connect( _rep2, SIGNAL(textChanged(const QString&)), SLOT(rep2Changed(const QString&)) );
        connect( _rep2B, SIGNAL(clicked()), SLOT(selectRep2Url()) );

        QToolTip::add( _rep2, _q("second source for a merge with two sources") );

        _rep2L->setEnabled(false);
        _rep2->setEnabled(false);
        _rep2B->setEnabled(false);
      }

      QHBoxLayout* h0 = new QHBoxLayout;
      gl->addMultiCellLayout( h0, 3, 3, 0, 3 );
      {
        _rwPeg = new RevisionWidget(true,"NDS","HBCP",0,this);
        _rwPeg->setTitle( _q("source peg revision:") );
        h0->addWidget(_rwPeg);

        connect( 
          _rwPeg, SIGNAL(revChanged(svn::RevisionPtr)),
          _model, SLOT(setRevisionPeg(svn::RevisionPtr)));
      }

      QHBoxLayout* h1 = new QHBoxLayout;
      gl->addMultiCellLayout( h1, 4, 4, 0, 3 );
      {
        _rw1 = new RevisionWidget(false,"NDS","HBCP",0,this);
        _rw1->setTitle( _q("source from revision:") );
        h1->addWidget(_rw1);

        _rw2 = new RevisionWidget(false,"NDS","HBCP",0,this);
        _rw2->setTitle( _q("source to revision:") );
        h1->addWidget(_rw2);

        connect( 
          _rw1, SIGNAL(revChanged(svn::RevisionPtr)),
          _model, SLOT(setRevision1(svn::RevisionPtr)));
        connect( 
          _rw2, SIGNAL(revChanged(svn::RevisionPtr)),
          _model, SLOT(setRevision2(svn::RevisionPtr)));
      }

      {
        QLabel* l       = new QLabel(this);
        _wc             = new QComboBox(this);
        QPushButton* pb = new ExternButton(this);

        l->setBuddy(pb);
        l->setText( _q("destination &working copy path:") );
        l->setFixedWidth( l->sizeHint().width() );
        _wc->setEditable(true);
        _wc->setAutoCompletion(true);
        _wc->setDuplicatesEnabled(false);

        gl->addMultiCellWidget( l, 5, 5, 0, 1 );
        gl->addWidget( _wc, 5, 2 ); 
        gl->addWidget( pb,  5, 3 ); 

        connect( _wc, SIGNAL(activated(const QString&)),   SLOT(checkOk(const QString&)) );
        connect( _wc, SIGNAL(highlighted(const QString&)), SLOT(checkOk(const QString&)) );
        connect( _wc, SIGNAL(textChanged(const QString&)), SLOT(checkOk(const QString&)) );
        connect( _wc, SIGNAL(textChanged(const QString&)), SLOT(wcChanged(const QString&)) );

        connect( pb, SIGNAL(clicked()), SLOT(selectWcPath()) );

        QToolTip::add( _wc, _q("the working copy where the merge should take place") );
      }
    }

    QHBoxLayout* h1 = new QHBoxLayout;
    vbl->addLayout(h1);
    {
      _recurse = new QCheckBox( _q("&recursive"), this );
      _recurse->setChecked(model->getRecursive());
      h1->addWidget(_recurse);

      _ancestry = new QCheckBox( _q("&ancestry"), this );
      _ancestry->setChecked(model->getCopies());
      h1->addWidget(_ancestry);

      _force = new QCheckBox( _q("&force"), this );
      _force->setChecked(model->getForce());
      h1->addWidget(_force);

      h1->addStretch(1); 

      connect( _recurse, SIGNAL(toggled(bool)), _model, SLOT(setRecursive(bool)) );
      connect( _ancestry, SIGNAL(toggled(bool)), _model, SLOT(setCopies(bool)) );
      connect( _force, SIGNAL(toggled(bool)), _model, SLOT(setForce(bool)) );
    }

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

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

      _dry = new QPushButton(this);
      _dry->setText( _q("&DryRun") );
      hu->addWidget(_dry);

      QPushButton* ca = new QPushButton(this);
      ca->setText( _q("&Cancel") );
      hu->addWidget(ca);

      hu->addSpacing(getSizeGripSpacing());
      
      connect( _ok, SIGNAL(clicked()), SLOT(accept()) );
      connect( _dry, SIGNAL(clicked()), SLOT(dryrun()) );
      connect( ca, SIGNAL(clicked()), SLOT(reject()) );
    }
  }

  _rep1->insertItem( QString::fromUtf8(_model->getPathOrUrl1()), 0 );
  _rep2->insertItem( QString::fromUtf8(_model->getPathOrUrl2()), 0 );
  _rw1->setRevision( _model->getRevision1() );
  _rw2->setRevision( _model->getRevision2() );
  enablePathOrUrl1( _model->getChangePathOrUrl1() );
  enablePathOrUrl2( _model->getChangePathOrUrl2() );
  enableTypeChange( _model->getChangeType() );

  const svn::Paths& targets = _model->getTargets();
  for( svn::Paths::const_iterator it = targets.begin(); it != targets.end(); it++ )
  {
    _wc->insertItem( QString::fromUtf8(*it), 0 );
  }
  _wc->setCurrentText( QString::fromUtf8(_model->getDefaultTarget()) );

  Settings s;
  resize( s.layout().getSize( name(), QSize(width(),height()) ) );

  // don't resize vertically.
  setMaximumHeight( sizeHint().height() );
}

MergeDialog::~MergeDialog()
{
  Settings s;
  s.layout().setSize( name(), geometry().size() );

  delete _model;
  delete _p;
}

void MergeDialog::rep1Changed( const QString& rep )
{
  _model->setPathOrUrl1( sc::String(rep.utf8()) );
}

void MergeDialog::rep2Changed( const QString& rep )
{
  _model->setPathOrUrl2( sc::String(rep.utf8()) );
}

void MergeDialog::wcChanged( const QString& rep )
{
  _model->setTarget( sc::String(rep.utf8()) );
}

void MergeDialog::changedMergeType( bool b )
{
  if( ! b )
  {
    _rep2L->setEnabled(false);
    _rep2->setEnabled(false);
    _rep2B->setEnabled(false);

    _rwPeg->setEnabled(true);
    _model->setPegMerge(true);

    _rep1L->setText( _q("&source:") );
    QToolTip::add( _rep1, _q("source for a merge of a revision range") );
    _rw1->setTitle( _q("source from revision:") );
    _rw2->setTitle( _q("source to revision:") );
  }
  else if( b )
  {
    _rep2L->setEnabled(true);
    _rep2->setEnabled(true);
    _rep2B->setEnabled(true);

    _rwPeg->setEnabled(false);
    _model->setPegMerge(false);

    _rep1L->setText( _q("&first source:") );
    QToolTip::add( _rep1, _q("first source for a merge with two sources") );
    _rw1->setTitle( _q("first source revision:") );
    _rw2->setTitle( _q("second source revision:") );
  }

  checkOk( "" );
}

void MergeDialog::selectRep1Url()
{
  sc::String res;

  if( _p->selectUrl( this, sc::String(_rep1->currentText().utf8()), res, ExternProvider::Dir) )
  {
    _rep1->insertItem( QString::fromUtf8(res), 0 );
  }
}

void MergeDialog::selectRep2Url()
{
  sc::String res;

  if( _p->selectUrl( this, sc::String(_rep2->currentText().utf8()), res, ExternProvider::Dir) )
  {
    _rep2->insertItem( QString::fromUtf8(res), 0 );
  }
}

void MergeDialog::selectWcPath()
{
  sc::String res;

  if( _p->selectPath( this, sc::String(_wc->currentText().utf8()), res) )
  {
    _wc->insertItem( QString::fromUtf8(res), 0 );
  }
}

void MergeDialog::checkOk( const QString& text )
{
  QString rep1 = _rep1->currentText();
  QString rep2 = _rep2->currentText();
  QString wc   = _wc->currentText();

  //if( _rbGroup->selectedId() == rbOneSource )
  if( ! _type->isChecked() )
  {
    _ok->setEnabled( ! rep1.isEmpty() && ! wc.isEmpty() );
    _dry->setEnabled( ! rep1.isEmpty() && ! wc.isEmpty() );
  }
  //else if( _rbGroup->selectedId() == rbTwoSources )
  else if( _type->isChecked() )
  {
    _ok->setEnabled( ! rep1.isEmpty() && ! rep2.isEmpty() && ! wc.isEmpty() );
    _dry->setEnabled( ! rep1.isEmpty() && ! rep2.isEmpty() && ! wc.isEmpty() );
  }
  else
  {
    assert(false);
  }
}

void MergeDialog::accept()
{
  _model->merge();
  close();
}

void MergeDialog::reject()
{
  close();
}

void MergeDialog::dryrun()
{
  _model->dryrun();
}

void MergeDialog::enablePathOrUrl1( bool enable )
{
  _rep1->setEnabled(enable);
  _rep1B->setEnabled(enable);
}

void MergeDialog::enablePathOrUrl2( bool enable )
{
  _rep2L->setEnabled(enable);
  _rep2->setEnabled(enable);
  _rep2B->setEnabled(enable);
  _type->setChecked(enable);
}

void MergeDialog::enableTypeChange( bool enable )
{
  _type->setEnabled(enable);
}
