/***************************************************************************
 *   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 "svnitem.h"
#include "svnactions.h"
#include "tdesvn_part.h"
#include "src/settings/tdesvnsettings.h"
#include "src/svnqt/status.hpp"
#include "src/svnqt/smart_pointer.hpp"
#include "src/svnqt/url.hpp"
#include "helpers/sub2qt.h"
#include "helpers/ktranslateurl.h"

#include <kglobal.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <kiconeffect.h>
#include <kfileitem.h>
#include <kdebug.h>

#include <tqstring.h>
#include <tqfileinfo.h>
#include <tqimage.h>
#include <tqptrlist.h>
#include <tqpainter.h>
#include <tqbitmap.h>

class SvnItem_p:public svn::ref_count
{
    friend class SvnItem;
public:
    SvnItem_p();
    SvnItem_p(const svn::StatusPtr&);
    virtual ~SvnItem_p();
    KFileItem*createItem(const svn::Revision&peg);
    const KURL& kdeName(const svn::Revision&);
    KMimeType::Ptr mimeType(bool dir=false);

protected:
    svn::StatusPtr m_Stat;
    void init();
    TQString m_url,m_full,m_short;
    KURL m_kdename;
    TQDateTime m_fullDate;
    TQString m_infoText;
    KFileItem*m_fitem;
    bool isWc;
    svn::Revision lRev;
    KMimeType::Ptr mptr;
};

SvnItem_p::SvnItem_p()
    :ref_count(),m_Stat(new svn::tqStatus())
{
    init();
}

SvnItem_p::SvnItem_p(const svn::StatusPtr&aStat)
    :ref_count(),m_Stat(aStat)
{
    init();
}

SvnItem_p::~SvnItem_p()
{
    delete m_fitem;
}

void SvnItem_p::init()
{
    m_full = m_Stat->path();
    m_kdename="";
    mptr = 0;
    lRev=svn::Revision::UNDEFINED;
    while (m_full.endsWith("/")) {
        /* dir name possible */
        m_full.truncate(m_full.length()-1);
    }
    int p = m_full.findRev("/");
    if (p>-1) {
        ++p;
        m_short = m_full.right(m_full.length()-p);
    } else {
        m_short = m_full;
    }
    m_url = m_Stat->entry().url();
    m_fullDate = svn::DateTime(m_Stat->entry().cmtDate());
    m_infoText = TQString();
    m_fitem = 0;
}

KMimeType::Ptr SvnItem_p::mimeType(bool dir)
{
    if (!mptr||m_kdename.isEmpty()) {
        if (m_kdename.isEmpty()) {
            kdeName(svn::Revision::UNDEFINED);
        }
        if (dir) {
            mptr = KMimeType::mimeType("inode/directory");
        } else {
            mptr = KMimeType::findByURL(m_kdename,0,isWc,!isWc);
        }
    }
    return mptr;
}

const KURL& SvnItem_p::kdeName(const svn::Revision&r)
{
    isWc = !svn::Url::isValid(m_Stat->path());
    TQString name;
    if (!(r==lRev)||m_kdename.isEmpty()) {
        lRev=r;
        if (!isWc) {
            m_kdename = m_Stat->entry().url();
            TQString proto;
            proto = helpers::KTranslateUrl::makeKdeUrl(m_kdename.protocol());
            m_kdename.setProtocol(proto);
            TQString revstr= lRev.toString();
            if (revstr.length()>0) {
                m_kdename.setQuery("?rev="+revstr);
            }
        } else {
            m_kdename = KURL::fromPathOrURL(m_Stat->path());
        }
    }
    return m_kdename;
}

KFileItem*SvnItem_p::createItem(const svn::Revision&peg)
{
    if (!m_fitem||!(peg==lRev) ) {
        delete m_fitem;
        m_fitem=0;
        m_fitem=new KFileItem(KFileItem::Unknown,KFileItem::Unknown,kdeName(peg));
    }
    return m_fitem;
}

SvnItem::SvnItem()
    : p_Item(new SvnItem_p())
{
    m_overlaycolor = false;
}

