/* ====================================================================
 * 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 "ProjectSettingsWidget.h"
#include "../ExternProvider.h"
#include "../Project.h"
#include "sublib/ExternButton.h"
#include "util/Compare.h"

// qt
#include <QtCore/QRegExp>
#include <QtGui/QLayout>
#include <QtGui/QLineEdit>
#include <QtGui/QLabel>
#include <QtGui/QFileDialog>
#include <QtGui/QTabWidget>
#include <QtGui/QTabBar>
#include <QtGui/QComboBox>
#include <QtGui/QToolTip>
#include <Qt3Support/Q3ListView>
#include <Qt3Support/Q3HBox>

// sys
#include <assert.h>


///////////////////////////////////////////////////////////////////////////////

class ProjectItemLvi : public Q3ListViewItem
{
  typedef Q3ListViewItem super;

public:
  ProjectItemLvi( Q3ListView* parent, const Project::Item& item, bool current )
    : super(parent), _current(current), _item(item)
  {
  }

  virtual ~ProjectItemLvi()
  {
  }

  int compare( Q3ListViewItem * i, int /*col*/, bool /*ascending*/ ) const
  {
    ProjectItemLvi* lvi =  dynamic_cast<ProjectItemLvi*>(i);

    return compare3( _item.getSortPos(), lvi->getItem().getSortPos() );
  }

  QString text( int col ) const
  {
    switch( col )
    {
    case 0:
      {
        switch( _item.getType() )
        {
        case Project::Item_Trunk:
          {
            return "trunk";
          }
        case Project::Item_Branches:
          {
            return "branches";
          }
        case Project::Item_Tags:
          {
            return "tags";
          }
        case Project::Item_Repository:
          {
            return "repository";
          }
        case Project::Item_WorkingCopy:
          {
            return "working copy";
          }
        default:
          return "";
        }
      }
    case 1:
      {
        if( _current )
        {
          return "*";
        }
        else
        {
          return "";
        }
        break;
      }
    case 2:
      {
        return QString::fromUtf8(_item.getName());
        break;
      }
    case 3:
      {
        return QString::fromUtf8(_item.getSource());
        break;
      }
    case 4:
      {
        return QString("%1").arg(_item.getId());
        break;
      }
    case 5:
      {
        return QString("%1").arg(_item.getSortPos());
        break;
      }
    default:
      {
        return "";
      }
    }
  }

  Project::Item& getItem()
  {
    return _item;
  }

  void setItem( const Project::Item& item )
  {
    _item = item;
    listView()->adjustColumn(1);
    listView()->adjustColumn(2);
    repaint();
  }

  void setCurrent( bool b )
  {
    _current = b;
  }

private:
  bool          _current;
  Project::Item _item;
};

///////////////////////////////////////////////////////////////////////////////

