/***************************************************************************
 *   Copyright (C) 2005-2007 by Rajko Albrecht                             *
 *   rajko.albrecht@tecways.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.                                   *
 *                                                                         *
 *   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 "tdesvn-config.h"
#include "tdesvnd_dcop.h"
#include "authdialogimpl.h"
#include "ssltrustprompt_impl.h"
#include "logmsg_impl.h"
#include "tdesvnsettings.h"
#include "pwstorage.h"
#include "client.h"
#include "revision.h"
#include "status.h"
#include "context_listener.h"
#include "url.h"
#include "ktranslateurl.h"

#include <kdebug.h>
#include <tdeapplication.h>
#include <tdemessagebox.h>
#include <tdelocale.h>
#include <tdeglobal.h>
#include <tdefiledialog.h>
#include <kpassdlg.h>

#include <tqdir.h>

extern "C" {
    KDESVN_EXPORT KDEDModule *create_tdesvnd(const TQCString &name)
    {
       return new tdesvnd_dcop(name);
    }
}

class IListener:public svn::ContextListener
{
    friend class tdesvnd_dcop;

    tdesvnd_dcop*m_back;
public:
    IListener(tdesvnd_dcop*p);
    virtual ~IListener();
    /* context-listener methods */
    virtual bool contextGetLogin (const TQString & realm,
                                  TQString & username,
                                  TQString & password,
                                  bool & maySave);
    virtual bool contextGetSavedLogin (const TQString & realm,TQString & username,TQString & password);
    virtual bool contextGetCachedLogin (const TQString & realm,TQString & username,TQString & password);

    virtual void contextNotify (const char *path,
                                svn_wc_notify_action_t action,
                                svn_node_kind_t kind,
                                const char *mime_type,
                                svn_wc_notify_state_t content_state,
                                svn_wc_notify_state_t prop_state,
                                svn_revnum_t revision);
    virtual void contextNotify (const svn_wc_notify_t *action);

    virtual bool contextCancel();
    virtual bool contextGetLogMessage (TQString & msg,const svn::CommitItemList&);
    virtual svn::ContextListener::SslServerTrustAnswer
            contextSslServerTrustPrompt (const SslServerTrustData & data,
            apr_uint32_t & acceptedFailures);
    virtual bool contextSslClientCertPrompt (TQString & certFile);
    virtual bool contextLoadSslClientCertPw(TQString&password,const TQString&realm);
    virtual bool contextSslClientCertPwPrompt (TQString & password,
                                               const TQString & realm, bool & maySave);
    virtual void contextProgress(long long int current, long long int max);

    /* context listener virtuals end */

protected:
    svn::Client* m_Svnclient;
    svn::ContextP m_CurrentContext;
};

IListener::IListener(tdesvnd_dcop*p)
    :svn::ContextListener()
{
    m_Svnclient = svn::Client::getobject(0,0);
    m_back=p;
    m_CurrentContext = new svn::Context();
    m_CurrentContext->setListener(this);
    m_Svnclient->setContext(m_CurrentContext);
}

IListener::~IListener()
{
}

tdesvnd_dcop::tdesvnd_dcop(const TQCString&name) : KDEDModule(name)
{
    TDEGlobal::locale()->insertCatalogue("tdesvn");
    m_Listener=new IListener(this);
}

tdesvnd_dcop::~tdesvnd_dcop()
{
    delete m_Listener;
}

TQStringList tdesvnd_dcop::getActionMenu (const KURL::List list)
{
    TQStringList result;
    Kdesvnsettings::self()->readConfig();
    if (Kdesvnsettings::no_konqueror_contextmenu()||list.count()==0) {
        return result;
    }
    TQString base;


    bool parentIsWc = false;
    bool itemIsWc = isWorkingCopy(list[0],base);
    bool itemIsRepository = false;

    TQString _par = list[0].directory(true,true);
    parentIsWc = isWorkingCopy(_par,base);

    if (!parentIsWc && !itemIsWc) {
        itemIsRepository = isRepository(list[0]);
    }

    if (!itemIsWc) {
        if (itemIsRepository) {
            result << "Export"
                   << "Checkout";
        } else {
            result << "Exportto"
                   << "Checkoutto";
        }
    } else {
        result << "Update"
               << "Commit";
    }

    if (!parentIsWc && !itemIsWc) {
        if (itemIsRepository) {
            result << "Log"
                    << "Info";
            if (isRepository(list[0].upURL())) {
                result << "Blame"
                        << "Rename";
            }
            result << "Tree";
        }
        return result;
    }

    if (!itemIsWc) {
        result << "Add";
        return result;
    }

    result << "Log"
        << "Tree"
        << "Info"
        << "Diff"
        << "Rename"
        << "Revert";

    KURL url = helpers::KTranslateUrl::translateSystemUrl(list[0]);

    TQFileInfo f(url.path());
    if (f.isFile()) {
        result << "Blame";
    }

    if (f.isDir()) {
        result << "Addnew";
        result << "Switch";
    }

    return result;
}

