/* ====================================================================
 * 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 "config.h"
#include "ProjectWizard.h"
#include "sublib/ExternButton.h"
#include "svn/Client.h"

// qt
#include <QtGui/QLayout>
#include <QtGui/QPushButton>
#include <QtGui/QLabel>
#include <QtGui/QLineEdit>
#include <QtGui/QTextEdit>
#include <QtGui/QFileDialog>
#include <QtCore/QVariant>
#include <QtCore/QRegExp>

// sys
#include <cassert>


enum PageIndex
{
  IdxPage1,
  IdxPage2,
  IdxPage3,
  IdxPage4
};


class ProjectNamePage : public QWizardPage
{
public:
  ProjectNamePage(QWidget *parent) : QWizardPage(parent)
  {
    setTitle( _q("Project Name") );

    QGridLayout* l = new QGridLayout();
    {
      QLineEdit* prjName = new QLineEdit( _q("<project name>"), this );
      QLabel*    text    = new QLabel( _q("choose a name for the project"), this );
      QLabel*    label   = new QLabel( prjName, _q("Project Name:"), this );
      QTextEdit* info    = new QTextEdit(this);
      info->setPlainText(
        _q("A project is simply a group of related bookmarks. A bookmark can be"
           " either a repository url or a working copy path. A project can have"
           " as many bookmarks as you like.\n\n"
           "The project name can be changed at any time by choosing rename from"
           "the project (context) menu or by 'in place' editing the bookmark.") );
      info->setStyleSheet("QTextEdit { background: transparent }");
      info->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
      info->setFrameShape(QFrame::NoFrame);
      info->setReadOnly(true);

      l->setSpacing(10);
      l->addWidget( text,    0, 0, 1, 2 );
      l->addWidget( label,   1, 0 );
      l->addWidget( prjName, 1, 1 );
      l->addWidget( info,    2, 0, 1, 2 );

      registerField("ProjectName*", prjName);
    }
    setLayout(l);
  }

  bool isComplete() const
  {
    return ! field("ProjectName").toString().isEmpty();
  }
};


class WorkingCopyPage : public QWizardPage
{
public:
  WorkingCopyPage(QWidget *parent) : QWizardPage(parent)
  {
    setTitle( _q("working copy Bookmark") );

    QGridLayout* l = new QGridLayout();
    {
      QLineEdit* wcName = new QLineEdit( "", this );
      QLineEdit* wcPath = new QLineEdit( "", this );

      QLabel* labelName = new QLabel( wcName, _q("Name:"), this );
      QLabel* labelPath = new QLabel( wcPath, _q("Path:"), this );
      ExternButton* ext = new ExternButton(this);

      QLabel* text = new QLabel(
        _q("To add an existing working copy to the project "
        "choose a name and enter or select its working copy path"), this );
      text->setWordWrap(true);

      QTextEdit* info = new QTextEdit(this);
      info->setPlainText(
        _q("The working copy bookmark can be set or modified at any time from "
           "the project (context) menu or the bookmark (context) menu. Its name"
           " can also be changed by 'in place' editing the bookmark.\n\n"
           "Additional working copies can be added from the project (context) "
           "menu or by drag and drop (drag in a file explorer and drop on the "
           "project bookmark).") );
      info->setStyleSheet("QTextEdit { background: transparent }");
      info->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
      info->setFrameShape(QFrame::NoFrame);
      info->setReadOnly(true);
      
      l->setSpacing(10);
      l->addWidget( text,       0, 0, 1, 3 );
      l->addWidget( labelName,  1, 0 );
      l->addWidget( wcName,     1, 1 );
      l->addWidget( labelPath,  2, 0 );
      l->addWidget( wcPath,     2, 1 );
      l->addWidget( ext,        2, 2 );
      l->addWidget( info,       3, 0, 1, 3 );

      registerField("WcName*", wcName);
      registerField("WcPath*", wcPath);

      connect( ext,  SIGNAL(clicked()), parent, SLOT(selectPath()) );
    }
    setLayout(l);
  }

  bool isComplete() const
  {
    bool name = ! field("WcName").toString().isEmpty();
    bool path = ! field("WcPath").toString().isEmpty();

    bool complete = true;
    if( (name && !path) || (!name && path) )
      complete = false;

    if(complete)
      wizard()->page(nextId())->initializePage();

    return complete;
  }
};


class TrunkPage : public QWizardPage
{
public:
  TrunkPage(QWidget *parent) : QWizardPage(parent)
  {
    setTitle( _q("trunk Bookmark") );

    QGridLayout* l = new QGridLayout();
    {
      QLineEdit* trunkName = new QLineEdit( _q("trunk"), this );
      QLineEdit* trunkUrl  = new QLineEdit( "", this );
      QLabel*    text      = new QLabel( _q("enter the trunk url for your project"), this );
      QLabel*    labelName = new QLabel( trunkName, _q("Name:"), this );
      QLabel*    labelUrl  = new QLabel( trunkUrl, _q("URL:"), this );

      _wc  = new QPushButton( _q("get URL from working copy"), this );
      _wcl = new QLabel( _wc, _q("(<unset>)"), this );
      _wcl->setAlignment(Qt::AlignHCenter);
      
      QTextEdit* info  = new QTextEdit(this);
      info->setPlainText(
        _q("The trunk url is the projects repository url. Typically it is the "
           "url from which you checkout a project. For example the trunk url of"
           " the Subcommander repository is: "
           "\"http://subcommander.tigris.org/svn/subcommander/trunk\"\n\n"
           "It is recommended to set the trunk url because it simplifies "
           "checking out a fresh working copy from the repository or browsing "
           "the repositoy.\n\n"
           "If you do not set an url the trunk bookmark will not be visible. It"
           " can be set or modified at any time from the project (context) menu"
           " or the bookmark (context) menu. Its name can also be changed by "
           "'in place' editing the bookmark.") );
      info->setStyleSheet("QTextEdit { background: transparent }");
      info->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
      info->setFrameShape(QFrame::NoFrame);
      info->setReadOnly(true);
      

      l->setSpacing(10);
      l->addWidget( text,       0, 0, 1, 2 );
      l->addWidget( labelName,  1, 0 );
      l->addWidget( trunkName,  1, 1 );
      l->addWidget( labelUrl,   2, 0 );
      l->addWidget( trunkUrl,   2, 1 );
      l->addWidget( _wc,        3, 0, 1, 2 );
      l->addWidget( _wcl,       4, 0, 1, 2 );
      l->addWidget( info,       5, 0, 1, 2 );

      registerField("TrunkName*", trunkName);
      registerField("TrunkUrl*", trunkUrl);

      connect( _wc, SIGNAL(clicked()), parent, SLOT(trunkFromWc()) );
    }
    setLayout(l);
  }

  void initializePage()
  {
    QString qwcPath(field("WcPath").toString());
    sc::String wcPath( (const char*)qwcPath.toUtf8() );

    bool enable = ! wcPath.isEmpty() && svn::Client::isWorkingCopy(wcPath);
      _wc->setEnabled(enable);

    if( enable )
      _wcl->setText(_q("(%1)").arg(qwcPath));
    else
      _wcl->setText(_q("(%1)").arg(_q("<unset>")));
  }

  bool isComplete() const
  {
    bool name = ! field("TrunkName").toString().isEmpty();
    bool url = ! field("TrunkUrl").toString().isEmpty();

    bool complete = true;
    if( (name && !url) || (!name && url) )
      complete = false;

    if(complete)
      wizard()->page(nextId())->initializePage();

    return complete;
  }

private:
  QPushButton* _wc;
  QLabel*      _wcl;
};


class BranchesTagsPage : public QWizardPage
{
public:
  BranchesTagsPage(QWidget *parent) : QWizardPage(parent)
  {
    setTitle( _q("branches/tags Bookmarks") );

    QGridLayout* l = new QGridLayout();
    {
      QLineEdit* branchesName  = new QLineEdit( _q("branches"), this );
      QLineEdit* branchesUrl   = new QLineEdit( "", this );
      QLineEdit* tagsName      = new QLineEdit( _q("tags"), this );
      QLineEdit* tagsUrl       = new QLineEdit( "", this );

      QLabel* lBranchesName = new QLabel( branchesName, _q("branches Name:"), this );
      QLabel* lBranchesUrl  = new QLabel( branchesUrl, _q("branches URL:"), this );
      QLabel* lTagsName     = new QLabel( tagsName, _q("tags Name:"), this );
      QLabel* lTagsUrl      = new QLabel( tagsUrl, _q("tags URL:"), this );
      _std                  = new QPushButton( _q("Standard Layout"), this );

      QLabel* text = new QLabel( _q("enter the branches and tags url for "
        "your project. If you don't use branches or tags just press finish."), this );
      text->setWordWrap(true);

      QTextEdit* info  = new QTextEdit(this);
      info->setPlainText(
        _q("Setting both makes branching and tagging a lot easier because you "
           "will not have to select or enter a target url for a branch or tag "
           "when you like to create one. You will only have to give a name and "
           "subcommander will create it in the configured repository location.\n\n"
           "Use the 'Standard Layout' button to fill the urls based on the trunk"
           " url for the common trunk/branches/tags layout.\n\n"
           "If you do not set the urls the bookmarks will not be visible. Both "
           "bookmarks can be added or changed at any time from the project "
           "(context) menu or the bookmark (context) menu. Their names can also"
           " be changed by 'in place' editing the corresponding bookmark.") );
      info->setStyleSheet("QTextEdit { background: transparent }");
      info->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
      info->setFrameShape(QFrame::NoFrame);
      info->setReadOnly(true);
      
      l->setSpacing(10);
      l->addWidget( text,          0, 0, 1, 2 );
      l->addWidget( lBranchesName, 1, 0 );
      l->addWidget( branchesName,  1, 1 );
      l->addWidget( lBranchesUrl,  2, 0 );
      l->addWidget( branchesUrl,   2, 1 );
      l->addWidget( lTagsName,     3, 0 );
      l->addWidget( tagsName,      3, 1 );
      l->addWidget( lTagsUrl,      4, 0 );
      l->addWidget( tagsUrl,       4, 1 );
      l->addWidget( _std,          5, 0, 1, 2 );
      l->addWidget( info,          6, 0, 1, 2 );

      registerField("BranchesName*", branchesName);
      registerField("BranchesUrl*", branchesUrl);
      registerField("TagsName*", tagsName);
      registerField("TagsUrl*", tagsUrl);

      connect( _std, SIGNAL(clicked()), parent, SLOT(standardLayout()) );
    }
    setLayout(l);
  }

  void initializePage()
  {
    QString qTrunkUrl(field("TrunkUrl").toString());
    sc::String trunkUrl( (const char*)qTrunkUrl.toUtf8() );

    _std->setEnabled( !trunkUrl.isEmpty() );
  }

  bool isComplete() const
  {
    return true;
  }

private:
  QPushButton* _std;
};



ProjectWizard::ProjectWizard( QWidget* parent )
: super(parent,Qt::Dialog)
{
  setCaption( _q("subcommander:new project") );
  setOption(QWizard::IndependentPages,true);

  // fixed order! pages interact.
  addPage( new ProjectNamePage(this) );
  addPage( new WorkingCopyPage(this) );
  addPage( new TrunkPage(this) );
  addPage( new BranchesTagsPage(this) );
}

ProjectWizard::~ProjectWizard()
{
}

void ProjectWizard::standardLayout()
{
  QString root = field("TrunkUrl").toString();

  root.replace( QRegExp("/trunk(/*)$"), "" );
  QString tmp;

  tmp = root + "/branches";
  setField( "BranchesUrl", tmp );

  tmp = root + "/tags";
  setField( "TagsUrl", tmp );
}

void ProjectWizard::selectPath()
{
  QString res = QFileDialog::getExistingDirectory( field("WcPath").toString(),
    this, "get existing working copy", "subcommander:select working copy" );
  setField( "WcPath", res );
}

void ProjectWizard::trunkFromWc()
{
  sc::String wcPath = sc::String(field("WcPath").toString().utf8());
  sc::String wcUrl;

  svn::Client::getUrlFromPath( wcPath, wcUrl );

  setField( "TrunkUrl", QString::fromUtf8(wcUrl) );
}

QString ProjectWizard::getProjectName() const
{
  return field("ProjectName").toString();
}

QString ProjectWizard::getTrunkName() const
{
  return field("TrunkName").toString();
}

QString ProjectWizard::getTrunkUrl() const
{
  return field("TrunkUrl").toString();
}

QString ProjectWizard::getBranchesName() const
{
  return field("BranchesName").toString();
}

QString ProjectWizard::getBranchesUrl() const
{
  return field("BranchesUrl").toString();
}

QString ProjectWizard::getTagsName() const
{
  return field("TagsName").toString();
}

QString ProjectWizard::getTagsUrl() const
{
  return field("TagsUrl").toString();
}

QString ProjectWizard::getWcName() const
{
  return field("WcName").toString();
}

QString ProjectWizard::getWcPath() const
{
  return field("WcPath").toString();
}
