/* ====================================================================
 * 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 "RepositoryDialog.h"
#include "RepoModel.h"
#include "CursorSupport.h"
#include "Settings.h"
#include "sublib/Gui.h"
#include "sublib/Utility.h"
#include "sublib/settings/LayoutSettings.h"
#include "svn/DirEntry.h"
#include "svn/Path.h"

// qt
#include <QtGui/QLayout>
#include <QtGui/QPushButton>
#include <QtCore/QRegExp>
#include <QtCore/QTimer>
#include <QtGui/QComboBox>
#include <QtGui/QLabel>
#include <QtGui/QLineEdit>
#include <Qt3Support/Q3ProgressBar>
#include <Qt3Support/Q3ListView>
#include <Qt3Support/Q3Header>


RepositoryDialog::RepositoryDialog( RepoModel* model, QWidget *parent )
  : super( parent, 0, true, Qt::WStyle_Customize | Qt::WStyle_Dialog |
  Qt::WStyle_NormalBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu  ),
  _model(model)
{
  setName( "RepositoryDialog" );
  setCaption( _q("subcommander:select repository url") );
  _dirsOnly = false;

  _folder = new QPixmap( getIconDir() + "FolderSvn.png" );
  _timer  = new QTimer();

  connect( _timer, SIGNAL(timeout()), this, SLOT(timeout()) );

  QVBoxLayout *vbl = new QVBoxLayout(this,5,8);
  vbl->setSpacing(10);

  QHBoxLayout* hbl = new QHBoxLayout;
  vbl->addLayout(hbl);
  {
    QLabel* l = new QLabel( _q("URL:"), this);
    hbl->addWidget(l);

    _edit = new QComboBox(this);
    _edit->setEditable(true);
    hbl->addWidget(_edit,1);

    connect(
      _edit->lineEdit(), SIGNAL(returnPressed()),
      this, SLOT(editChanged()) );
  }

  {
    QGridLayout* gl = new QGridLayout(vbl,1,1);
    {
      _list = new Q3ListView(this);
      _list->setRootIsDecorated(true);
      _list->setAllColumnsShowFocus(true);
      _list->addColumn( _q("url") );
      _list->setResizeMode( Q3ListView::LastColumn );

      connect( _list, SIGNAL(selectionChanged(Q3ListViewItem*)),
        this, SLOT(selectionChanged(Q3ListViewItem*)) );

      connect( _list, SIGNAL(expanded(Q3ListViewItem*)),
        this, SLOT(expanded(Q3ListViewItem*)) );

      gl->addWidget(_list,0,0);
    }

    QHBoxLayout* hu = new QHBoxLayout;
    vbl->addLayout(hu);
    {
      _progress = new Q3ProgressBar(this);
      _progress->setCenterIndicator(true);
      _progress->setTotalSteps(0);
      hu->addWidget(_progress);

      _parent = new QPushButton( _q("up"), this);
      _parent->setEnabled(true);
      hu->addWidget(_parent);

      connect( _parent, SIGNAL(clicked()), this, SLOT(parent()) );

      // eats extra space, so the buttons keep their size
      hu->addStretch(1); 

      QPushButton* ok = new QPushButton(this);
      ok->setText( _q("&Ok") );
      ok->setDefault(true);
      hu->addWidget(ok);
      QPushButton* ca = new QPushButton(this);
      ca->setText( _q("&Cancel") );
      hu->addWidget(ca);
      
      hu->addSpacing(getSizeGripSpacing());

      connect( ok, SIGNAL(clicked()), SLOT(accept()) );
      connect( ca, SIGNAL(clicked()), SLOT(reject()) );
    }
  }

  connect( _model, SIGNAL(doneRoot()), this, SLOT(rooted()) );
  connect( _model, SIGNAL(doneList(const sc::String&)), this,
    SLOT(listed(const sc::String&)) );

  _timer->start(100);
  _model->root();

  setDisabled(true);
  setWaitCursor();

  Settings s;
  resize( s.layout().getSize( name(), QSize(300,400) ) );
}

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

  delete _timer;
  delete _folder;
}

void RepositoryDialog::rooted()
{
  restoreCursor();
  setDisabled(false);

  _timer->stop();
  _progress->reset();

  QString root = QString::fromUtf8(_model->getUrl());
  _edit->setCurrentText(root);

  Q3ListViewItem* lvi = new Q3ListViewItem( _list, root, root );
  lvi->setPixmap(0,getFolderPixmap());
  lvi->setExpandable(true);
}

void RepositoryDialog::listed( const sc::String& url )
{
  restoreCursor();
  setDisabled(false);

  _timer->stop();
  _progress->reset();

  svn::DirEntries entries;
  _model->getEntries( url, entries );

  if( entries.size() > 0 )
  {
    _list->setOpen( _expanded, true );
  }
  else
  {
    _expanded->setExpandable(false);
  }

  for( svn::DirEntries::iterator it = entries.begin(); it != entries.end(); it++ )
  {
    svn::DirEntryPtr e = *it;

    if( e->isDir() || ! showDirsOnly() )
    {
      QString stripped = QString::fromUtf8(e->getName());
      stripped.remove( 0, (uint)url.getCharCnt()+1 );

      Q3ListViewItem* lvi = new Q3ListViewItem(
        _expanded, stripped, QString::fromUtf8(e->getName()) );

      if( e->isDir() )
      {
        lvi->setPixmap(0,getFolderPixmap());
        lvi->setExpandable(true);
      }
    }
  }
}

void RepositoryDialog::timeout()
{
  _progress->setProgress(_progress->progress()+1);
}

void RepositoryDialog::setDirsOnly( bool b )
{
  _dirsOnly = b;
}

bool RepositoryDialog::showDirsOnly()
{
  return _dirsOnly;
}

sc::String RepositoryDialog::getSelection() const
{
  // return full url from hidden column
  return sc::String(_list->selectedItem()->text(1).utf8());
}

void RepositoryDialog::editChanged()
{
  sc::String url = sc::String(_edit->currentText().utf8());

  if( ! svn::Path::isUrl(url) )
  {
    // TODO error and return
  }

  _list->clear();
  _model->setUrl(url);
  _model->root();

  setDisabled(true);
  setWaitCursor();
}

void RepositoryDialog::selectionChanged( Q3ListViewItem* lvi )
{
  if( !lvi )
    return;

  _edit->setCurrentText(lvi->text(1));
}

void RepositoryDialog::expanded( Q3ListViewItem* lvi )
{
  if( !lvi )
    return;

  sc::String url = sc::String(lvi->text(1).utf8());

  if( _model->isListed(url) )
    return;

  _expanded = lvi;
  _timer->start(100);
  _model->list(url);

  setDisabled(true);
  setWaitCursor();
}

void RepositoryDialog::parent()
{
  sc::String parent = _model->parent();

  if( parent.isEmpty() )
   return;

  _list->clear();
  _model->setUrl(parent);
  _model->root();

  setDisabled(true);
  setWaitCursor();
}

const QPixmap& RepositoryDialog::getFolderPixmap() const
{
  return *_folder;
}