ProjectSettingsWidget::ProjectSettingsWidget( ExternProvider* p, QWidget *parent,
  const char *name ) : super(parent), _prj(0), _p(p)
{
  int row = 0;

  QGridLayout* gl = new QGridLayout(this/*tab2*/,3,4);
  gl->setMargin(2);
  gl->setSpacing(5);
  gl->setColStretch( 0, 1 );
  gl->setColStretch( 1, 1 );
  gl->setColStretch( 2, 2 );
  gl->setColStretch( 3, 1 );
  {
    QHBoxLayout* lh = new QHBoxLayout;

    QLabel* prjL = new QLabel( "&project name:", this ); 
    _name        = new QLineEdit(this);
    prjL->setBuddy(_name);
    lh->add(prjL);
    lh->add(_name);

    gl->addMultiCellLayout( lh, row, row, 0, 3 );
    row++;

    _items = new Q3ListView(this);
    _items->setAllColumnsShowFocus(true);
    _items->addColumn( "type" );
    _items->addColumn( "current" );
    _items->addColumn( "name" );
    _items->addColumn( "path" );
    //_items->addColumn( "id" );
    //_items->addColumn( "sortpos" );
    _items->setItemMargin( 2 );
    _items->setShowToolTips( true );
    _items->setColumnAlignment( 0, Qt::AlignLeft );
    _items->setColumnAlignment( 1, Qt::AlignCenter );
    _items->setColumnWidthMode( 2, Q3ListView::Maximum );
    _items->setColumnWidthMode( 3, Q3ListView::Maximum );
    _items->setResizeMode(Q3ListView::LastColumn);

    connect( _items, SIGNAL(selectionChanged(Q3ListViewItem*)),
      this, SLOT(selectionChanged(Q3ListViewItem*)) );
    connect( _items, SIGNAL(clicked(Q3ListViewItem*)),
      this, SLOT(clicked(Q3ListViewItem*)) );

    gl->addMultiCellWidget( _items, row, row, 0, 3 );
    row++;

    _type = new QComboBox( false, this );
    _type->insertItem( "trunk",        Project::Item_Trunk );
    _type->insertItem( "branches",     Project::Item_Branches );
    _type->insertItem( "tags",         Project::Item_Tags );
    _type->insertItem( "working copy", Project::Item_WorkingCopy );      
    _type->insertItem( "repository",   Project::Item_Repository );
    // increase space so all texts are completly visible (MacOSX)
    _type->setMinimumWidth( _type->sizeHint().width()+10 );

    _itemName = new QLineEdit(this);
    _itemSource = new QLineEdit(this);
    _itemEx = new ExternButton(this);
    _itemSource->setEnabled(false);
    _itemEx->setEnabled(false);
    gl->addWidget( _type,       row, 0 );
    gl->addWidget( _itemName,   row, 1 );
    gl->addWidget( _itemSource, row, 2 );
    gl->addWidget( _itemEx,     row, 3 );
    row++;

    connect( _type,   SIGNAL(activated(int)), SLOT(activated(int)) );
    connect( _itemEx, SIGNAL(clicked()),      SLOT(selectSource()) );

    _type->setCurrentItem( Project::Item_WorkingCopy );

    QGridLayout* glb = new QGridLayout(2,3);
    glb->setColStretch(3,10);
    gl->addMultiCellLayout( glb, row, row, 0, 3 );
    row++;
    {
      _add    = new QPushButton( "&Add",   this );
      _del    = new QPushButton( "&Del",   this );
      _clr    = new QPushButton( "&Clear", this );
      _up     = new QPushButton( "&Up",    this );
      _down   = new QPushButton( "&Down",  this );
      _layout = new QPushButton( "&trunk/branches/tags", this );

      _add->setDisabled(true);
      _del->setDisabled(true);
      _clr->setDisabled(true);
      _up->setDisabled(true);
      _down->setDisabled(true);
      _layout->setDisabled(true);

      glb->addWidget( _clr,    0, 0 );
      glb->addWidget( _add,    0, 1 );
      glb->addWidget( _del,    0, 2 );
      glb->addWidget( _up,     0, 5 );

      glb->addMultiCellWidget( _layout, 1, 1, 0, 1 );
      glb->addWidget( _down,   1, 5 );

      QToolTip::add( _layout, 
        "create standard layout.\n\n"
        "replaces 'trunk', 'branches' and 'tags' urls with:\n"
        " 'trunk' url + '/trunk'   \n"
        " 'trunk' url + '/branches'\n"
        " 'trunk' url + '/tags'    \n" );
    }

    connect( _add,  SIGNAL(clicked()), this, SLOT(add()) );
    connect( _del,  SIGNAL(clicked()), this, SLOT(del()) );
    connect( _clr,  SIGNAL(clicked()), this, SLOT(clr()) );
    connect( _up,   SIGNAL(clicked()), this, SLOT(up()) );
    connect( _down, SIGNAL(clicked()), this, SLOT(down()) );
    connect( _layout, SIGNAL(clicked()), this, SLOT(std()) );
  }

  connect( _name,         SIGNAL(textChanged(const QString&)), SLOT(textChanged(const QString&)) ); 
  connect( _itemName,     SIGNAL(textChanged(const QString&)), SLOT(textChanged(const QString&)) );
  connect( _itemSource,   SIGNAL(textChanged(const QString&)), SLOT(textChanged(const QString&)) );
}

ProjectSettingsWidget::~ProjectSettingsWidget()
{
}

void ProjectSettingsWidget::setProject( Project* prj )
{
  _prj = prj;

  // unfortunately this fires textChanged..
  _name->setText( QString::fromUtf8(_prj->getName()) );
  
  _items->clear();
  _itemName->clear();
  _itemSource->clear();
  _del->setDisabled(true);

  Project::Items items;
  _prj->getItems(items);

  for( Project::Items::iterator it = items.begin(); it != items.end(); it++ )
  {
    const Project::Item& item    = *it;
    bool                 current = _prj->getCurWorkingCopyId() == item.getId(); 

    new ProjectItemLvi( _items, item, current );
  }
}

Project* ProjectSettingsWidget::getProject() const
{
  return _prj;
}

