/***************************************************************************
 *   Copyright (C) 2005-2007 by Rajko Albrecht                             *
 *   ral@alwins-world.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 "tdesvnview.h"
#include "svnfrontend/tdesvnfilelist.h"
#include "svnfrontend/createrepo_impl.h"
#include "svnfrontend/dumprepo_impl.h"
#include "svnfrontend/hotcopydlg_impl.h"
#include "svnfrontend/loaddmpdlg_impl.h"
#include "svnfrontend/stopdlg.h"
#include "svnfrontend/fronthelpers/propertylist.h"
#include "tdesvnsettings.h"
#include "url.h"
#include "repository.h"
#include "version_check.h"
#include "svnqttypes.h"

#include <tqpainter.h>
#include <tqlayout.h>
#include <tqfileinfo.h>
#include <tqheader.h>
#include <tqtooltip.h>
#include <tqwhatsthis.h>
#include <tqsplitter.h>
#include <tqlayout.h>
#include <tqvbox.h>

#include <kurl.h>
#include <ktrader.h>
#include <tdeapplication.h>
#include <klibloader.h>
#include <tdemessagebox.h>
#include <krun.h>
#include <tdelocale.h>
#include <ktextbrowser.h>
#include <kdebug.h>
#include <tdeactioncollection.h>
#include <tdeshortcut.h>
#include <kdialog.h>
#include <kdialogbase.h>
#include <kprogress.h>

tdesvnView::tdesvnView(TDEActionCollection*aCollection,TQWidget *parent,const char*name,bool full)
    : TQWidget(parent,name),svn::repository::RepositoryListener(),m_Collection(aCollection),
      m_currentURL("")
{
    Q_UNUSED(full);
    setupActions();
    m_CacheProgressBar=0;

    m_topLayout = new TQVBoxLayout(this);

    m_Splitter = new TQSplitter( this, "m_Splitter" );
    m_Splitter->setOrientation( TQt::Vertical );

    m_flist=new tdesvnfilelist(m_Collection,m_Splitter);

    m_infoSplitter = new TQSplitter(m_Splitter);
    m_infoSplitter->setOrientation( TQt::Horizontal );
    m_infoSplitter->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)7, (TQSizePolicy::SizeType)7, 0, 1, m_infoSplitter->sizePolicy().hasHeightForWidth() ) );
    m_LogWindow=new KTextBrowser(m_infoSplitter);
    Propertylist*pl = new Propertylist(m_infoSplitter);
    pl->setCommitchanges(true);
    pl->addCallback(m_flist);
    connect(m_flist,TQ_SIGNAL(sigProplist(const svn::PathPropertiesMapListPtr&,bool,const TQString&)),
            pl,TQ_SLOT(displayList(const svn::PathPropertiesMapListPtr&,bool,const TQString&)));

    m_flist->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)7, (TQSizePolicy::SizeType)7, 0, 1, m_flist->sizePolicy().hasHeightForWidth() ) );

    m_topLayout->addWidget(m_Splitter);
    connect(m_flist,TQ_SIGNAL(sigLogMessage(const TQString&)),this,TQ_SLOT(slotAppendLog(const TQString&)));
    connect(m_flist,TQ_SIGNAL(changeCaption(const TQString&)),this,TQ_SLOT(slotSetTitle(const TQString&)));
    connect(m_flist,TQ_SIGNAL(sigShowPopup(const TQString&,TQWidget**)),this,TQ_SLOT(slotDispPopup(const TQString&,TQWidget**)));
    connect(m_flist,TQ_SIGNAL(sigUrlOpend(bool)),parent,TQ_SLOT(slotUrlOpened(bool)));
    connect(m_flist,TQ_SIGNAL(sigSwitchUrl(const KURL&)),this,TQ_SIGNAL(sigSwitchUrl(const KURL&)));
    connect(m_flist,TQ_SIGNAL(sigUrlChanged( const TQString& )),this,TQ_SLOT(slotUrlChanged(const TQString&)));
    connect(m_flist,TQ_SIGNAL(sigCacheStatus(TQ_LONG,TQ_LONG)),this,TQ_SLOT(fillCacheStatus(TQ_LONG,TQ_LONG)));
    connect(this,TQ_SIGNAL(sigMakeBaseDirs()),m_flist,TQ_SLOT(slotMkBaseDirs()));
    TDEConfigGroup cs(Kdesvnsettings::self()->config(),"tdesvn-mainlayout");
    TQString t1 = cs.readEntry("split1",TQString());
    if (!t1.isEmpty()) {
        TQTextStream st1(&t1,IO_ReadOnly);
        st1 >> *m_Splitter;
    }
    if (m_infoSplitter) {
        t1 = cs.readEntry("infosplit",TQString());
        if (!t1.isEmpty()) {
            TQTextStream st2(&t1,IO_ReadOnly);
            st2 >> *m_infoSplitter;
        }
    }
}

void tdesvnView::slotAppendLog(const TQString& text)
{
    m_LogWindow->append(text);
}

tdesvnView::~tdesvnView()
{
    TDEConfigGroup cs(Kdesvnsettings::self()->config(),"tdesvn-mainlayout");
    TQString t1,t2;
    TQTextStream st1(&t1,IO_WriteOnly);
    st1 << *m_Splitter;
    cs.writeEntry("split1",t1);

    if (m_infoSplitter) {
        t2="";
        TQTextStream st2(&t2,IO_WriteOnly);
        st2 << *m_infoSplitter;
        cs.writeEntry("infosplit",t2);
    }
}

void tdesvnView::slotUrlChanged(const TQString&url)
{
    m_currentURL=url;
    slotSetTitle(url);
    emit sigUrlChanged(url);
    slotOnURL(i18n("Repository opened"));
}

TQString tdesvnView::currentURL()
{
    return m_currentURL;
}

bool tdesvnView::openURL(TQString url)
{
    return openURL(KURL(url));
}

bool tdesvnView::openURL(const KURL& url)
{
    /* transform of url must be done in part! otherwise we will run into different troubles! */
    m_currentURL = "";
    KURL _url;
    bool open = false;
    _url = url;
    if (_url.isLocalFile()) {
        TQString query = _url.query();
        _url.setQuery("");
        TQString _f = _url.path();
        TQFileInfo f(_f);
        if (!f.isDir()) {
            m_currentURL="";
            return open;
        }
        if (query.length()>1) {
            _url.setQuery(query);
        }
    } else {
        if (!svn::Url::isValid(url.protocol())) {
            return open;
        }
    }
    m_LogWindow->setText("");
    slotSetTitle(url.prettyURL());
    if (m_flist->openURL(url)) {
        slotOnURL(i18n("Repository opened"));
        m_currentURL=url.url();
        open = true;
    } else {
        TQString t = m_flist->lastError();
        if (t.isEmpty()) {
            t = i18n("Could not open repository");
        }
        slotOnURL(t);
    }
    return open;
}

