/*
 *  Copyright (C) 1999-2002 Bernd Gehrmann
 *                          bernd@mail.berlios.de
 *  Copyright (c) 2003-2004 Christian Loose <christian.loose@hamburg.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */


#include "checkoutdlg.h"

#include <tqcheckbox.h>
#include <tqcombobox.h>
#include <tqdir.h>
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqpushbutton.h>
#include <kprocess.h>
#include <tdefiledialog.h>
#include <klineedit.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kurlcompletion.h>

#include "progressdlg.h"
#include "repositories.h"
#include "misc.h"
#include "cvsservice_stub.h"

using Cervisia::IsValidTag;


CheckoutDialog::CheckoutDialog(TDEConfig& cfg, CvsService_stub* service,
                               ActionType action, TQWidget* parent,
                               const char* name)
    : KDialogBase(parent, name, true, TQString(),
                  Ok | Cancel | Help, Ok, true)
    , act(action)
    , partConfig(cfg)
    , cvsService(service)
{
    setCaption( (action==Checkout)? i18n("CVS Checkout") : i18n("CVS Import") );

    TQFrame* mainWidget = makeMainWidget();

    TQBoxLayout* layout = new TQVBoxLayout(mainWidget, 0, spacingHint());

    TQGridLayout* grid = new TQGridLayout(layout);
    grid->setColStretch(0, 1);
    grid->setColStretch(1, 20);
    for( int i = 0; i < ((action==Checkout)? 4 : 10); ++i )
        grid->setRowStretch(i, 0);

    repo_combo = new TQComboBox(true, mainWidget);
    repo_combo->setFocus();
    // make sure combobox is smaller than the screen
    repo_combo->setSizePolicy(TQSizePolicy::Preferred, TQSizePolicy::Fixed);
    grid->addWidget(repo_combo, 0, 1);

    TQLabel* repo_label = new TQLabel(repo_combo, i18n("&Repository:"), mainWidget);
    grid->addWidget(repo_label, 0, 0, AlignLeft | AlignVCenter);

    if( action == Import )
    {
        module_edit = new KLineEdit(mainWidget);
        grid->addWidget(module_edit, 1, 1);
        TQLabel* module_label = new TQLabel(module_edit, i18n("&Module:"), mainWidget);
        grid->addWidget(module_label, 1, 0, AlignLeft | AlignVCenter);
    }
    else
    {
        module_combo = new TQComboBox(true, mainWidget);

        TQPushButton* module_button = new TQPushButton(i18n("Fetch &List"), mainWidget);
        connect( module_button, TQ_SIGNAL(clicked()),
                 this, TQ_SLOT(moduleButtonClicked()) );

        TQBoxLayout* module_layout = new TQHBoxLayout();
        grid->addLayout(module_layout, 1, 1);
        module_layout->addWidget(module_combo, 10);
        module_layout->addWidget(module_button, 0, AlignVCenter);

        TQLabel* module_label = new TQLabel(module_combo, i18n("&Module:"), mainWidget);
        grid->addWidget(module_label, 1, 0, AlignLeft | AlignVCenter);

        branchCombo = new TQComboBox(true, mainWidget);

        TQPushButton* branchButton = new TQPushButton(i18n("Fetch &List"), mainWidget);
        connect( branchButton, TQ_SIGNAL(clicked()),
                 this, TQ_SLOT(branchButtonClicked()) );

        TQBoxLayout* branchLayout = new TQHBoxLayout();
        grid->addLayout(branchLayout, 2, 1);
        branchLayout->addWidget(branchCombo, 10);
        branchLayout->addWidget(branchButton, 0, AlignVCenter);

        TQLabel* branch_label = new TQLabel(branchCombo, i18n("&Branch tag:"), 
                                          mainWidget);
        grid->addWidget(branch_label, 2, 0, AlignLeft | AlignVCenter);

        connect( branchCombo, TQ_SIGNAL( textChanged( const TQString&)),
                 this, TQ_SLOT( branchTextChanged() ));

        recursive_box = new TQCheckBox(i18n("Re&cursive checkout"), mainWidget);
        grid->addMultiCellWidget(recursive_box, 6, 6, 0, 1);
    }

    workdir_edit = new KLineEdit(mainWidget);
    workdir_edit->setText(TQDir::homeDirPath());
    workdir_edit->setMinimumWidth(fontMetrics().width('X') * 40);
    
    KURLCompletion* comp = new KURLCompletion();
    workdir_edit->setCompletionObject(comp);
    workdir_edit->setAutoDeleteCompletionObject(true);
    connect( workdir_edit, TQ_SIGNAL(returnPressed(const TQString&)),
             comp, TQ_SLOT(addItem(const TQString&)) );

    TQPushButton* dir_button = new TQPushButton("...", mainWidget);
    connect( dir_button, TQ_SIGNAL(clicked()),
             this, TQ_SLOT(dirButtonClicked()) );
    dir_button->setFixedWidth(30);

    TQBoxLayout* workdir_layout = new TQHBoxLayout();
    grid->addLayout(workdir_layout, (action==Import)? 2 : 3, 1);
    workdir_layout->addWidget(workdir_edit, 10);
    workdir_layout->addWidget(dir_button, 0, AlignVCenter);

    TQLabel* workdir_label = new TQLabel(workdir_edit, i18n("Working &folder:"), 
                                       mainWidget);
    grid->addWidget(workdir_label, (action==Import)? 2 : 3, 0, AlignLeft | AlignVCenter);

    if( action == Import )
    {
        vendortag_edit = new KLineEdit(mainWidget);
        grid->addWidget(vendortag_edit, 3, 1);

        TQLabel* vendortag_label = new TQLabel(vendortag_edit, i18n("&Vendor tag:"), 
                                             mainWidget);
        grid->addWidget(vendortag_label, 3, 0, AlignLeft | AlignVCenter);

        releasetag_edit = new KLineEdit(mainWidget);
        grid->addWidget(releasetag_edit, 4, 1);

        TQLabel* releasetag_label = new TQLabel(releasetag_edit, i18n("&Release tag:"),
                                              mainWidget);
        grid->addWidget(releasetag_label, 4, 0, AlignLeft | AlignVCenter);

        ignore_edit = new KLineEdit(mainWidget);
        grid->addWidget(ignore_edit, 5, 1);

        TQLabel* ignore_label = new TQLabel(ignore_edit, i18n("&Ignore files:"), 
                                          mainWidget);
        grid->addWidget(ignore_label, 5, 0, AlignLeft | AlignVCenter);

        comment_edit = new KLineEdit(mainWidget);
        grid->addWidget(comment_edit, 6, 1);

        TQLabel* comment_label = new TQLabel(comment_edit, i18n("&Comment:"), 
                                           mainWidget);
        grid->addWidget(comment_label, 6, 0, AlignLeft | AlignVCenter);

        binary_box = new TQCheckBox(i18n("Import as &binaries"), mainWidget);
        grid->addMultiCellWidget(binary_box, 7, 7, 0, 1);

        m_useModificationTimeBox = new TQCheckBox(
                i18n("Use file's modification time as time of import"), mainWidget);
        grid->addMultiCellWidget(m_useModificationTimeBox, 8, 8, 0, 1);
    }
    else
    {
        alias_edit = new KLineEdit(mainWidget);
        grid->addWidget(alias_edit, 4, 1);

        TQLabel* alias_label = new TQLabel(alias_edit, i18n("Chec&k out as:"), mainWidget);
        grid->addWidget(alias_label, 4, 0, AlignLeft | AlignVCenter);

        export_box = new TQCheckBox(i18n("Ex&port only"), mainWidget);
        grid->addMultiCellWidget(export_box, 5, 5, 0, 1);
    }

    TQStringList list1 = Repositories::readCvsPassFile();
    TQStringList::ConstIterator it1;
    for (it1 = list1.begin(); it1 != list1.end(); ++it1)
        repo_combo->insertItem(*it1);

    TQStringList list2 = Repositories::readConfigFile();
    TQStringList::ConstIterator it2;
    for (it2 = list2.begin(); it2 != list2.end(); ++it2)
        if (!list1.contains(*it2))
            repo_combo->insertItem(*it2);

    setHelp((act == Import) ? "importing" : "checkingout");
    
    restoreUserInput();
}