SvnItem::SvnItem(const svn::StatusPtr&aStat)
    : p_Item(new SvnItem_p(aStat))
{
    m_overlaycolor = false;
}

SvnItem::~SvnItem()
{
}

void SvnItem::setStat(const svn::StatusPtr&aStat)
{
    m_overlaycolor = false;
    p_Item = new SvnItem_p(aStat);
}

const TQString&SvnItem::fullName()const
{
    return (p_Item->m_full);
}

const TQString&SvnItem::shortName()const
{
    return (p_Item->m_short);
}

const TQString&SvnItem::Url()const
{
    return (p_Item->m_url);
}

bool SvnItem::isDir()const
{
    if (isRemoteAdded() || p_Item->m_Stat->entry().isValid()) {
        return p_Item->m_Stat->entry().kind()==svn_node_dir;
    }
    /* must be a local file */
    TQFileInfo f(fullName());
    return f.isDir();
}

const TQDateTime&SvnItem::fullDate()const
{
    return (p_Item->m_fullDate);
}

TQPixmap SvnItem::internalTransform(const TQPixmap&first,int size)
{
    TQPixmap result(size,size);
    if (result.isNull()) {
        return result;
    }
    const TQBitmap * b = first.mask();
    result.fill(TQt::white);
    if (b) {
        result.setMask(*b);
    } else {
        TQBitmap m(size,size,true);
        m.fill(TQt::white);
        result.setMask(m);
    }
    TQPainter pa;
    pa.begin(&result);
    int w = first.width()>size?size:first.width();
    int h = first.height()>size?size:first.height();
    pa.drawPixmap(0,0,first,0,0,w,h);
    pa.end();
    return result;
}

TQPixmap SvnItem::getPixmap(const TQPixmap&_p,int size,bool overlay)
{
    if (!isVersioned()) {
        m_bgColor = NOTVERSIONED;
    } else if (isRealVersioned()) {
        SvnActions*wrap = getWrapper();
        bool mod = false;
        TQPixmap p2 = TQPixmap();
        if (p_Item->m_Stat->texttqStatus()==svn_wc_status_conflicted) {
            m_bgColor = CONFLICT;
            if (overlay)
                p2 = tdesvnPartFactory::instance()->iconLoader()->loadIcon("tdesvnconflicted",KIcon::Desktop,size);
        } else if (p_Item->m_Stat->texttqStatus ()==svn_wc_status_missing) {
            m_bgColor = MISSING;
        } else if (isLocked()||wrap->checkReposLockCache(fullName())) {
            if (overlay) p2 = tdesvnPartFactory::instance()->iconLoader()->loadIcon("tdesvnlocked",KIcon::Desktop,size);
            m_bgColor = LOCKED;
        } else if (Kdesvnsettings::check_needslock() && !isRemoteAdded() && wrap->isLockNeeded(this,svn::Revision::UNDEFINED) ) {
            if (overlay) p2 = tdesvnPartFactory::instance()->iconLoader()->loadIcon("tdesvnneedlock",KIcon::Desktop,size);
            m_bgColor = NEEDLOCK;
        } else if (wrap->isUpdated(p_Item->m_Stat->path())) {
            if (overlay) p2 = tdesvnPartFactory::instance()->iconLoader()->loadIcon("tdesvnupdates",KIcon::Desktop,size);
            m_bgColor = UPDATES;
        } else if (p_Item->m_Stat->texttqStatus()==svn_wc_status_deleted) {
            if (overlay) p2 = tdesvnPartFactory::instance()->iconLoader()->loadIcon("tdesvndeleted",KIcon::Desktop,size);
            m_bgColor = DELETED;
        } else if (p_Item->m_Stat->texttqStatus()==svn_wc_status_added ) {
            if (overlay) p2 = tdesvnPartFactory::instance()->iconLoader()->loadIcon("tdesvnadded",KIcon::Desktop,size);
            m_bgColor = ADDED;
        } else if (isModified()) {
            mod = true;
        } else if (isDir()&&wrap) {
            svn::StatusEntries dlist;
            svn::StatusEntries::const_iterator it;
            if (isRemoteAdded() || wrap->checkUpdateCache(fullName())) {
                if (overlay) p2 = tdesvnPartFactory::instance()->iconLoader()->loadIcon("tdesvnupdates",KIcon::Desktop,size);
                m_bgColor = UPDATES;
            } else if (wrap->checkConflictedCache(fullName())) {
                m_bgColor = CONFLICT;
                if (overlay)
                    p2 = tdesvnPartFactory::instance()->iconLoader()->loadIcon("tdesvnconflicted",KIcon::Desktop,size);
            } else {
                mod = wrap->checkModifiedCache(fullName());
            }
        }
        if (mod) {
            m_bgColor = MODIFIED;
            if (overlay) p2 = tdesvnPartFactory::instance()->iconLoader()->loadIcon("tdesvnmodified",KIcon::Desktop,size);
        }
        if (!p2.isNull()) {
            TQPixmap p;
            if (_p.width()!=size || _p.height()!=size) {
                p = internalTransform(_p,size);
            } else {
                p = _p;
            }
            m_overlaycolor = true;
            TQImage i1; i1 = p;
            TQImage i2;i2 = p2;

            KIconEffect::overlay(i1,i2);
            p = i1;
            return p;
        }
    }
    return _p;
}