void tdesvnView::slotOnURL(const TQString& url)
{
    emit signalChangeStatusbar(url);
}

void tdesvnView::slotSetTitle(const TQString& title)
{
    //emit signalChangeCaption(title);
    emit setWindowCaption(title);
}


/*!
    \fn tdesvnView::closeMe()
 */
void tdesvnView::closeMe()
{
    m_flist->closeMe();
    m_LogWindow->setText("");
    slotOnURL(i18n("No repository open"));
}

void tdesvnView::slotDispPopup(const TQString&item,TQWidget**target)
{
    emit sigShowPopup(item,target);
}


/*!
    \fn tdesvnView::refreshCurrentTree()
 */
void tdesvnView::refreshCurrentTree()
{
    m_flist->refreshCurrentTree();
}


/*!
    \fn tdesvnView::slotSettingsChanged()
 */
void tdesvnView::slotSettingsChanged()
{
    m_flist->slotSettingsChanged();
}

/*!
    \fn tdesvnView::slotCreateRepo()
 */
void tdesvnView::slotCreateRepo()
{
    KDialogBase * dlg = new KDialogBase(
        TDEApplication::activeModalWidget(),
        "create_repository",
        true,
        i18n("Create new repository"),
        KDialogBase::Ok|KDialogBase::Cancel);
    if (!dlg) return;
    TQWidget* Dialog1Layout = dlg->makeVBoxMainWidget();
    bool compatneeded = svn::Version::version_major()>1||svn::Version::version_minor()>3;
    bool compat14 = svn::Version::version_major()>1||svn::Version::version_minor()>4;
    Createrepo_impl*ptr = new Createrepo_impl(compatneeded,compat14,Dialog1Layout);
    dlg->resize(dlg->configDialogSize(*(Kdesvnsettings::self()->config()),"create_repo_size"));
    int i = dlg->exec();
    dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"create_repo_size",false);

    if (i!=TQDialog::Accepted) {
        delete dlg;
        return;
    }
    svn::repository::Repository*_rep = new svn::repository::Repository(this);
    bool ok = true;
    bool createdirs;
    TQString path = ptr->targetDir();
    closeMe();
    kdDebug()<<"Creating "<<path << endl;
    try {
        _rep->CreateOpen(path,ptr->fsType(),ptr->disableFsync(),
                         !ptr->keepLogs(),ptr->compat13(),ptr->compat14());
    } catch(const svn::ClientException&e) {
        slotAppendLog(e.msg());
        kdDebug()<<"Creating "<<path << " failed "<<e.msg() << endl;
        ok = false;
    }
    kdDebug()<<"Creating "<<path << " done " << endl;
    createdirs = ptr->createMain();
    delete dlg;
    delete _rep;
    if (!ok) {
        return;
    }
    openURL(path);
    if (createdirs) {
        emit sigMakeBaseDirs();
    }
}