TQStringList tdesvnd_dcop::getSingleActionMenu(TQCString what)
{
    KURL::List l; l.append(KURL(what));
    return getActionMenu(l);
}

TQStringList tdesvnd_dcop::get_login(TQString realm,TQString user)
{
    AuthDialogImpl auth(realm,user);
    TQStringList res;
    if (auth.exec()==TQDialog::Accepted) {
        res.append(auth.Username());
        res.append(auth.Password());
        if (auth.maySave()) {
            res.append("true");
        } else {
            res.append("false");
        }
    }
    return res;
}

int tdesvnd_dcop::get_sslaccept(TQString hostname,TQString fingerprint,TQString validFrom,TQString validUntil,TQString issuerDName,TQString realm)
{
    bool ok,saveit;
    if (!SslTrustPrompt_impl::sslTrust(
        hostname,
        fingerprint,
        validFrom,
        validUntil,
        issuerDName,
        realm,
        TQStringList(),
        &ok,&saveit)) {
        return -1;
    }
    if (!saveit) {
        return 0;
    }
    return 1;
}

TQStringList tdesvnd_dcop::get_sslclientcertpw(TQString realm)
{
    TQStringList resList;
    TQString npass;
    int keep = 1;
    int res = KPasswordDialog::getPassword(npass,i18n("Enter password for realm %1").arg(realm),&keep);
    if (res!=KPasswordDialog::Accepted) {
        return resList;
    }
    resList.append(npass);
    if (keep) {
        resList.append("true");
    } else {
        resList.append("false");
    }
    return resList;
}

TQString tdesvnd_dcop::get_sslclientcertfile()
{
    TQString afile = KFileDialog::getOpenFileName(TQString(),
        TQString(),
        0,
        i18n("Open a file with a #PKCS12 certificate"));
    return afile;
}

TQStringList tdesvnd_dcop::get_logmsg()
{
    TQStringList res;
    bool ok;
    TQString logMessage = Logmsg_impl::getLogmessage(&ok,0,0,0,"logmsg_impl");
    if (!ok) {
        return res;
    }
    res.append(logMessage);
    return res;
}

TQStringList tdesvnd_dcop::get_logmsg(TQMap<TQString,TQString> list)
{
    TQStringList res;
    bool ok;
    TQString logMessage = Logmsg_impl::getLogmessage(list,&ok,0,0,0,"logmsg_impl");
    if (!ok) {
        return res;
    }
    res.append(logMessage);
    return res;
}

TQString tdesvnd_dcop::cleanUrl(const KURL&url)
{
    TQString cleanpath = url.path();
    while (cleanpath.endsWith("/")) {
        cleanpath.truncate(cleanpath.length()-1);
    }
    return cleanpath;
}

/* just simple name check of course - no network acess! */
bool tdesvnd_dcop::isRepository(const KURL&url)
{
    kdDebug()<<"tdesvnd_dcop::isRepository Url zum repo check: "<<url<<endl;
    TQString proto = svn::Url::transformProtokoll(url.protocol());
    kdDebug()<<"tdesvnd_dcop::isRepository Protokoll: " << proto << endl;
    if (proto=="file") {
        // local access - may a repository
        svn::Revision where = svn::Revision::HEAD;
        svn::StatusEntries dlist;
        try {
            m_Listener->m_Svnclient->status("file://"+cleanUrl(url),svn::DepthEmpty,false,false,false,where);
        } catch (const svn::ClientException&e) {
            kdDebug()<< e.msg()<<endl;
            return false;
        }
        return true;
    } else {
        return svn::Url::isValid(proto);
    }
}