TQPixmap SvnItem::getPixmap(int size,bool overlay)
{
    TQPixmap p;
    m_overlaycolor = false;
    m_bgColor = NONE;
    /* yes - different way to "isDir" above 'cause here we try to use the
       mime-features of KDE on ALL not just unversioned entries.
     */
    if (svn::Url::isValid(p_Item->m_Stat->path())) {
        /* remote access */
        p = p_Item->mimeType(isDir())->pixmap(KIcon::Desktop,size,KIcon::DefaultState);
        if (isLocked()) {
            m_bgColor = LOCKED;
            TQPixmap p2;
            if (overlay) p2 = tdesvnPartFactory::instance()->iconLoader()->loadIcon("tdesvnlocked",KIcon::Desktop,size);
            if (!p2.isNull()) {
                TQImage i1; i1 = p;
                TQImage i2; i2 = p2;
                KIconEffect::overlay(i1,i2);
                p = i1;
            }
        }
    } else {
        if (isRemoteAdded()) {
            if (isDir()) {
                p = tdesvnPartFactory::instance()->iconLoader()->loadIcon("folder",KIcon::Desktop,size);
            } else {
                p = tdesvnPartFactory::instance()->iconLoader()->loadIcon("unknown",KIcon::Desktop,size);
            }
        } else {
            KURL uri;
            uri.setPath(fullName());
            p = KMimeType::pixmapForURL(uri,0,KIcon::Desktop,size);
            p = getPixmap(p,size,overlay);
        }
    }
    return p;
}

bool SvnItem::isVersioned()const
{
    return p_Item->m_Stat->isVersioned();
}

bool SvnItem::isValid()const
{
    if (isVersioned()) {
        return true;
    }
    TQFileInfo f(fullName());
    return f.exists();
}

bool SvnItem::isRealVersioned()const
{
    return p_Item->m_Stat->isRealVersioned();
}

bool SvnItem::isIgnored()const
{
    return p_Item->m_Stat->texttqStatus()==svn_wc_status_ignored;
}

bool SvnItem::isRemoteAdded()const
{
    return getWrapper()->isUpdated(p_Item->m_Stat->path()) &&
            p_Item->m_Stat->validRepostqStatus()&&!p_Item->m_Stat->validLocaltqStatus();
}

