/* ====================================================================
 * 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 "RepositoryLvi.h"
#include "ListWidget.h"
#include "ScModel.h"
#include "Project.h"
#include "ActionStorage.h"
#include "CheckoutDialog.h"
#include "DiffDialog.h"
#include "SwitchDialog.h"
#include "RepositoryModel.h"
#include "CursorSupport.h"
#include "ErrorSupport.h"
#include "PostCmdResult.h"
#include "ExternProviderImpl.h"
#include "ColorId.h"
#include "ProjectLvi.h"
#include "ProjectFoldersWidget.h"
#include "DragDropMimeTypes.h"
#include "ProjectItemDragObject.h"
#include "dialogs/CopyDialogCmd.h"
#include "dialogs/CheckoutDialogCmd.h"
#include "commands/ScCmd.h"
#include "commands/CheckoutParam.h"
#include "commands/ListParam.h"
#include "commands/DiffParam.h"
#include "commands/SwitchParam.h"
#include "events/DialogEvent.h"
#include "events/LviOnItemEvent.h"
#include "events/EventSupport.h"
#include "sublib/ColorStorage.h"
#include "sublib/StringUtil.h"
#include "sublib/Utility.h"
#include "sublib/MessageBox.h"
#include "svn/ClientTypes.h"
#include "svn/Revision.h"
#include "svn/Error.h"
#include "util/Id.h"
#include "util/Guard.h"
#include "util/Compare.h"

// qt
#include <qpopupmenu.h>
#include <qdragobject.h>
#include <QtGui/QClipboard>
#include <QtGui/QApplication>
#include <QtGui/QLineEdit>
#include <QtGui/QPainter>
#include <QtGui/QCursor>
#include <QtGui/QFileDialog>
#include <QtGui/QAction>

// sys
#include <assert.h>


enum Actions
{
  ActionCheckout,
  ActionSwitch,
  ActionDiff,
  ActionLog,
  ActionBranch,
  ActionTag,

  ItemActionEdit,
  ItemActionRemove
};

static ActionStorage _actions;
static QPopupMenu*   _menu = NULL;


RepositoryLvi::RepositoryLvi( QListViewItem* parent, RepositoryModel* rmodel,
  Project* prj, const Project::Item& item )
: super(parent,""), _rpModel(rmodel), _prj(prj), _item(item), _root(true)
{
  init( QString::fromUtf8(_item.getName()) ); 
}

RepositoryLvi::RepositoryLvi( RepositoryLvi* parent, RepositoryModel* rmodel,
  Project* prj, QString repPath )
: super(parent,repPath), _rpModel(rmodel), _prj(prj), _root(false)
{
  init( repPath );
}

RepositoryLvi::~RepositoryLvi()
{
}

void RepositoryLvi::setupActions( ProjectFoldersWidget* parent )
{
  QAction* action;

  action = new QAction( _q("&checkout.."), _q("Ctrl+Shift+C"), parent );
  action->setStatusTip( _q("checkout a working copy from a repository") );
  action->setEnabled(false);
  parent->connect( action, SIGNAL(activated()), SLOT(checkout()) );
  _actions.addAction( ActionCheckout, action );

  action = new QAction( _q("&switch to.."), _q("Ctrl+Shift+S"), parent );
  action->setStatusTip( _q("switch working copy to the selected repository url") );
  action->setEnabled(false);
  parent->connect( action, SIGNAL(activated()), SLOT(switchx()) );
  _actions.addAction( ActionSwitch, action );

  action = new QAction( _q("&diff.."), _q("Ctrl+Shift+D"), parent );
  action->setStatusTip( _q("show the differences between repository paths") );
  action->setEnabled(false);
  parent->connect( action, SIGNAL(activated()), SLOT(diff()) );
  _actions.addAction( ActionDiff, action );

  action = new QAction( _q("&log.."), _q("Ctrl+Shift+L"), parent );
  action->setStatusTip( _q("view the log history of the selected url") );
  action->setEnabled(false);
  parent->connect( action, SIGNAL(activated()), SLOT(log()) );
  _actions.addAction( ActionLog, action );

  action = new QAction( _q("&branch.."), _q("Ctrl+Shift+B"), parent );
  action->setStatusTip( _q("create a branch from the selected repository url") );
  action->setEnabled(false);
  parent->connect( action, SIGNAL(activated()), SLOT(branch()) );
  _actions.addAction( ActionBranch, action );

  action = new QAction( _q("&tag.."), _q("Ctrl+Shift+T"), parent );
  action->setStatusTip( _q("create a tag from the selected repository url") );
  action->setEnabled(false);
  parent->connect( action, SIGNAL(activated()), SLOT(tag()) );
  _actions.addAction( ActionTag, action );

  action = new QAction( _q("&edit.."), _q("Ctrl+E"), parent );
  action->setStatusTip( _q("edit repository configuration") );
  action->setEnabled(false);
  parent->connect( action, SIGNAL(activated()), SLOT(editRpPrjItem()) );
  _actions.addAction( ItemActionEdit, action );

  action = new QAction( _q("&delete"), _q("CTRL+D"), parent );
  action->setStatusTip( _q("delete repository") );
  action->setEnabled(false);
  parent->connect( action, SIGNAL(activated()), SLOT(delRpPrjItem()) );
  _actions.addAction( ItemActionRemove, action );
  {
    _menu = new QPopupMenu(parent);
    QAction* action;

    action = _actions.getAction( ActionLog );
    action->addTo(_menu);

    _menu->insertSeparator();

    action = _actions.getAction( ActionBranch );
    action->addTo(_menu);
    action = _actions.getAction( ActionTag );
    action->addTo(_menu);

    _menu->insertSeparator();

    action = _actions.getAction( ActionCheckout );
    action->addTo(_menu);
    action = _actions.getAction( ActionSwitch );
    action->addTo(_menu);
    //action = _actions.getAction( ActionDiff );
    //action->addTo(_menu);

    _menu->insertSeparator();

    action = _actions.getAction( ItemActionEdit );
    action->addTo(_menu);
    action = _actions.getAction( ItemActionRemove );
    action->addTo(_menu);
  }
}

QPopupMenu* RepositoryLvi::getMenu()
{
  return _menu;
}

void RepositoryLvi::init( const QString& text )
{
  setText( 0, text );
  setPixmap( 0, QPixmap(getIconDir() + "BookmarkRepository.png") );
}

QString RepositoryLvi::getUrl() const
{
  return QString::fromUtf8(_item.getSource());
}

QString RepositoryLvi::text( int column ) const
{
  switch( column )
  {
  case 1:
    {
      if( isRoot() )
      {
        sc::String sRev = _item.getRevision()->toString();
        QString qRev = QString("<@ %1>").arg((const char*)sRev);
        return qRev;
      }
      break;
    }
  }
  return super::text(column);
}

int RepositoryLvi::compare( QListViewItem* i, int col, bool ascending ) const
{
  ScLvi* lvi = dynamic_cast<ScLvi*>(i);

  if( lvi )
  {
    if( isRoot() )
    {
      return compare3( getSortPos(), lvi->getSortPos() );
    }
    else
    {
      return sc::compare( text(0), lvi->text(0) );
    }
  }
  else
  {
    return super::compare(i,col,ascending);
  }
}

bool RepositoryLvi::acceptDrop( const QMimeSource* mime ) const
{
  return mime->provides( ScMimeTypeRepository ) 
    ||   mime->provides( ScMimeTypeWorkingCopy );
}

void RepositoryLvi::dropped( QDropEvent* e )
{
  ProjectItem prjItem;
  ProjectItemDragObject::decode(e,prjItem);

  if( ! (prjItem._prjId == _prj->getId()) || prjItem._itemId == _item.getId() )
  {
    return;
  }

  _prj->moveItem( prjItem._itemId, _item.getId() );
  ((ProjectLvi*)parent())->updateBookmarks();

  _rpModel->saveProject(_prj);
}

QDragObject* RepositoryLvi::dragObject()
{
  ProjectItem prjItem(_prj->getId(),_item.getId());
  return new ProjectItemDragObject( ScMimeTypeRepository, listView(), prjItem );
}

void RepositoryLvi::paintFocus( QPainter * p, const QColorGroup & cg, const QRect & r )
{
  super::paintFocus(p,cg,r);

  //if( isRunning() )
  //{
    //p->setPen( QColor(255,255,0) );
    //p->drawRect( r );
  //}
}

void RepositoryLvi::paintCell( QPainter *p, const QColorGroup & cg, int column, int width, int alignment )
{
  QColorGroup g(cg);

  if( column == 1 )
  {
    g.setColor( QColorGroup::Text,            ColorStorage::getColor(ColorFaded) );
    g.setColor( QColorGroup::HighlightedText, ColorStorage::getColor(ColorFaded) );
  }

  super::paintCell(p,g,column,width,alignment);
}

void RepositoryLvi::onItem()
{
  postEvent( getTidObj(), new LviOnItemEvent(getRepositoryUrl()) );
}

void RepositoryLvi::pressed( bool refresh )
{
  // TODO replace with visitor

  ProjectFoldersWidget* pfw = dynamic_cast<ProjectFoldersWidget*>(listView());

  pfw->list( getId(), _item.getSource(), _item.getRevision(), _prj );

}

void RepositoryLvi::renamed( const QString& text )
{
  _item.setName( sc::String(text.utf8()) );
  _prj->setItem(_item);
}

#if 0
  case mCopy:
    {
      // TODO
      QTextDrag* qtd = new QTextDrag( _repPath );
      qtd->setSubtype( "utf8" );
      QApplication::clipboard()->setData( qtd );
      break;
    }
#endif

void RepositoryLvi::contextMenuRequest( const QPoint& pos, int col )
{
  _menu->exec(pos);
}

long RepositoryLvi::getSortPos() const
{
  return _item.getSortPos();
}

bool RepositoryLvi::isRoot() const
{
  return _root;
}

QString RepositoryLvi::getRepositoryUrl() const
{
  if( isRoot() )
  {
    return getUrl();
  }
  else
  {
    return ((RepositoryLvi*)parent())->getRepositoryUrl() + "/" + text(0);
  }
}

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

const Project::Item& RepositoryLvi::getProjectItem() const
{
  return _item;
}

void RepositoryLvi::setProjectItem( const Project::Item& item )
{
  _item = item;

  init( QString::fromUtf8(_item.getName()) );
}

#if 0
// experimental
svn::Revnumber rev;
svn::Client* svn = getModel()->getClient();
svn::Error*  err = svn->getHeadRevision( &rev, getRepositoryUrl().utf8() );
// experimental
#endif

void RepositoryLvi::checkout()
{
  CheckoutDialogCmd co( listView(), getTid(), _rpModel );

  QString srcPath(getRepositoryUrl());
  QString dstPath = QString::fromUtf8(_prj->getCurWorkingCopyPath());

  co.run( srcPath, dstPath, _prj );

  ProjectLvi* prjlvi = getProjectLvi();
  prjlvi->refresh();
}

void RepositoryLvi::switchx()
{
#if 0
  ExternProviderImpl externProvider(_rpModel);

  SwitchDialog* dlg = new SwitchDialog(&externProvider,
    _rpModel->isCmdRecursive(),listView());
  dlg->enableRepositoryUrl(false);

  QString url = getRepositoryUrl();
  dlg->setRepositoryUrl(url);

  QString wc = QString::fromUtf8(_prj->getCurWorkingCopyPath());
  dlg->setWorkingCopyPath(wc);

  int result = dlg->exec();

  if( result != QDialog::Accepted )
  {
    return;
  }

  SwitchParam* param = new SwitchParam(sc::String(dlg->getWorkingCopyPath()),
    sc::String(getRepositoryUrl().utf8()), dlg->getRevision(), dlg->isRecursive() );

  PostCmdResult* pcres = new PostCmdResult( getTidObj() );

  _rpModel->switchx( param, pcres );
#endif
}

void RepositoryLvi::diff( RepositoryLvi* lvi )
{
#if 0
  RepositoryLvi* secondLvi = 0;

  if( lvi && !(lvi->getProject()->getId() == getProject()->getId()) )
  {
    msgWarning( _q("subcommander [diff]"),
      _q("You can't run diff across project boundaries!"), _q("&Ok") );
    return;
  }

  if( lvi && lvi != this )
  {
    secondLvi = lvi;
  }

  DiffDialog* dlg = new DiffDialog( _rpModel, true, new ExternProviderImpl(_rpModel), 0 );

  QString url = getRepositoryUrl();
  dlg->enablePathOrUrl1(false);
  dlg->setPathOrUrl1(url);
  dlg->setPathOrUrl2(url);

  if( secondLvi )
  {
    QString url2 = secondLvi->getRepositoryUrl();
    dlg->enablePathOrUrl2(true);
    dlg->setPathOrUrl2(url2);
  }

  dlg->show();
#endif
}

void RepositoryLvi::log()
{
#if 0
  LogDialog* ldlg = new LogDialog( _rpModel, getProject(),
     sc::String(getRepositoryUrl().utf8()), true );

  ldlg->show();
#endif
}

void RepositoryLvi::branch()
{
  CopyDialogCmd copy( listView(), getTid(), _rpModel );

  QString srcPath(getRepositoryUrl());
  QString dstPath(QString::fromUtf8(_prj->getBranchesUrl()));

  copy.run( srcPath, dstPath );
}

void RepositoryLvi::tag()
{
  CopyDialogCmd copy( listView(), getTid(), _rpModel );

  QString srcPath(getRepositoryUrl());
  QString dstPath(QString::fromUtf8(_prj->getTagsUrl().getStr()));

  copy.run( srcPath, dstPath );
}

void RepositoryLvi::enableActions()
{
  _actions.enableActions();
  _actions.enableAction( ItemActionRemove, _item.isRepository() );
}

void RepositoryLvi::disableActions()
{
  _actions.disableActions();
}
