/* ====================================================================
 * Copyright (c) 2003-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 "Commit.h"
#include "MainWindow.h"
#include "DialogHandler.h"
#include "CommitDialog.h"
#include "CursorSupport.h"
#include "ScModel.h"
#include "settings/FontSettings.h"
#include "events/CustomEvents.h"
#include "events/DialogEvent.h"
#include "events/EventSupport.h"
#include "sublib/TargetId.h"
#include "util/Condition.h"

// qt
#include <QtGui/QApplication>

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

/**
 * helper class to bring up the commit dialog.
 */
class CommitHandler : public DialogHandler, public CommitResult
{
public:
  CommitHandler( CommitDialog* dlg, sc::Condition* cond, const svn::CommitItems& items )
   : _dlg(dlg), _cond(cond), _items(items), _ok(false)
  {
  }

  void run( QWidget* parent )
  {
    // any better idea to get the model?
    MainWindow* mw = dynamic_cast<MainWindow*>(qApp->mainWidget());

    // explict commit?
    if( _dlg )
    {
      // yes, than there is already a commit dialog open
      sc::Condition cond;
      _dlg->setResult(this);
      _dlg->setCondition(&cond);
      _dlg->setCommitItems(_items);

      // wait until the dialog fires the final commit step.
      // since this code runs in the event loop we must NOT block!
      // make sure we still have the event loop running.
      while( ! cond.wait(10)  )
      {
        QApplication::processEvents( QEventLoop::AllEvents, 500 );
      }

      // wake up commit thread
      _cond->wakeAll();
    }
    else
    {
      // no, create a commit dialog
      _dlg = new CommitDialog( false, false, NULL /* WcViewModel */,
        mw->getModel()->getCommitLogHistory(),
        mw->getModel()->getFontSettings()->getEditorFont(),
        parent );
      _dlg->setResult( this );
      _dlg->setCommitItems(_items);

      _dlg->exec();
      delete _dlg;
 
      // wake up commit thread
      _cond->wakeAll();
    }
  }

  bool ok() const
  {
    return _ok;
  }

  const sc::String& getLogMessage() const
  {
    return _log;
  }

  // CommitResult
  void setCommit( bool commit )
  {
    _ok = commit;
  }

  void setLog( const sc::String& log )
  {
    _log = log;
  }

private:
  // in
  CommitDialog*    _dlg;
  sc::Condition*   _cond;
  svn::CommitItems _items;

  // out
  bool       _ok;
  sc::String _log;
};

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

Commit::Commit() : _type(Implicit), _dlg(NULL)
{
}

Commit::Commit( CommitDialog* dlg )
: _type(ExplicitShow), _dlg(dlg)
{
}

Commit::Commit( const sc::String& log )
: _type(ExplicitSkip), _dlg(NULL), _log(log)
{
}

/** 
 * Get the log message for the current commit. This method is called
 * from subversion (CommitBaton).
 */
bool Commit::getLogMsg( sc::String& logMsg, sc::String& tmpFile, const svn::CommitItems& items )
{
  if( _type == ExplicitSkip )
  {
    logMsg = _log;
    return true;
  }
  else
  {
    sc::Condition cond;
    CommitHandler handler( _dlg, &cond, items );
  
    postEvent( qApp->mainWidget(), new DialogEvent(&handler) );
  
    cond.wait();
  
    if( ! handler.ok() )
    {
      return false;
    }

    // ok
   logMsg = handler.getLogMessage();
   return true;
  }
}