TQString CheckoutDialog::workingDirectory() const
{
    return workdir_edit->text();
}


TQString CheckoutDialog::repository() const
{
    return repo_combo->currentText();
}


TQString CheckoutDialog::module() const
{
    return act==Import? module_edit->text() : module_combo->currentText();
}


TQString CheckoutDialog::branch() const
{
    return branchCombo->currentText();
}


TQString CheckoutDialog::vendorTag() const
{
    return vendortag_edit->text();
}


TQString CheckoutDialog::releaseTag() const
{
    return releasetag_edit->text();
}


TQString CheckoutDialog::ignoreFiles() const
{
    return ignore_edit->text();
}


TQString CheckoutDialog::comment() const
{
    return comment_edit->text();
}

TQString CheckoutDialog::alias() const
{
    return alias_edit->text();
}

bool CheckoutDialog::importBinary() const
{
    return binary_box->isChecked();
}

bool CheckoutDialog::useModificationTime() const
{
    return m_useModificationTimeBox->isChecked();
}

bool CheckoutDialog::exportOnly() const
{
    if( export_box->isEnabled() )
        return export_box->isChecked();

    return false;
}

bool CheckoutDialog::recursive() const
{
    return recursive_box->isChecked();
}

void CheckoutDialog::slotOk()
{
    TQFileInfo fi(workingDirectory());
    if (!fi.exists() || !fi.isDir())
    {
        KMessageBox::information(this, i18n("Please choose an existing working folder."));
        return;
    }
    if (module().isEmpty())
    {
        KMessageBox::information(this, i18n("Please specify a module name."));
        return;
    }

    if (act==Import)
    {
        if (vendorTag().isEmpty() || releaseTag().isEmpty())
        {
            KMessageBox::information(this,
                                     i18n("Please specify a vendor tag and a release tag."));
            return;
        }
        if (!IsValidTag(vendorTag()) || !IsValidTag(releaseTag()))
        {
            KMessageBox::information(this,
                                     i18n("Tags must start with a letter and may contain\n"
                                          "letters, digits and the characters '-' and '_'."));
            return;
        }
    }
    else
    {
        if( branch().isEmpty() && exportOnly() )
        {
            KMessageBox::information(this,
                            i18n("A branch must be specified for export."));
            return;
        }
    }
    
    saveUserInput();
    
    KDialogBase::slotOk();
}


