/* ====================================================================
 * Copyright (c) 2003-2006, 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 "PropertiesDialog.h"
#include "WcModel.h"
#include "SyncCmdResult.h"
#include "ErrorSupport.h"
#include "commands/PropListParam.h"
#include "commands/PropSetParam.h"
#include "sublib/Gui.h"
#include "svn/Revision.h"
#include "svn/WcStatus.h"
#include "svn/WcEntry.h"
#include "svn/PropListItem.h"

// qt
#include <QtGui/QLayout>
#include <QtGui/QGroupBox>
#include <QtGui/QPushButton>
#include <QtGui/QListView>
#include <QtGui/QLabel>
#include <QtGui/QTextEdit>
#include <QtGui/QComboBox>
#include <QtGui/QCheckBox>
#include <QtCore/QRegExp>
//#include <QtGui/QToolTip>



static const char* KnownProperties[] =
{
  "svn:eol-style",
  "svn:executable",
  "svn:externals",
  "svn:ignore",
  "svn:keywords",
  "svn:mime-type",
  "svn:needs-lock",
  0
};


PropertiesDialog::PropertiesDialog( WcModel* model, QWidget *parent, const char *name )
: super( parent, name, true, Qt::WStyle_Customize | Qt::WStyle_Dialog |
  Qt::WStyle_NormalBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu ), _model(model)
{
  QVBoxLayout *vbl = new QVBoxLayout(this,5,8);
  vbl->setSpacing(10);
  {
    QGroupBox* gb = new QGroupBox(1,Qt::Vertical,this);
    gb->setTitle( _q("property options: ") );
    gb->setInsideSpacing(10);
    gb->setInsideMargin(0);
    gb->setFlat(true);
    vbl->addWidget(gb);

    QHBoxLayout* hb = new QHBoxLayout(vbl);
    {
      QVBoxLayout* vb1 = new QVBoxLayout(hb);
      hb->setStretchFactor( vb1, 2 );
      {
        _props = new QListView(this);
        _props->setTreeStepSize(11);
        _props->setRootIsDecorated(true);
        _props->setShowToolTips(true);
        _props->addColumn( _q("properties") );
        _props->setResizeMode( QListView::LastColumn );
        vb1->addWidget(_props);

        //connect( _props, SIGNAL(pressed(QListViewItem*)), SLOT(pressed(QListViewItem*)) );
        connect( _props, SIGNAL(selectionChanged(QListViewItem*)), SLOT(pressed(QListViewItem*)) );

        _newProp = new QComboBox(this);
        _newProp->setEditable(true);
        _newProp->setAutoCompletion(true);
        _newProp->setDuplicatesEnabled(false);
        _newProp->setInsertionPolicy( QComboBox::AtTop );
        _newProp->insertStrList( KnownProperties, -1, 1 );
        vb1->addWidget(_newProp);

        connect( _newProp, SIGNAL(textChanged(const QString&)), SLOT(newPropChanged(const QString&)) );

        QHBoxLayout* h = new QHBoxLayout(vb1);
        {
          //h->addStretch(1);

          _add = new QPushButton( _q("&New"), this );
          _add->setEnabled(false);
          h->addWidget(_add);

          connect( _add, SIGNAL(pressed()), SLOT(add()) );
        }
      }

      QVBoxLayout* vb2 = new QVBoxLayout(hb);
      hb->setStretchFactor( vb2, 5 );
      {
        _propValue = new QTextEdit(this);
        _propValue->setWordWrap(QTextEdit::NoWrap);
        _propValue->setReadOnly(true);
        QLabel* l  = new QLabel( _propValue, _q("Property Value"), this );

        vb2->addWidget(l);
        vb2->addWidget(_propValue);

        QHBoxLayout* h = new QHBoxLayout(vb2);
        {
          h->addStretch(1);

          _recursive = new QCheckBox( _q("&recursive"), this );
          h->addWidget(_recursive);

          _set = new QPushButton( _q("&Set"), this );
          _set->setEnabled(false);
          h->addWidget(_set);

          _del = new QPushButton( _q("&Delete"), this );
          _del->setEnabled(false);
          h->addWidget(_del);

          connect( _set, SIGNAL(pressed()), SLOT(set()) );
          connect( _del, SIGNAL(pressed()), SLOT(del()) );
        }
      }
    }

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

      _close = new QPushButton(this);
      _close->setEnabled(true);
      _close->setText( _q("&Done") );
      _close->setDefault(true);
      hu->addWidget(_close);
      
      hu->addSpacing(getSizeGripSpacing());
      
      connect( _close, SIGNAL(clicked()), SLOT(accept()) );
    }
  }

  resize( 500, 400 );
}

PropertiesDialog::~PropertiesDialog()
{
}

void PropertiesDialog::setSource( svn::WcStatusPtr status )
{
  _status = status;
  _source = _status->getName();
  setCaption( _q("subcommander:properties (%1)").arg((const char*)_source) );

  if( _status->getWcEntry() )
  {
    _recursive->setEnabled( status->getWcEntry()->isDir() );
  }

  proplist();
}

void PropertiesDialog::pressed( QListViewItem* lvi )
{
  // no lvi pressed?
  if( ! lvi )
  {
    return;
  }

  // Leaf item?
  if( lvi->isExpandable() )
  {
    // no
    _propValue->setReadOnly(true);
    _propValue->clear();
    _set->setEnabled(false);
    _del->setEnabled(false);
    return;
  }

  // yes
  _propValue->setEnabled(true);
  _propValue->setReadOnly(false);
  _propValue->setText( lvi->text(1) );
  _newProp->setCurrentText( lvi->text(0) );
  _set->setEnabled(true);
  _del->setEnabled(true);
}

void PropertiesDialog::newPropChanged(const QString& newVal )
{
  // check if the property alrady exists
  QListViewItem* lvi = _props->findItem( _newProp->currentText(), 0 );
  if( ! lvi )
  {
    _add->setEnabled(true);
  }
  else
  {
    _add->setEnabled(false);
  }
}

void PropertiesDialog::add()
{
#if 0
  static const sc::String propInit("(new property value)");

  PropSetParam* param = new PropSetParam( sc::String(_newProp->currentText().utf8()),
    propInit, _source, _recursive->isChecked() );

  SyncCmdResult res;
  _model->propset( param, &res, false );

  if( res.getError() )
  {
    handleErrorSync(res.getError(),this);
    return;
  }
#endif

  addProperty( _newProp->currentText(), "" );

  QListViewItem* lvi = _props->findItem( _newProp->currentText(), 0 );
  _props->setCurrentItem(lvi);

  _add->setEnabled(false);
  _del->setEnabled(true);
}

void PropertiesDialog::del()
{
  QListViewItem* curr  = _props->currentItem();
  QListViewItem* above = curr->itemAbove();
  QString        prop  = curr->text(0);

  PropSetParam* param = new PropSetParam( sc::String(prop.utf8()),
    sc::String(), _source, _recursive->isChecked() );

  SyncCmdResult res;
  _model->propset( param, &res, false );

  if( res.getError() )
  {
    handleError(res.getError(),this);
    return;
  }


  curr->parent()->takeItem(curr);
  delete curr;

  _propValue->setReadOnly(true);
  _propValue->clear();

  _del->setEnabled(false);
  _add->setEnabled(true);

  _props->setSelected(above,true);
  pressed(above);
}

void PropertiesDialog::set()
{
  QListViewItem* curr  = _props->currentItem();
  QString        prop  = curr->text(0);

  PropSetParam* param = new PropSetParam( sc::String(curr->text(0).utf8()),
    sc::String(_propValue->text().utf8()), _source, _recursive->isChecked() );

  SyncCmdResult res;
  _model->propset( param, &res, false );

  if( res.getError() )
  {
    handleError(res.getError(),this);
    return;
  }

  curr->setText( 1, _propValue->text() );
}

void PropertiesDialog::addProperty( const QString& propName, const QString& propValue )
{
  QRegExp exp("^(.+):(.+)$");

  if( exp.exactMatch(propName) )
  {
    QListViewItem* lvi = _props->findItem( exp.cap(1), 0 );
    if( ! lvi )
    {
      lvi = new QListViewItem( _props, exp.cap(1) );
      lvi->setExpandable(true);
      lvi->setOpen(true);
    }
    new QListViewItem( lvi, propName, propValue );
  }
  else
  {
    new QListViewItem( _props, propName, propValue );
  }
}

void PropertiesDialog::proplist()
{
  _props->clear();

  PropListParam* param = new PropListParam( _source,
    new svn::Revision(svn::Revision_Unspecified), false );

  SyncCmdResult res;
  _model->proplist( param, &res, false );

  if( res.getError() )
  {
    handleError(res.getError(),this);
    return;
  }

  svn::PropListItems& props = param->getItems();

  for( svn::PropListItems::iterator it = props.begin(); it != props.end(); it++ )
  {
    svn::PropListItemPtr            item  = *it;
    const svn::PropListItem::Props& props = item->getProps();

    for( svn::PropListItem::Props::const_iterator it = props.begin(); it != props.end(); it++ )
    {
      QString propName  = QString::fromUtf8((*it).first);
      QString propValue = QString::fromUtf8((*it).second);

      addProperty( propName, propValue );
    }
  }
}
