/* ====================================================================
 * 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 "PropertiesDialog2.h"
#include "WcViewModel.h"
#include "Settings.h"
#include "commands/PropSetParam.h"
#include "sublib/Gui.h"
#include "sublib/settings/LayoutSettings.h"
#include "svn/PropListItem.h"

// qt
#include <QtGui/QLayout>
#include <QtGui/QPushButton>
#include <QtGui/QLabel>
#include <QtGui/QTextEdit>
#include <QtGui/QCheckBox>
#include <QtCore/QRegExp>
//#include <QtGui/QToolTip>
#include <Qt3Support/Q3GroupBox>
#include <Qt3Support/Q3ListView>
#include <Qt3Support/Q3ComboBox>
#include <Qt3Support/Q3Header>



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


PropertiesDialog2::PropertiesDialog2( const sc::String& iname, bool dir,
  WcViewModel* model, QWidget *parent )
: super( parent, NULL, true, Qt::WStyle_Customize | Qt::WStyle_Dialog | 
  Qt::WStyle_NormalBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu ),
  _name(iname), _dir(dir), _model(model)
{
  setName( "PropertiesDialog" );
  setCaption( _q("subcommander:properties (%1)").arg(QString::fromUtf8(_name)) );

  QVBoxLayout *vbl = new QVBoxLayout(this,5,8);
  vbl->setSpacing(10);
  {
    Q3GroupBox* gb = new Q3GroupBox(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 Q3ListView(this);
        _props->header()->hide();
        _props->setTreeStepSize(11);
        _props->setRootIsDecorated(true);
        _props->setShowToolTips(true);
        _props->addColumn( _q("properties") );
        _props->setResizeMode( Q3ListView::LastColumn );
        QLabel* l = new QLabel( _props, _q("Property Names"), this );

        vb1->addWidget(l);
        vb1->addWidget(_props);

        connect( _props, SIGNAL(selectionChanged(Q3ListViewItem*)), SLOT(pressed(Q3ListViewItem*)) );

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

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

          connect( _add, SIGNAL(clicked()), SLOT(add()) );

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

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

      QVBoxLayout* vb2 = new QVBoxLayout(hb);
      hb->setStretchFactor( vb2, 5 );
      {
        _propValue = new QTextEdit(this);
        _propValue->setWordWrapMode(QTextOption::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 );
          _recursive->setEnabled(_dir);
          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(clicked()), SLOT(set()) );
          connect( _del, SIGNAL(clicked()), 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()) );
    }
  }

  connect( 
    _model, SIGNAL(proplist(const sc::String&,const svn::PropListItems&)),
    this, SLOT(proplist(const sc::String&,const svn::PropListItems&)) );

  connect( 
    _model, SIGNAL(confirmPropSet(PropSetParam*,bool&)),
    this, SLOT(confirmPropSet(PropSetParam*,bool&)) );

  _model->proplist();

  Settings s;
  resize( s.layout().getSize( name(), QSize(600,500) ) );
}

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

  disconnect( 
    _model, SIGNAL(proplist(const sc::String&,const svn::PropListItems&)),
    this, SLOT(proplist(const sc::String&,const svn::PropListItems&)) );

  disconnect( 
    _model, SIGNAL(confirmPropSet(PropSetParam*,bool&)),
    this, SLOT(confirmPropSet(PropSetParam*,bool&)) );
}

void PropertiesDialog2::pressed( Q3ListViewItem* lvi )
{
  if( ! lvi )
  {
    return;
  }

  // Leaf item?
  if( lvi->isExpandable() )
  { // no
    _propValue->setReadOnly(true);
    _propValue->clear();
    _set->setEnabled(false);
    _del->setEnabled(false);
  }
  else
  { // yes
    _propValue->setEnabled(true);
    _propValue->setReadOnly(false);
    _propValue->setText( lvi->text(1) );
    _set->setEnabled(true);
    _del->setEnabled(true);
  }
}

void PropertiesDialog2::newProp(const QString& newVal )
{
  // check if the property already exists => disable add button
  if( newVal.isEmpty() )
  {
    _add->setDisabled(true);
  }
  else
  {
    _add->setDisabled( _props->findItem(newVal,0) );
  }
}

void PropertiesDialog2::add()
{
  QString value;

  if( _newProp->currentText() == "svn:executable" )
  {
    value = "*";
  }

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

  Q3ListViewItem* lvi = _props->findItem( _newProp->currentText(), 0 );
  _props->setCurrentItem(lvi);
  _propValue->setFocus();

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

void PropertiesDialog2::del()
{
  _propValue->setReadOnly(true);
  _propValue->clear();

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

  _model->propset();
}

void PropertiesDialog2::set()
{
  _model->propset();
}

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

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

void PropertiesDialog2::delProperty()
{
  Q3ListViewItem* curr   = _props->currentItem();

  Q3ListViewItem* parent = curr->parent();
  Q3ListViewItem* above  = curr->itemAbove();
  Q3ListViewItem* below  = curr->itemBelow();

  delete curr;

  // if curr was the only child delete parent too.
  if( parent->childCount() == 0 )
  {
    above = parent->itemAbove();
    below = parent->itemBelow();

    delete parent;
  }

  if( above )
  {
    _props->setSelected(above,true);
    pressed(above);
  }
  else if( below )
  {
    _props->setSelected(below,true);
    pressed(below);
  }
  else
  {
    _propValue->setReadOnly(false);
    _set->setEnabled(false);
    _del->setEnabled(false);
  }

  newProp( _newProp->currentText() );
}

void PropertiesDialog2::proplist( const sc::String& name, const svn::PropListItems& items )
{
  for( svn::PropListItems::const_iterator itl = items.begin(); itl != items.end(); itl++ )
  {
    const svn::PropListItem::Props& props = (*itl)->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 );
    }
  }
}

void PropertiesDialog2::confirmPropSet( PropSetParam* param, bool& proceed )
{
  Q3ListViewItem* curr = _props->currentItem();

  param->setPropName( sc::String(curr->text(0).utf8()) );
  param->setPropVal( sc::String(_propValue->text().utf8()) );
  param->setRecurse( _recursive->isChecked() );

  proceed = true;

  // empty value? than this is a delete.
  if( _propValue->text().isEmpty() )
  {
    delProperty();
  }
}