void ProjectSettingsWidget::textChanged( const QString& text )
{
  const QObject* src = sender();

  if( src == _name )
  {
    _prj->setName( sc::String(text.utf8()) );
  }
  else if( src == _itemName )
  {
    ProjectItemLvi* lvi = dynamic_cast<ProjectItemLvi*>(_items->selectedItem());
    if( lvi )
    {
      long id = lvi->getItem().getId();

      Project::Item item = _prj->getItem( id );
      item.setName( sc::String(text.utf8()) );
      _prj->setItem(item);
      lvi->setItem(item);
      
      _itemName->setEnabled(true);
      if( !_itemName->text().isEmpty() )
      {
        _itemSource->setEnabled(true);
        _itemEx->setEnabled(true);
      }
      else
      {
        _itemSource->setEnabled(false);
        _itemEx->setEnabled(false);
      }
    }
    else if( _type->currentItem() == Project::Item_WorkingCopy )
    {
      if( !text.isEmpty() )
      {
        _add->setEnabled(true);
        _del->setEnabled(false);
        _clr->setEnabled(true);
        _itemSource->setEnabled(true);
        _itemEx->setEnabled(true);
      }
      else
      {
        _add->setDisabled(true);
        _del->setDisabled(true);
        _clr->setDisabled(true);
        _itemSource->setEnabled(false);
        _itemEx->setEnabled(false);
      }
    }
  }
  else if( src == _itemSource )
  {
    ProjectItemLvi* lvi = dynamic_cast<ProjectItemLvi*>(_items->selectedItem());
    if( lvi )
    {
      long id = lvi->getItem().getId();

      Project::Item item = _prj->getItem( id );
      item.setSource( sc::String(text.utf8()) );

      _prj->setItem(item);
      lvi->setItem(item);
    }
  }

  emit modified();
}

void ProjectSettingsWidget::selectionChanged( Q3ListViewItem* lvi )
{
  ProjectItemLvi* pil  = dynamic_cast<ProjectItemLvi*>(lvi);
  Project::Item&  item = pil->getItem();

  _type->setCurrentItem(item.getType());
  _itemName->setText( QString::fromUtf8(item.getName()) );
  _itemSource->setText( QString::fromUtf8(item.getSource()) );

  //_itemName->setEnabled(true);
  //_itemSource->setEnabled(true);
  //_itemEx->setEnabled(true);
  
  _add->setDisabled(!item.isWorkingCopy());
  _del->setDisabled(!item.isWorkingCopy());
  _clr->setDisabled(!item.isWorkingCopy());
  _layout->setDisabled(item.getType()!=Project::Item_Trunk);

  _up->setDisabled(false);
  _down->setDisabled(false);

  if( lvi == _items->firstChild() )
  {
    _up->setDisabled(true);
  }
  if( lvi == _items->lastItem() )
  {
    _down->setDisabled(true);
  }
}

void ProjectSettingsWidget::clicked( Q3ListViewItem* lvi )
{
  if( !lvi )
  {
    _up->setEnabled(false);
    _down->setEnabled(false);
  }
}

void ProjectSettingsWidget::selectSource()
{
  sc::String res;

  if( _type->currentItem() == Project::Item_WorkingCopy )
  {
    if( _p->selectPath( this, sc::String(_itemSource->text().utf8()), res, ExternProvider::Dir ) )
    {
      _itemSource->setText( QString::fromUtf8(res) );
    }
  }
  else
  {
    if( _p->selectUrl( this, sc::String(_itemSource->text().utf8()), res, ExternProvider::Dir ) )
    {
      _itemSource->setText( QString::fromUtf8(res) );
    }
  }
}

void ProjectSettingsWidget::std()
{
  QString root = _itemSource->text();

  root.replace( QRegExp("/$"), "" );
  QString tmp;

  Project::Item trunk = _prj->getTrunkItem();
  tmp = root + "/trunk";
  trunk.setSource( sc::String(tmp.utf8()) );
  _prj->setItem(trunk);

  Project::Item branches = _prj->getBranchesItem();
  tmp = root + "/branches";
  branches.setSource( sc::String(tmp.utf8()) );
  _prj->setItem(branches);

  Project::Item tags = _prj->getTagsItem();
  tmp = root + "/tags";
  tags.setSource( sc::String(tmp.utf8()) );
  _prj->setItem(tags);


  Q3ListViewItemIterator it( _items );
  while( it.current() )
  {
    ProjectItemLvi* lvi = dynamic_cast<ProjectItemLvi*>(it.current());

    if( lvi->getItem().isTrunk() )
    {
      lvi->setItem(trunk);
    }
    else if( lvi->getItem().isBranches() )
    {
      lvi->setItem(branches);
    }
    else if( lvi->getItem().isTags() )
    {
      lvi->setItem(tags);
    }

    it++;
  }

  selectionChanged(_items->selectedItem());
  emit modified();
}