bool tdesvnd_dcop::isWorkingCopy(const KURL&_url,TQString&base)
{
    base = "";
    KURL url = _url;
    url = helpers::KTranslateUrl::translateSystemUrl(url);

    if (url.isEmpty()||!url.isLocalFile()||url.protocol()!="file") return false;
    svn::Revision peg(svn_opt_revision_unspecified);
    svn::Revision rev(svn_opt_revision_unspecified);
    svn::InfoEntries e;
    try {
        e = m_Listener->m_Svnclient->info(cleanUrl(url),svn::DepthEmpty,rev,peg);
    } catch (const svn::ClientException&e) {
        kdDebug()<< e.msg()<<endl;
        return false;
    }
    base=e[0].url();
    return true;
}

bool IListener::contextGetSavedLogin (const TQString & realm,TQString & username,TQString & password)
{
    PwStorage::self()->getLogin(realm,username,password);
    return true;
}

bool IListener::contextGetCachedLogin (const TQString & realm,TQString & username,TQString & password)
{
    return true;
}

bool IListener::contextGetLogin (const TQString & realm,
                                  TQString & username,
                                  TQString & password,
                                  bool & maySave)
{
    maySave=false;
    TQStringList res = m_back->get_login(realm,username);
    if (res.count()!=3) {
        return false;
    }
    username = res[0];
    password = res[1];
    maySave = (res[2]=="true");
    if (maySave && Kdesvnsettings::passwords_in_wallet() ) {
        PwStorage::self()->setLogin(realm,username,password);
        maySave=false;
    }
    return true;
}

void IListener::contextNotify(const char * /*path*/,
                                 svn_wc_notify_action_t /*action*/,
                                 svn_node_kind_t /*kind*/,
                                 const char */*mime_type*/,
                                 svn_wc_notify_state_t /*content_state*/,
                                 svn_wc_notify_state_t /*prop_state*/,
                                 svn_revnum_t /*revision*/)
{
}

void IListener::contextNotify(const svn_wc_notify_t * /*action*/)
{
}

bool IListener::contextCancel()
{
    return false;
}

bool IListener::contextGetLogMessage (TQString & msg,const svn::CommitItemList&)
{
    TQStringList res = m_back->get_logmsg();
    if (res.count()==0) {
        return false;
    }
    msg = res[1];
    return true;
}

svn::ContextListener::SslServerTrustAnswer IListener::contextSslServerTrustPrompt (const SslServerTrustData & data,
        apr_uint32_t & /*acceptedFailures*/)
{
    int res = m_back->get_sslaccept(data.hostname,
            data.fingerprint,
            data.validFrom,
            data.validUntil,
            data.issuerDName,
            data.realm);
    switch (res) {
        case -1:
            return DONT_ACCEPT;
            break;
        case 1:
            return ACCEPT_PERMANENTLY;
            break;
        default:
        case 0:
            return ACCEPT_TEMPORARILY;
            break;
    }
    /* avoid compiler warnings */
    return ACCEPT_TEMPORARILY;
}

bool IListener::contextSslClientCertPrompt (TQString & certFile)
{
    certFile = m_back->get_sslclientcertfile();
    if (certFile.isEmpty()) {
        return false;
    }
    return true;
}

bool IListener::contextLoadSslClientCertPw(TQString&password,const TQString&realm)
{
    return PwStorage::self()->getCertPw(realm,password);
}

bool IListener::contextSslClientCertPwPrompt (TQString & password,
                                   const TQString & realm, bool & maySave)
{
    maySave=false;
    if (PwStorage::self()->getCertPw(realm,password)) {
        return true;
    }
    TQStringList res = m_back->get_sslclientcertpw(realm);
    if (res.size()!=2) {
        return false;
    }
    password=res[0];
    maySave=res[1]==TQString("true");

    if (maySave && Kdesvnsettings::passwords_in_wallet() ) {
        PwStorage::self()->setCertPw(realm,password);
        maySave=false;
    }

    return true;
}

void IListener::contextProgress(long long int, long long int)
{
}