/* ====================================================================
 * Copyright (c) 2006-2008  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 "Controller.h"
#include "ScModel.h"
#include "Bookmark.h"
#include "WcViewModel.h"
#include "RpViewModel.h"
#include "LogViewModel.h"
#include "BlameViewModel.h"
#include "BookmarkViewModel.h"
#include "LogGraphViewModel.h"
#include "WcStatusCache.h"
#include "sublib/MessageBox.h"
#include "svn/WcStatus.h"
#include "svn/DirEntry.h"


Controller::Controller( ScModel* model )
: _model(model), _curWcModel(NULL),  _curRpModel(NULL)
{
  _bmModel = new BookmarkViewModel(_model);

  connect(
    _bmModel, SIGNAL(bookmarkAdded(Bookmark*)), SLOT(addBookmark(Bookmark*)) );
  connect(
    _bmModel, SIGNAL(bookmarkSelected(Bookmark*)), SLOT(selectBookmark(Bookmark*)) );
  connect(
    _bmModel, SIGNAL(bookmarkModified(Bookmark*)), SLOT(modifiedBookmark(Bookmark*)) );
}

Controller::~Controller()
{
  for( WcViewModels::iterator it = _wcModels.begin(); it != _wcModels.end(); it++ )
  {
    delete (*it).second._model;
  }

  delete _bmModel;
}

ScModel* Controller::getScModel()
{
  return _model;
}

WcViewModel* Controller::getWcViewModel()
{
  return _curWcModel;
}

BookmarkViewModel* Controller::getBookmarkViewModel()
{
  return _bmModel;
}

void Controller::initBookmarks()
{
  _bmModel->initBookmarks();
}

void Controller::updateBookmarks()
{
  _bmModel->updateBookmarks();
}

void Controller::addBookmark( Bookmark* bm )
{
  if( bm->isWorkingCopy() )
  {
    WcViewModels::iterator it = _wcModels.find( bm->getId() );
    if( it == _wcModels.end() )
    {
      WcViewModel* model = new WcViewModel(bm, _model);

      WcViewData data;
      data._model       = model;
      data._initialized = false;
      data._source      = bm->getSource();

      it = _wcModels.insert( WcViewModels::value_type(bm->getId(),data) ).first;
      emit newView(bm->getId(),model);

      connect( model, SIGNAL(commandStarted(Bookmark*)), _bmModel, SLOT(running(Bookmark*)) );
      connect( model, SIGNAL(commandFinished(Bookmark*)), _bmModel, SLOT(finished(Bookmark*)) );
    }
  }
  else if( bm->isRemote() )
  {
    RpViewModels::iterator it = _rpModels.find( bm->getId() );
    if( it == _rpModels.end() )
    {
      RpViewModel* model = new RpViewModel(bm, _model);

      RpViewData data;
      data._model       = model;
      data._initialized = false;
      data._source      = bm->getSource();

      it = _rpModels.insert( RpViewModels::value_type(bm->getId(),data) ).first;

      if(data._source.isEmpty())
        return;

      emit newView(bm->getId(),model);
    }
  }
  else if( bm->isProject() )
  {
  }
}

void Controller::delBookmark( Bookmark* bm )
{
  if( bm->isWorkingCopy() )
  {
    WcViewModels::iterator it = _wcModels.find( bm->getId() );
    if( it == _wcModels.end() )
      assert(false);

    const WcViewData& data = (*it).second;
    emit delView(bm->getId());

    delete data._model;
    _wcModels.erase(it);
  }
  else if( bm->isRemote() )
  {
    RpViewModels::iterator it = _rpModels.find( bm->getId() );
    if( it == _rpModels.end() )
      assert(false);

    const RpViewData& data = (*it).second;
    emit delView(bm->getId());

    delete data._model;
    _rpModels.erase(it);
  }
  else if( bm->isProject() )
  {
  }
}

void Controller::selectBookmark( Bookmark* bm )
{
  ///> \todo remember model initialized, the models don't use it..

  if( bm->isWorkingCopy() )
  {
    WcViewModels::iterator it = _wcModels.find( bm->getId() );

    if( it == _wcModels.end() )
      assert(false);

    WcViewData& data = (*it).second;

    // remember current view model
    _curWcModel = data._model;

    if( ! data._initialized )
    {
      // trigger initial status load
      data._model->status();
      data._initialized = true;
    }

    emit showView(bm->getId());
  }
  // repository
  else if( bm->isRemote() )
  {
    RpViewModels::iterator it = _rpModels.find( bm->getId() );

    if( it == _rpModels.end() )
      assert(false);

    RpViewData& data = (*it).second;

    // remember current view model
    _curRpModel = data._model;

    if( ! data._initialized )
    {
      // trigger initial list
      data._model->list();
      data._initialized = true;
    }

    emit showView(bm->getId());
  }
  // project
  else if( bm->isProject() )
  {
    // anything usefull we could display here?
  }
}

void Controller::modifiedBookmark( Bookmark* bm )
{
  // working copy
  if( bm->isWorkingCopy() )
  {
    WcViewModels::iterator it = _wcModels.find( bm->getId() );

    if( it == _wcModels.end() )
      assert(false);

    if( bm->getSource() != (*it).second._source )
    {
      delBookmark( bm );
      addBookmark( bm );
      selectBookmark( bm );
    }
  }
  // repository
  else if( bm->isRemote() )
  {
    RpViewModels::iterator it = _rpModels.find( bm->getId() );

    if( it == _rpModels.end() )
      assert(false);

    if( bm->getSource() != (*it).second._source )
    {
      delBookmark( bm );
      addBookmark( bm );
      selectBookmark( bm );
    }
  }
}

WcViewModel* Controller::getWcModel( ID id )
{
  WcViewModels::iterator it = _wcModels.find(id);

  if( it == _wcModels.end() )
    assert(false);

  return (*it).second._model;
}

void Controller::reload()
{
  Bookmark* bm = _bmModel->getBookmark();

  if( bm->isWorkingCopy() )
  {
    WcViewModels::iterator it = _wcModels.find( bm->getId() );
    if( it != _wcModels.end() )
      _curWcModel->reload();
  }
  else if( bm->isRemote() )
  {
    RpViewModels::iterator it = _rpModels.find( bm->getId() );
    if( it != _rpModels.end() )
      _curRpModel->reload();
  }
}

void Controller::wcDiffBase()
{
  _curWcModel->diffBase();
}

void Controller::wcAdd()
{
  _curWcModel->add();
}

void Controller::wcRemove()
{
  _curWcModel->remove();
}

void Controller::wcRevert()
{
  _curWcModel->revert();
}

void Controller::wcCommit()
{
  emit showCommit( false, _curWcModel );
}

void Controller::wcEditConflict()
{
  _curWcModel->editConflict();
}

void Controller::wcResolved()
{
  _curWcModel->resolved();
}

void Controller::wcLog()
{
  svn::WcStatusPtr status = _curWcModel->getSelection().getSingle();
  emit showLog( new LogViewModel( status->getName(), status->isDir(),
    _curWcModel->getBookmark(), _model) );
}

void Controller::wcLogGraph()
{
  svn::WcStatusPtr status = _curWcModel->getSelection().getSingle();
  emit showLogGraph( new LogGraphViewModel( status->getName(),
    status->isDir(), _curWcModel->getBookmark(), _model) );
}

void Controller::wcProperties()
{
  emit showProps(_curWcModel);
}

void Controller::wcIgnore()
{
  _curWcModel->ignore();
}

void Controller::wcBlame()
{
  svn::WcStatusPtr status = _curWcModel->getSelection().getSingle();
  emit showBlame( new BlameViewModel( status->getName(),
    _curWcModel->getBookmark(), _model) );
}

void Controller::wcLock()
{
  _curWcModel->lock();
}

void Controller::wcUnlock()
{
  _curWcModel->unlock();
}

void Controller::wcCleanup()
{
  _curWcModel->cleanup();
}

void Controller::wcMkdir()
{
  _curWcModel->mkdir();
}

void Controller::wcExport()
{
  _curWcModel->exportx();
}

void Controller::wcUpdateRev()
{
  _curWcModel->updateRev();
}

void Controller::wcBranchTag()
{
  _curWcModel->branchTag();
}

void Controller::wcPropList()
{
  _curWcModel->proplist();
}

void Controller::wcPropGet()
{
  _curWcModel->propget();
}

void Controller::wcPropSet()
{
  _curWcModel->propset();
}

void Controller::wcCat()
{
}

void Controller::wcAutoUpdate()
{
  int cnt = 0;
  for( WcViewModels::iterator it = _wcModels.begin(); it != _wcModels.end(); it++ )
  {
    WcViewModel* m = (*it).second._model;
    Bookmark*    b = m->getBookmark();
    
    if( b->getAutoUpdate() )
      cnt++;
  }
  
  if( cnt == 0 )
    return;

  bool proceed = false;
  emit confirmAutoUpdate(proceed);

  if( ! proceed )
    return;

  for( WcViewModels::iterator it = _wcModels.begin(); it != _wcModels.end(); it++ )
  {
    WcViewModel* m = (*it).second._model;
    Bookmark*    b = m->getBookmark();
    
    if( b->getAutoUpdate() )
      m->update(true);
  }
}

void Controller::rpLog()
{
  svn::DirEntryPtr entry =_curRpModel->getSelection().getSingle();
  emit showLog( new LogViewModel( entry->getName(), entry->isDir(),
    _curRpModel->getBookmark(), _model) );
}

void Controller::rpLogGraph()
{
  svn::DirEntryPtr entry =_curRpModel->getSelection().getSingle();
  emit showLogGraph( new LogGraphViewModel( entry->getName(), entry->isDir(),
    _curRpModel->getBookmark(), _model) );
}

void Controller::rpBlame()
{
  svn::DirEntryPtr entry =_curRpModel->getSelection().getSingle();
  emit showBlame( new BlameViewModel( entry->getName(),
    _curRpModel->getBookmark(), _model) );
}

void Controller::rpBranchTag()
{
  _curRpModel->branchTag();
}

void Controller::rpCheckout()
{
  _curRpModel->checkout();
}

void Controller::rpSwitch()
{
  _curRpModel->switchx();
}

void Controller::rpDiff()
{
  _curRpModel->diff();
}

void Controller::rpMerge()
{
  _curRpModel->merge();
}

void Controller::rpMkdir()
{
  _curRpModel->mkdir();
}

void Controller::rpRemove()
{
  _curRpModel->remove();
}

void Controller::rpImport()
{
  _curRpModel->import();
}

void Controller::rpExport()
{
  _curRpModel->exportx();
}

void Controller::rpCat()
{
  _curRpModel->cat();
}

void Controller::bmUpdate()
{
  ID id = _bmModel->getBookmarkMenu()->getId();

  WcViewModel* model = getWcModel(id);
  model->update(true);
}

void Controller::bmUpdateRev()
{
  ID id = _bmModel->getBookmarkMenu()->getId();

  WcViewModel* model = getWcModel(id);
  model->updateRev(true);
}

void Controller::bmCommit()
{
  ID id = _bmModel->getBookmarkMenu()->getId();

  emit showCommit( true, getWcModel(id) );
}

void Controller::bmLog()
{
  Bookmark* bm = _bmModel->getBookmarkMenu();

  emit showLog( new LogViewModel( bm->getSource(), true, bm, _model) );
}

void Controller::bmBranchTag()
{
  // \todo move branchTag method to common ViewModel interface

  Bookmark* bm = _bmModel->getBookmarkMenu();

  if( bm->isWorkingCopy() )
  {
    WcViewModels::iterator it = _wcModels.find( bm->getId() );
    if( it != _wcModels.end() )
      (*it).second._model->branchTag(true);
  }
  else if( bm->isRemote() )
  {
    RpViewModels::iterator it = _rpModels.find( bm->getId() );
    if( it != _rpModels.end() )
      (*it).second._model->branchTag(true);
  }
}

void Controller::bmCheckout()
{
  Bookmark* bm = _bmModel->getBookmarkMenu();

  if( bm->isRemote() )
  {
    RpViewModels::iterator it = _rpModels.find( bm->getId() );
    if( it != _rpModels.end() )
      (*it).second._model->checkout(true);
  }
  else
  {
    assert(false);
  }
}

void Controller::bmSwitch()
{
  Bookmark* bm = _bmModel->getBookmarkMenu();

  if( bm->isRemote() )
  {
    RpViewModels::iterator it = _rpModels.find( bm->getId() );
    if( it != _rpModels.end() )
      (*it).second._model->switchx(true);
  }
  else
  {
    assert(false);
  }
}

void Controller::adminCreate()
{
  // todo should be in a model class.
  bool proceed = false;
  emit confirmCreateRepository(proceed);
}

#if 0
void ProjectFoldersWidget::status( long wcId, const sc::String& wcRoot, Project* prj )
{
  emit wcItemSelected();

  if( ! _wcModel->isWorkingCopy(wcRoot) )
  {
    QString msg = _q("%1 is not a working copy. Checkout a new working copy ?")
      .arg( QString::fromUtf8(wcRoot) );

    int answer = msgInformation( _q("subcommander:status"), msg,
      _q("&Ok"), _q("&Cancel") );
  
    if( answer == QMessageBox::Ok )
    {
      ExternProviderImpl externProvider(_wcModel);

      CheckoutDialog *codlg = new CheckoutDialog(&externProvider,
        _wcModel->isCmdRecursive(), false, this );
      codlg->enableWorkingCopyPath(false);

      QString qwcRoot = QString::fromUtf8(wcRoot);
      codlg->setWorkingCopyPath( qwcRoot );

      if( prj->getTagsUrl().getCharCnt() )
      {
        QString url = QString::fromUtf8(prj->getTagsUrl());
        codlg->setRepositoryUrl(url);
      }
      if( prj->getBranchesUrl().getCharCnt() )
      {
        QString url = QString::fromUtf8(prj->getBranchesUrl());
        codlg->setRepositoryUrl(url);
      }
      if( prj->getRepositoryUrl().getCharCnt() )
      {
        QString url = QString::fromUtf8(prj->getRepositoryUrl());
        codlg->setRepositoryUrl(url);
      }

      int result = codlg->exec();

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

      CheckoutParam* param = new CheckoutParam( 
        sc::String(codlg->getRepositoryUrl().utf8()),
        sc::String(codlg->getWorkingCopyPath().utf8()),
        codlg->getPegRevision(), codlg->getRevision(),
        codlg->isRecursive() );

      PostCmdResult* pcres = new PostCmdResult(this);

      _wcModel->checkout( param, pcres );
    }
    return;
  }

  if( _wcModel->getWcId() != wcId )
  {
    // init model
    _wcModel->setProject(prj);
    _wcModel->setRoot( wcId, wcRoot );

    emit wcStatusReset();

    StatusParam* param = new StatusParam( wcRoot,
      new svn::Revision(svn::Revision_Unspecified), _wcModel->getStatusRecurse(),
      true /* that is correct! */, _wcModel->getStatusUpdates(),
      _wcModel->getStatusIgnored(), false );

    param->setCmdData( new IdCmdData(wcId) );

    PostCmdResult* pcres = new PostCmdResult(this);

    _wcModel->status( param, pcres );
  }
}
#endif