void ProjectSettingsWidget::add()
{
  if( _itemName->text().isEmpty() && _itemSource->text().isEmpty() )
  {
    return;
  }

  Project::Item item = _prj->createWorkingCopyItem();
  item.setName( sc::String(_itemName->text().utf8()) );
  item.setSource( sc::String(_itemSource->text().utf8()) );

  _prj->setItem(item);

  bool currentWC = false;
  if( item.getType() == Project::Item_WorkingCopy )
  {
    currentWC = item.getId() == _prj->getCurWorkingCopyId();
  }

  ProjectItemLvi* lvi = new ProjectItemLvi( _items, item, currentWC );
  _items->setSelected(lvi,true);

  emit modified();
}

void ProjectSettingsWidget::del()
{
  ProjectItemLvi* lvi = dynamic_cast<ProjectItemLvi*>(_items->selectedItem());
  if( ! lvi )
  {
    return;
  }

  // select another item if available.
  Q3ListViewItem* newCurrent = lvi->itemBelow();
  if( ! newCurrent )
  {
    newCurrent = lvi->itemAbove();
  }

  _prj->delItem( lvi->getItem().getId() );
  _items->takeItem(lvi);
  delete lvi;

  _itemName->clear();
  _itemSource->clear();
  _del->setDisabled(true);

  // update list view with new values.
  long cid = _prj->getCurWorkingCopyId();

  Q3ListViewItemIterator it( _items );
  while( it.current() )
  {
    ProjectItemLvi* clvi = dynamic_cast<ProjectItemLvi*>(it.current());

    if( clvi->getItem().isWorkingCopy() )
    {
      long lviId = clvi->getItem().getId();

      clvi->setItem( _prj->getItem(lviId) );
      clvi->setCurrent( (lviId == cid) );
    }

    it++;
  }

  if( newCurrent )
  {
    _items->setSelected(newCurrent,true);
  }

  emit modified();
}

void ProjectSettingsWidget::clr()
{
  _items->clearSelection();
  _type->setCurrentItem(Project::Item_WorkingCopy);

  _itemName->clear();
  _itemSource->clear();
  
  _up->setEnabled(false);
  _down->setEnabled(false);
}

void ProjectSettingsWidget::up()
{
  //todo move to project
  ProjectItemLvi* lvi  = dynamic_cast<ProjectItemLvi*>(_items->selectedItem());
  ProjectItemLvi* lvia = dynamic_cast<ProjectItemLvi*>(lvi->itemAbove());

  long tmp = lvi->getItem().getSortPos();
  lvi->getItem().setSortPos( lvia->getItem().getSortPos() );
  lvia->getItem().setSortPos( tmp );

  _prj->setItem(lvi->getItem());
  _prj->setItem(lvia->getItem());

  _items->sort();
  selectionChanged(_items->selectedItem());

  emit modified();
}

void ProjectSettingsWidget::down()
{
  //todo move to project
  ProjectItemLvi* lvi  = dynamic_cast<ProjectItemLvi*>(_items->selectedItem());
  ProjectItemLvi* lvib = dynamic_cast<ProjectItemLvi*>(lvi->itemBelow());

  long tmp = lvi->getItem().getSortPos();
  lvi->getItem().setSortPos( lvib->getItem().getSortPos() );
  lvib->getItem().setSortPos( tmp );

  _prj->setItem(lvi->getItem());
  _prj->setItem(lvib->getItem());

  _items->sort();
  selectionChanged(_items->selectedItem());

  emit modified();
}

void selectItem( Q3ListView* lv, Project::ItemType type )
{
  Q3ListViewItemIterator it( lv );
  while( it.current() )
  {
    ProjectItemLvi* clvi = dynamic_cast<ProjectItemLvi*>(it.current());
    
    if( clvi->getItem().getType() == type )
    {
      lv->setSelected( clvi, true );
      return;
    }
    it++;
  }
}

void ProjectSettingsWidget::activated(int i)
{
  if( _items->selectedItem() )
  {
    _items->clearSelection();
  }
  
  _add->setDisabled(true);
  _del->setDisabled(true);
  _clr->setDisabled(true);
  _up->setDisabled(true);
  _down->setDisabled(true);
  _layout->setDisabled(true);
  
  _itemName->clear();
  _itemSource->clear();
  
  switch(i)
  {
    case Project::Item_Trunk:
    {
      selectItem( _items, Project::Item_Trunk );
      break;
    }
    case Project::Item_Branches:
    {
      selectItem( _items, Project::Item_Branches );
      break;
    }
    case Project::Item_Tags:
    {
      selectItem( _items, Project::Item_Tags );
      break;
    }
  }
}