void tdesvnView::slotHotcopy()
{
    KDialogBase * dlg = new KDialogBase(
        TDEApplication::activeModalWidget(),
        "hotcopy_repository",
        true,
        i18n("Hotcopy a repository"),
        KDialogBase::Ok|KDialogBase::Cancel);
    if (!dlg) return;
    TQWidget* Dialog1Layout = dlg->makeVBoxMainWidget();
    HotcopyDlg_impl * ptr = new HotcopyDlg_impl(Dialog1Layout);
    dlg->resize(dlg->configDialogSize(*(Kdesvnsettings::self()->config()),"hotcopy_repo_size"));
    int i = dlg->exec();
    dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"hotcopy_repo_size",false);

    if (i!=TQDialog::Accepted) {
        delete dlg;
        return;
    }
    bool cleanlogs = ptr->cleanLogs();
    TQString src = ptr->srcPath();
    TQString dest = ptr->destPath();
    delete dlg;
    if (src.isEmpty()||dest.isEmpty()) {
        return;
    }
    try {
        svn::repository::Repository::hotcopy( src,dest,cleanlogs);
        slotAppendLog(i18n("Hotcopy finished."));
    } catch(const svn::ClientException&e) {
        slotAppendLog(e.msg());
        kdDebug()<<"Hotcopy of "<< src << " failed "<<e.msg() << endl;
    }
}

void tdesvnView::slotLoaddump()
{
    KDialogBase dlg(
        TDEApplication::activeModalWidget(),
        "hotcopy_repository",
        true,
        i18n("Hotcopy a repository"),
        KDialogBase::Ok|KDialogBase::Cancel);
    TQWidget* Dialog1Layout = dlg.makeVBoxMainWidget();
    LoadDmpDlg_impl * ptr = new LoadDmpDlg_impl(Dialog1Layout);
    dlg.resize(dlg.configDialogSize(*(Kdesvnsettings::self()->config()),"loaddump_repo_size"));
    int i = dlg.exec();
    dlg.saveDialogSize(*(Kdesvnsettings::self()->config()),"loaddump_repo_size",false);
    if (i!=TQDialog::Accepted) {
        return;
    }
    svn::repository::Repository _rep(this);
    m_ReposCancel = false;

    try {
        _rep.Open(ptr->repository());
    }catch (const svn::ClientException&e) {
        slotAppendLog(e.msg());
        kdDebug()<<"Open "<<ptr->repository() << " failed "<<e.msg() << endl;
        return ;
    }

    svn::repository::Repository::LOAD_UUID _act;
    switch (ptr->uuidAction()) {
    case 1:
        _act = svn::repository::Repository::UUID_IGNORE_ACTION;
        break;
    case 2:
        _act = svn::repository::Repository::UUID_FORCE_ACTION;
        break;
    case 0:
    default:
        _act = svn::repository::Repository::UUID_DEFAULT_ACTION;
        break;
    }
    try {
        StopDlg sdlg(this,this,0,"Load Dump",i18n("Loading a dump into a repository."));
        _rep.loaddump(ptr->dumpFile(),_act,ptr->parentPath(),ptr->usePre(),ptr->usePost());
        slotAppendLog(i18n("Loading dump finished."));
    }catch (const svn::ClientException&e) {
        slotAppendLog(e.msg());
        kdDebug()<<"Load dump into "<<ptr->repository() << " failed "<<e.msg() << endl;
    }
}

