/* This file is part of the KDE libraries
    Copyright (C) 2009 Norbert Frese <nf2.email@gmail.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
 */


#include "gtkbookmarks.h"
#include <QtCore/QByteArray>
#include <QtCore/QString>
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <KDebug>
#include <KMimeType>
#include <kio/netaccess.h>

GtkBookmarks::GtkBookmarks()
{
    m_bookmarksFilename = QDir::homePath () + "/.gtk-bookmarks";

    m_kDirWatch = new KDirWatch;
    m_kDirWatch->addFile(m_bookmarksFilename);
    QObject::connect( m_kDirWatch, SIGNAL(dirty(const QString&)),
            this, SLOT(slotFileChanged(const QString&)));
    QObject::connect( m_kDirWatch, SIGNAL(created(const QString&)),
            this, SLOT(slotFileChanged(const QString&)));
    QObject::connect( m_kDirWatch, SIGNAL(deleted(const QString&)),
            this, SLOT(slotFileChanged(const QString&)));
    kDebug(7043) << "starting KDirWatch for " << m_bookmarksFilename;

    previousBookmarks = read();
}


GtkBookmarks::~GtkBookmarks()
{
    delete m_kDirWatch;
}

QList<GtkBookmark> GtkBookmarks::read()
{
    QList<GtkBookmark> list;


    QFile file(m_bookmarksFilename);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        kWarning() << "cannot open "<< m_bookmarksFilename << " Error: " << file.error();
        return list;
    }

    while (!file.atEnd()) {
        QByteArray line = file.readLine().trimmed();

        int ix = line.indexOf(' ');

        if (ix < 0)
        {
            QString urlStr = QString(line);
            KUrl url(urlStr);
            QString text = url.path().split('/').last();
            GtkBookmark bookmark(url, text);
            list << bookmark;
        }
        else
        {
            QByteArray part1 = line.left(ix);
            QByteArray part2 = line.mid(ix+1);
            QString urlStr = QString(part1);
            QString text = QString(part2);

            GtkBookmark bookmark(KUrl(urlStr), text);
            list << bookmark;
        }
    }
    return list;
}

void GtkBookmarks::write(const QList<GtkBookmark> &list)
{
    QFile file(m_bookmarksFilename);
    if (!file.open(QIODevice::WriteOnly))
    {
        kWarning() << "cannot open "<< m_bookmarksFilename << " Error: " << file.error();
        return;
    }

    foreach(const GtkBookmark & bookmark, list)
    {
        file.write(bookmark.url().toEncoded());
        if (!bookmark.text().isEmpty())
        {
            file.write(" ");
            file.write(bookmark.text().toUtf8 ());
        }
        file.write("\n");
    }
}

void GtkBookmarks::findChanges(QList<GtkBookmark> bookmarksIn)
{
    int ix = 0;
    int prevIx=0;
    int targetIx=0;

    while(ix < bookmarksIn.size() && prevIx < previousBookmarks.size())
    {
        GtkBookmark::CompareResult r = previousBookmarks[prevIx].compare(bookmarksIn[ix]);

        if (r == GtkBookmark::Same)
        {
            ix++;
            prevIx++;
            targetIx++;
            continue;
        }

        if (r == GtkBookmark::Modified)
        {
            emit modified(bookmarksIn[ix], targetIx);
            ix++;
            prevIx++;
            targetIx++;
            continue;
        }

        if (r == GtkBookmark::Different)
        {
//            if (ix+1 < bookmarksIn.size())
//            {
//                GtkBookmark::CompareResult rn = previousBookmarks[prevIx].compare(bookmarksIn[ix+1]);
//                if (rn != GtkBookmark::Different)
//                {
//                    emit added(bookmarksIn[ix], targetIx);
//                    ix++;
//                    targetIx++;
//                    continue;
//                }
//            }
//
//            if (prevIx+1 < previousBookmarks.size())
//            {
//                GtkBookmark::CompareResult rn = previousBookmarks[prevIx+1].compare(bookmarksIn[ix]);
//                if (rn != GtkBookmark::Different)
//                {
//                    emit removed(previousBookmarks[prevIx], targetIx);
//                    prevIx++;
//                    continue;
//                }
//            }

            emit removed(previousBookmarks[prevIx], targetIx);
            emit added(bookmarksIn[ix], targetIx);
            targetIx++;
            ix++;
            prevIx++;
        }
    }

    while (prevIx < previousBookmarks.size())
    {
        emit removed(previousBookmarks[prevIx], targetIx);
        prevIx ++;
    }

    while (ix < bookmarksIn.size())
    {
        emit added(bookmarksIn[ix], targetIx);
        targetIx ++;
        ix ++;
    }

    previousBookmarks = bookmarksIn;

}

void GtkBookmarks::createBookmark(const KUrl &url, const QString &text )
{
    QList<GtkBookmark> copy = previousBookmarks;

    GtkBookmark bookmark(url, text);
    copy << bookmark;
    write(copy);
}

void GtkBookmarks::updateBookmark(int index, const KUrl &url, const QString &text )
{
    QList<GtkBookmark> copy = previousBookmarks;
    copy[index].update(url, text);
    write(copy);
}

void GtkBookmarks::removeBookmark(int index)
{
    QList<GtkBookmark> copy = previousBookmarks;
    copy.removeAt(index);
    write(copy);
}
void GtkBookmarks::moveBookmark(int index, int afterIndex)
{
    QList<GtkBookmark> copy = previousBookmarks;
    GtkBookmark bookmark = copy[index];

    if (afterIndex >= copy.size())
    {
        copy << bookmark;
    }
    else
    {
        copy.insert(afterIndex, bookmark);
    }

    copy.removeAt(index);
    write(copy);
}

void GtkBookmarks::insertUrls(int index, const QList<KUrl> &urls)
{
    QList<GtkBookmark> copy = previousBookmarks;

    foreach (const KUrl &url, urls)
    {
        KMimeType::Ptr mimetype = KMimeType::mimeType(KIO::NetAccess::mimetype(url, 0));

        if (!mimetype) {
            kWarning() << "URL not added to Places as mimetype could not be determined!";
            continue;
        }

        if (!mimetype->is("inode/directory")) {
            // Only directories are allowed
            continue;
        }

        GtkBookmark bookmark(url, QString());

        if (index >= copy.size())
        {
            copy << bookmark;
        }
        else
        {
            copy.insert(index, bookmark);
        }
    }
    write(copy);
}

void GtkBookmarks::slotFileChanged(const QString& path)
{
    kDebug() << "file changed (KDirWatch) " << path ;
    if (path == m_bookmarksFilename)
    {
        findChanges(read());
    }
}
