/***************************************************************************
 *   Copyright (C) 2003 by Ajay Guleria                                    *
 *   ajay_guleria at yahoo dot com                                         *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "clearcasepart.h"
#include "commentdlg.h"

#include <tqfileinfo.h>
#include <tqpopupmenu.h>

#include <tdepopupmenu.h>
#include <kdebug.h>
#include <kdevgenericfactory.h>
#include <tdelocale.h>
#include <kprocess.h>
#include <tdemessagebox.h>
#include <tdeapplication.h>

#include "kdevcore.h"
#include "kdevmakefrontend.h"
#include "kdevdifffrontend.h"
#include "kdevappfrontend.h"
#include "execcommand.h"
#include "domutil.h"
#include "kdevmainwindow.h"
#include "kdevproject.h"
#include "kdevplugininfo.h"

#include "clearcasefileinfoprovider.h"
#include "clearcasemanipulator.h"


static const KDevPluginInfo pluginData("kdevclearcase");

typedef KDevGenericFactory<ClearcasePart> ClearcaseFactory;
K_EXPORT_COMPONENT_FACTORY( libkdevclearcase, ClearcaseFactory( pluginData ) )

ClearcasePart::ClearcasePart( TQObject *parent, const char *name, const TQStringList & )
        : KDevVersionControl( &pluginData, parent, name ? name : "ClearcasePart" ),
          default_checkin(""),
          default_checkout(""),
          default_uncheckout("-rm"),
          default_create("-ci"),
          default_remove("-f"),
          default_lshistory(""),
          default_diff("-pred -diff"),
          default_lscheckout("-recurse")
{

    // check if project directory is valid and cache it
    isValidCCDirectory_ = ClearcaseManipulator::isCCRepository( project()->projectDirectory() );

    fileInfoProvider_ = new ClearcaseFileinfoProvider(this);

    setInstance(ClearcaseFactory::instance());
    connect( core(), TQ_SIGNAL(contextMenu(TQPopupMenu *, const Context *)),
             this, TQ_SLOT(contextMenu(TQPopupMenu *, const Context *)) );
}

ClearcasePart::~ClearcasePart()
{}



bool ClearcasePart::isValidDirectory(const TQString &dirPath) const {
    return isValidCCDirectory_;
}


void ClearcasePart::contextMenu(TQPopupMenu *popup, const Context *context)
{

    if (context->hasType( Context::FileContext )) {
        const FileContext *fcontext = static_cast<const FileContext*>(context);
        popupfile_ = fcontext->urls().first().path();

        TQFileInfo fi(popupfile_);
        popup->insertSeparator();

        TDEPopupMenu *sub = new TDEPopupMenu(popup);
        TQString name = fi.fileName();
        sub->insertTitle( i18n("Actions for %1").arg(name) );
        sub->insertItem( i18n("Checkin"),
                         this, TQ_SLOT(slotCheckin()) );
        sub->insertItem( i18n("Checkout"),
                         this, TQ_SLOT(slotCheckout()) );
        sub->insertItem( i18n("Uncheckout"),
                         this, TQ_SLOT(slotUncheckout()) );
        sub->insertSeparator();
        sub->insertItem( i18n("Create Element"),
                         this, TQ_SLOT(slotCreate()) );
        sub->insertItem( i18n("Remove Element"),
                         this, TQ_SLOT(slotRemove()) );
        sub->insertSeparator();
        sub->insertItem( i18n("History"),
                         this, TQ_SLOT(slotListHistory()) );
        sub->insertSeparator();
        sub->insertItem( i18n("Diff"),
                         this, TQ_SLOT(slotDiff()) );

        sub->insertSeparator();
        sub->insertItem( i18n("List Checkouts"),
                         this, TQ_SLOT(slotListCheckouts()) );

        popup->insertItem(i18n("Clearcase"), sub);

	if (!project() || !isValidDirectory( project()->projectDirectory() )) {
	    sub->setEnabled( false );
	}
    }
}


void ClearcasePart::slotCheckin()
{
    TQString dir, name;
    TQFileInfo fi(popupfile_);
    dir = fi.dirPath();
    name = fi.fileName();

    CcaseCommentDlg dlg(FALSE);
    if (dlg.exec() == TQDialog::Rejected)
        return;

    TQDomDocument &dom = *this->projectDom();
    TQString message = DomUtil::readEntry(dom,"/kdevclearcase/checkin_options",default_checkin);
    if(dlg.logMessage().isEmpty())
        message += "-nc ";
    else
        message += "-c \"" + dlg.logMessage() + "\"";

    TQString command("cd ");
    command += KShellProcess::quote(dir);
    command += " && ";
    command += " cleartool checkin ";
    command += message; // Already quoted, see above
    command += " ";
    command += KShellProcess::quote(name);

    if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("TDevelop/MakeFrontend"))
        makeFrontend->queueCommand(dir, command);
}


void ClearcasePart::slotCheckout()
{
    TQString dir, name;
    TQFileInfo fi(popupfile_);
    dir = fi.dirPath();
    name = fi.fileName();

    CcaseCommentDlg dlg(TRUE);
    if (dlg.exec() == TQDialog::Rejected)
        return;

    TQDomDocument &dom = *this->projectDom();
    TQString message = DomUtil::readEntry(dom,"/kdevclearcase/checkout_options",default_checkout);
    if(!dlg.isReserved())
       message += "-unres ";
    if(dlg.logMessage().isEmpty())
       message += "-nc ";
    else
       message += "-c \"" + dlg.logMessage() + "\"";

    TQString command("cd ");
    command += KShellProcess::quote(dir);
    command += " && cleartool checkout ";
    command += message;
    command += " ";
    command += KShellProcess::quote(name);

    if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("TDevelop/MakeFrontend"))
        makeFrontend->queueCommand(dir, command);

    emit finishedFetching(dir);
}


void ClearcasePart::slotUncheckout()
{
    TQString dir, name;
    TQFileInfo fi(popupfile_);
    dir = fi.dirPath();
    name = fi.fileName();

    TQDomDocument &dom = *this->projectDom();

    TQString command("cd ");
    command += KShellProcess::quote(dir);
    command += " && cleartool uncheckout ";
    command += DomUtil::readEntry(dom,"/kdevclearcase/uncheckout_options",default_uncheckout);
    command += " ";
    command += KShellProcess::quote(name);

    if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("TDevelop/MakeFrontend"))
        makeFrontend->queueCommand(dir, command);

    emit finishedFetching(dir);
}

void ClearcasePart::slotCreate()
{
    TQFileInfo fi(popupfile_);
    TQString dir = fi.dirPath();
    TQString name = fi.fileName();

    TQDomDocument &dom = *this->projectDom();

    // Checking whether current directory is checked out or not is cumbersome so skip it for now
    TQString command("cd ");
    command += KShellProcess::quote(dir);
    TQFileInfo di(dir);
    if(!di.isWritable()) { // Work-around to check if directory is checked out
        command += " && cleartool co -unres -nc ";
        command += KShellProcess::quote(dir);
    }
    command += " && cleartool mkelem ";
    if(fi.isDir())
        command += " -elt directory ";
    command += DomUtil::readEntry(dom,"/kdevclearcase/create_options",default_create);
    command += " ";
    command += KShellProcess::quote(name);

    if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("TDevelop/MakeFrontend"))
        makeFrontend->queueCommand(dir, command);

    emit finishedFetching(dir);
}


void ClearcasePart::slotRemove()
{
    TQFileInfo fi(popupfile_);
    TQString dir = fi.dirPath();
    TQString name = fi.fileName();

    TQDomDocument &dom = *this->projectDom();

    TQString command("cd ");
    command += KShellProcess::quote(dir);
    TQFileInfo di(dir);
    if(!di.isWritable()) { // Work-around to check if directory is checked out
        command += " && cleartool co -unres -nc ";
        command += KShellProcess::quote(dir);
    }
    command += " && cleartool rmname "; // Don't use rm command
    command += DomUtil::readEntry(dom,"/kdevclearcase/remove_options",default_remove);
    command += " ";
    command += KShellProcess::quote(name);

    if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("TDevelop/MakeFrontend"))
        makeFrontend->queueCommand(dir, command);

    emit finishedFetching(dir);
}

void ClearcasePart::slotListHistory()
{
    TQFileInfo fi(popupfile_);
    TQString dir = fi.dirPath();
    TQString name = fi.fileName();
    TQStringList args;
    TQStringList env;
    TQString str;

    TQDomDocument &dom = *this->projectDom();

    TQString command("cd ");
    command += KShellProcess::quote(dir);
    command += " && cleartool lshistory ";
    command += DomUtil::readEntry(dom, "/kdevclearcase/lshistory_options", default_lshistory);
    command += " ";
    command += KShellProcess::quote(name);

    if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("TDevelop/MakeFrontend"))
        makeFrontend->queueCommand(dir, command);
}

void ClearcasePart::slotDiff()
{
    TQFileInfo fi(popupfile_);
    TQString dir = fi.dirPath();
    TQString name = fi.fileName();
    TQStringList args;
    TQStringList env;
    TQString str;

    TQDomDocument &dom = *this->projectDom();

    args << "diff";
    str = DomUtil::readEntry(dom,"/kdevclearcase/diff_options",default_diff);
    if (str.length()) {
        TQStringList list = TQStringList::split(' ',str);
        for(TQStringList::Iterator it = list.begin(); it != list.end(); ++it) args << *it;
    }

    args << name;

    ExecCommand* cmv = new ExecCommand( "cleartool", args, dir, env, this );
    connect( cmv, TQ_SIGNAL(finished( const TQString&, const TQString& )),
             this, TQ_SLOT(slotDiffFinished( const TQString&, const TQString& )) );
}


void ClearcasePart::slotDiffFinished( const TQString& diff, const TQString& err )
{
    if ( diff.isNull() && err.isNull() ) {
        kdDebug(9000) << "clearcase diff canceled" << endl;
        return; // user pressed cancel or an error occured
    }

    if ( diff.isEmpty() && !err.isEmpty() ) {
        KMessageBox::detailedError( 0, i18n("Clearcase output errors during diff."), err, i18n("Errors During Diff") );
        return;
    }

    if ( !err.isEmpty() ) {
        int s = KMessageBox::warningContinueCancelList( 0, i18n("Clearcase outputted errors during diff. Do you still want to continue?"),
                TQStringList::split( "\n", err, false ), i18n("Errors During Diff") );
        if ( s != KMessageBox::Continue )
            return;
    }

    if ( diff.isEmpty() ) {
        KMessageBox::information( 0, i18n("There is no difference to the repository."), i18n("No Difference Found") );
        return;
    }

    if (KDevDiffFrontend *diffFrontend = extension<KDevDiffFrontend>("TDevelop/DiffFrontend"))
        diffFrontend->showDiff( diff );
}

void ClearcasePart::slotListCheckouts()
{
    TQString dir;
    TQFileInfo fi(popupfile_);
    if (fi.isDir()) {
        dir = fi.absFilePath();
    } else {
        dir = fi.dirPath();
    }

    TQDomDocument &dom = *this->projectDom();

    TQString command("cd ");
    command += KShellProcess::quote(dir);
    command += " && cleartool lsco ";
    command += DomUtil::readEntry(dom, "/kdevclearcase/lscheckout_options", default_lscheckout);

    if (KDevMakeFrontend *makeFrontend = extension<KDevMakeFrontend>("TDevelop/MakeFrontend"))
        makeFrontend->queueCommand(dir, command);

}


#include "clearcasepart.moc"