TQString SvnItem::infoText()const
{
    TQString info_text = "";
    if (getWrapper()->isUpdated(p_Item->m_Stat->path())) {
        if (p_Item->m_Stat->validRepostqStatus()&&!p_Item->m_Stat->validLocaltqStatus()) {
            info_text = i18n("Added in repository");
        } else {
            info_text = i18n("Needs update");
        }
    } else {
    switch(p_Item->m_Stat->texttqStatus ()) {
    case svn_wc_status_modified:
        info_text = i18n("Locally modified");
        break;
    case svn_wc_status_added:
        info_text = i18n("Locally added");
        break;
    case svn_wc_status_missing:
        info_text = i18n("Missing");
        break;
    case svn_wc_status_deleted:
        info_text = i18n("Deleted");
        break;
    case svn_wc_status_replaced:
        info_text = i18n("Replaced");
        break;
    case svn_wc_status_ignored:
        info_text = i18n("Ignored");
        break;
    case svn_wc_status_external:
        info_text=i18n("External");
        break;
    case svn_wc_status_conflicted:
        info_text=i18n("Conflict");
        break;
    case svn_wc_status_merged:
        info_text=i18n("Merged");
        break;
    case svn_wc_status_incomplete:
        info_text=i18n("Incomplete");
        break;
    default:
        break;
    }
    if (info_text.isEmpty()) {
        switch (p_Item->m_Stat->proptqStatus ()) {
        case svn_wc_status_modified:
            info_text = i18n("Property modified");
            break;
        default:
            break;
        }
    }
    }
    return info_text;
}

TQString SvnItem::cmtAuthor()const
{
    return p_Item->m_Stat->entry().cmtAuthor();
}

long int SvnItem::cmtRev()const
{
    return p_Item->m_Stat->entry().cmtRev();
}

bool SvnItem::isLocked()const
{
    return p_Item->m_Stat->entry().lockEntry().Locked();
}

TQString SvnItem::lockOwner()const
{
    if (p_Item->m_Stat->entry().lockEntry().Locked()) {
        return p_Item->m_Stat->entry().lockEntry().Owner();
    }
    svn::SharedPointer<svn::tqStatus> tmp;
    if (getWrapper()->checkReposLockCache(fullName(),tmp) && tmp) {
        return tmp->lockEntry().Owner();
    }
    return "";
}


/*!
    \fn SvnItem::isModified()
 */
bool SvnItem::isModified()const
{
    return p_Item->m_Stat->texttqStatus ()==svn_wc_status_modified||p_Item->m_Stat->proptqStatus()==svn_wc_status_modified
            ||p_Item->m_Stat->texttqStatus ()==svn_wc_status_replaced;
}

const svn::StatusPtr& SvnItem::stat()const
{
    return p_Item->m_Stat;
}


/*!
    \fn SvnItem::isNormal()const
 */
bool SvnItem::isNormal()const
{
    return p_Item->m_Stat->texttqStatus()==svn_wc_status_normal;
}

bool SvnItem::isMissing()const
{
    return p_Item->m_Stat->texttqStatus()==svn_wc_status_missing;
}

bool SvnItem::isDeleted()const
{
    return p_Item->m_Stat->texttqStatus()==svn_wc_status_deleted;
}

bool SvnItem::isConflicted()const
{
    return p_Item->m_Stat->texttqStatus()==svn_wc_status_conflicted;
}

/*!
    \fn SvnItem::getToolTipText()
 */
const TQString& SvnItem::getToolTipText()
{
    if (p_Item->m_infoText.isNull()) {
        if (isRealVersioned() && !p_Item->m_Stat->entry().url().isEmpty()) {
            SvnActions*wrap = getWrapper();
            svn::Revision peg(svn_opt_revision_unspecified);
            svn::Revision rev(svn_opt_revision_unspecified);
            if (svn::Url::isValid(p_Item->m_Stat->path())) {
                /* remote */
                rev = p_Item->m_Stat->entry().revision();
                peg = correctPeg();
            } else {
                /* local */
            }
            if (wrap) {
                TQPtrList<SvnItem> lst; lst.append(this);
                p_Item->m_infoText = wrap->getInfo(lst,rev,peg,false,false);
                if (p_Item->m_fitem) p_Item->m_infoText+=p_Item->m_fitem->getToolTipText(0);
            }
        } else if (p_Item->m_fitem){
            p_Item->m_infoText=p_Item->m_fitem->getToolTipText(6);
        }
    }
    return p_Item->m_infoText;
}

KFileItem*SvnItem::fileItem()
{
    return p_Item->createItem(correctPeg());
}

const KURL&SvnItem::kdeName(const svn::Revision&r)
{
    return p_Item->kdeName(r);
}

KMimeType::Ptr SvnItem::mimeType()
{
    return p_Item->mimeType(isDir());
}