/* ====================================================================
 * 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 "BlameViewModel.h"
#include "ScModel.h"
#include "PostCmdResult.h"
#include "events/BlameEvent.h"
#include "events/ScParamEvent.h"
#include "events/EventSupport.h"
#include "commands/BlameParam.h"
#include "commands/BlameCmd.h"
#include "sublib/TargetRepository.h"


class BlameViewModelParamVisitor :
  public ParamVisitor<BlameParam>
{
public:
  BlameViewModelParamVisitor( BlameViewModel* model )
    : _model(model)
  {
  }

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

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

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


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


class BlameBaton : public svn::BlameBaton
{
public:
  BlameBaton( ID tid ) :_tid(tid)
  {
  }

  void receive( const svn::BlameLinePtr line )
  {
    QObject* target = TargetRepository::get(_tid);
    if( target )
    {
      postEvent( target, new BlameEvent(line) );
    }
  }

private:
  ID _tid;
};

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

BlameViewModel::BlameViewModel( const sc::String& name, Bookmark* bm, ScModel* model )
: TargetId(this), _name(name), _bookmark(bm), _model(model)
{
  _revStart = svn::RevisionPtr(new svn::RevisionNumber(0));
  _revStop  = svn::RevisionPtr(new svn::Revision(svn::Revision_Head));
}

BlameViewModel::~BlameViewModel()
{
}

bool BlameViewModel::event( QEvent* e )
{
  switch( e->type() )
  {
  case ScParameterEvent:
    {
      BlameViewModelParamVisitor visitor(this);
      visitor.run(dynamic_cast<ScParamEvent*>(e));
      return true;
    }
  case ScBlameEvent:
    {
      BlameEvent* be = dynamic_cast<BlameEvent*>(e);
      emit addBlameLine(be->getLine());
      return true;
    }
  default:
    {
      return super::event(e);
    }
  }
}

const sc::String& BlameViewModel::getName() const
{
  return _name;
}

void BlameViewModel::setStartRevision( svn::RevisionPtr rev )
{
  _revStart = rev;
}

void BlameViewModel::setStopRevision( svn::RevisionPtr rev )
{
  _revStop = rev;
}

svn::RevisionPtr BlameViewModel::getStartRevision()
{
  return _revStart;
}

svn::RevisionPtr BlameViewModel::getStopRevision()
{
  return _revStop;
}

void BlameViewModel::blame()
{
  BlameParam* param = new BlameParam(
    _name, _revStart, _revStop, new BlameBaton(getTid()));

  BlameCmd* cmd = new BlameCmd( param, new PostCmdResult(this) );
  _model->runThreaded(cmd);
}

void BlameViewModel::result( BlameParam*, const sc::Error* )
{
  emit doneBlame();
}
