/* ====================================================================
 * Copyright (c) 2007, 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 "RepoModel.h"
#include "ScModel.h"
#include "PostCmdResult.h"
#include "events/ScParamEvent.h"
#include "events/EventSupport.h"
#include "commands/ListParam.h"
#include "commands/ListCmd2.h"
#include "commands/DetailsParam.h"
#include "commands/DetailsCmd.h"
#include "sublib/TargetRepository.h"

// qt
#include <QtCore/QRegExp>


class RepoModelParamVisitor :
  public ParamVisitor<ListParam>,
  public ParamVisitor<DetailsParam>
{
public:
  RepoModelParamVisitor( RepoModel* model )
    : _model(model)
  {
  }

  void run( ScParamEvent* e )
  {
    _event = e;
    _event->getParam()->accept(this);
  }

  void visit( ListParam* p )
  {
    _model->result( p, _event->getError() );
  }

  void visit( DetailsParam* p )
  {
    _model->result( p, _event->getError() );
  }

private:
  ScParamEvent*   _event;
  RepoModel*      _model;
};


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

RepoModel::RepoModel( const sc::String& url, ScModel* model )
: TargetId(this), _url(url), _model(model)
{
}

RepoModel::~RepoModel()
{
}

bool RepoModel::event( QEvent* e )
{
  switch( e->type() )
  {
  case ScParameterEvent:
    {
      RepoModelParamVisitor visitor(this);
      visitor.run(dynamic_cast<ScParamEvent*>(e));
      return true;
    }
  default:
    {
      return super::event(e);
    }
  }
}

void RepoModel::setUrl( const sc::String& url )
{
  _entries.clear();
  _url = url;
}

const sc::String& RepoModel::getUrl() const
{
  return _url;
}

const sc::String& RepoModel::getRoot() const
{
  return _root;
}

bool RepoModel::isListed( const sc::String& url )
{
  return _entries.find(url) != _entries.end();
}

void RepoModel::getEntries( const sc::String& url, svn::DirEntries& entries )
{
  RepoModelEntries::iterator it = _entries.find(url);

  if( it == _entries.end() )
    return;

  entries = (*it).second.entries;
}

sc::String RepoModel::parent()
{
  QString root = QString::fromUtf8(_root);
  QString url  = QString::fromUtf8(_url);

  if( root == url )
    return sc::NullString;

  QRegExp reg("(.*)/.+$");
  reg.exactMatch( url );

  return sc::String( reg.cap(1).utf8() );
}

void RepoModel::list( const sc::String& url )
{
  ListParam* param = new ListParam( url,
    new svn::Revision(svn::Revision_Unspecified), false, false );

  ListCmd2* cmd = new ListCmd2( param, _model->getListCache(), 
    new PostCmdResult(this) );

  _model->runThreaded(cmd);
}

void RepoModel::result( ListParam* p, const sc::Error* e )
{
  if( e )
  {
    emit doneList( p->getPathOrUrl() );
    return;
  }

  RepoModelEntry entry;
  entry.entries = p->getEntries();

  _entries.insert( RepoModelEntries::value_type(p->getPathOrUrl(),entry) );

  emit doneList( p->getPathOrUrl() );
}

void RepoModel::root()
{
  DetailsParam* param = new DetailsParam(_url);
  DetailsCmd*   cmd   = new DetailsCmd(param, new PostCmdResult(this) );

  _model->runThreaded(cmd);
}

void RepoModel::result( DetailsParam* p, const sc::Error* )
{
  _root = p->getReposRoot();
  emit doneRoot();
}