void CheckoutDialog::dirButtonClicked()
{
    TQString dir = KFileDialog::getExistingDirectory(workdir_edit->text());
    if (!dir.isEmpty())
        workdir_edit->setText(dir);
}


void CheckoutDialog::moduleButtonClicked()
{
    DCOPRef cvsJob = cvsService->moduleList(repository());
    if( !cvsService->ok() )
        return;

    ProgressDialog dlg(this, "Checkout", cvsJob, "checkout", i18n("CVS Checkout"));
    if( !dlg.execute() )
        return;

    module_combo->clear();
    TQString str;
    while (dlg.getLine(str))
    {
        if (str.left(12) == "Unknown host")
            continue;

        int pos = str.find(' ');
        if (pos == -1)
            pos = str.find('\t');
        if (pos == -1)
            pos = str.length();
        TQString module( str.left(pos).stripWhiteSpace() );
        if ( !module.isEmpty() )
            module_combo->insertItem(module);
    }
}


void CheckoutDialog::branchButtonClicked()
{
    TQStringList branchTagList;

    if( repository().isEmpty() )
    {
        KMessageBox::information(this, i18n("Please specify a repository."));
        return;
    }

    if( module().isEmpty() )
    {
        KMessageBox::information(this, i18n("Please specify a module name."));
        return;
    }

    DCOPRef cvsJob = cvsService->rlog(repository(), module(), 
                                      false/*recursive*/);
    if( !cvsService->ok() )
        return;

    ProgressDialog dlg(this, "Remote Log", cvsJob, TQString(), 
                       i18n("CVS Remote Log"));
    if( !dlg.execute() )
        return;

    TQString line;
    while( dlg.getLine(line) )
    {
        int colonPos;

        if( line.isEmpty() || line[0] != '\t' )
            continue;
        if( (colonPos = line.find(':', 1)) < 0 )
           continue;

        const TQString tag  = line.mid(1, colonPos - 1);
        if( !branchTagList.contains(tag) )
            branchTagList.push_back(tag);
    }

    branchTagList.sort();

    branchCombo->clear();
    branchCombo->insertStringList(branchTagList);
}


void CheckoutDialog::restoreUserInput()
{
    TDEConfigGroupSaver cs(&partConfig, "CheckoutDialog");

    repo_combo->setEditText(partConfig.readEntry("Repository"));
    workdir_edit->setText(partConfig.readPathEntry("Working directory"));

    if (act == Import)
    {
        module_edit->setText(partConfig.readEntry("Module"));
        vendortag_edit->setText(partConfig.readEntry("Vendor tag"));
        releasetag_edit->setText(partConfig.readEntry("Release tag"));
        ignore_edit->setText(partConfig.readEntry("Ignore files"));
        binary_box->setChecked(partConfig.readBoolEntry("Import binary"));
    }
    else
    {
        module_combo->setEditText(partConfig.readEntry("Module"));
        branchCombo->setCurrentText(partConfig.readEntry("Branch"));
        alias_edit->setText(partConfig.readEntry("Alias"));
        export_box->setChecked(partConfig.readBoolEntry("ExportOnly"));
        recursive_box->setChecked(true);
    }
}


void CheckoutDialog::saveUserInput()
{
    TDEConfigGroupSaver cs(&partConfig, "CheckoutDialog");

    partConfig.writeEntry("Repository", repository());
    partConfig.writeEntry("Module", module());
    partConfig.writeEntry("Working directory", workingDirectory());

    if (act == Import)
    {
        partConfig.writeEntry("Vendor tag", vendorTag());
        partConfig.writeEntry("Release tag", releaseTag());
        partConfig.writeEntry("Ignore files", ignoreFiles());
        partConfig.writeEntry("Import binary", importBinary());
    }
    else
    {
        partConfig.writeEntry("Branch", branch());
        partConfig.writeEntry("Alias", alias());
        partConfig.writeEntry("ExportOnly", exportOnly());
    }
}

void CheckoutDialog::branchTextChanged()
{
    if( branch().isEmpty() )
    {
        export_box->setEnabled(false);
        export_box->setChecked(false);
    }
    else
    {
        export_box->setEnabled(true);
    }
}


#include "checkoutdlg.moc"