void tdesvnView::slotDumpRepo()
{
    KDialogBase * dlg = new KDialogBase(
        TDEApplication::activeModalWidget(),
        "dump_repository",
        true,
        i18n("Dump a repository"),
        KDialogBase::Ok|KDialogBase::Cancel);
    if (!dlg) return;
    TQWidget* Dialog1Layout = dlg->makeVBoxMainWidget();
    DumpRepo_impl*ptr = new DumpRepo_impl(Dialog1Layout);
    dlg->resize(dlg->configDialogSize(*(Kdesvnsettings::self()->config()),"dump_repo_size"));
    int i = dlg->exec();
    dlg->saveDialogSize(*(Kdesvnsettings::self()->config()),"dump_repo_size",false);

    if (i!=TQDialog::Accepted) {
        delete dlg;
        return;
    }
    svn::repository::Repository*_rep = new svn::repository::Repository(this);
    TQString re,out;
    bool incr,diffs;
    re = ptr->reposPath();
    out = ptr->targetFile();
    incr = ptr->incremental();
    diffs = ptr->use_deltas();
    int s = ptr->startNumber();
    int e = ptr->endNumber();

    delete dlg;

    m_ReposCancel = false;
    svn::Revision st = svn::Revision::UNDEFINED;
    svn::Revision en = svn::Revision::UNDEFINED;

    if (s>-1) {
        st=s;
    }
    if (e>-1) {
        en=e;
    }

    try {
        _rep->Open(re);
    }catch (const svn::ClientException&e) {
        slotAppendLog(e.msg());
        kdDebug()<<"Open "<<re << " failed "<<e.msg() << endl;
        delete _rep;
        return ;
    }

    try {
        StopDlg sdlg(this,this,0,"Dump",i18n("Dumping a repository"));
        _rep->dump(out,st,en,incr,diffs);
        slotAppendLog(i18n("Dump finished."));
    }catch (const svn::ClientException&e) {
        slotAppendLog(e.msg());
        kdDebug()<<"Dump "<<out << " failed "<<e.msg() << endl;
    }
    delete _rep;
}

/*!
    \fn tdesvnView::setupActions()
 */
void tdesvnView::setupActions()
{
}

void tdesvnView::sendWarning(const TQString&aMsg)
{
    slotAppendLog(aMsg);
}

void tdesvnView::sendError(const TQString&aMsg)
{
    slotAppendLog(aMsg);
}

bool tdesvnView::isCanceld()
{
    if (!m_ReposCancel) {
        emit tickProgress();
        return false;
    }
    return true;
}

void tdesvnView::setCanceled(bool how)
{
    m_ReposCancel = how;
}

void tdesvnView::fillCacheStatus(TQ_LONG current,TQ_LONG max)
{
    if (current>-1 && max>-1) {
        kdDebug()<<"Fillcache "<<current<<" von "<<max<<endl;
        if (!m_CacheProgressBar) {
            kdDebug()<<"Creating progressbar"<<endl;
            m_CacheProgressBar=new KProgress((int)max,this);
            m_topLayout->addWidget(m_CacheProgressBar);
            m_CacheProgressBar->setFormat(i18n("Inserted %v not cached log entries of %m."));
        }
        if (!m_CacheProgressBar->isVisible()) {
            m_CacheProgressBar->show();
        }
        m_CacheProgressBar->setValue((int)current);
    } else {
        delete m_CacheProgressBar;
        m_CacheProgressBar=0;
    }
}

#include "tdesvnview.moc"
