/*
   Copyright (C) 2008 Norbert Frese <nf2 at scheinwelt at>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License (LGPL) 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 "giobridge.h"
#include "giobridge-remote.h"

#include <QtCore/QByteRef>
#include <QtCore/QDate>
#include <QtCore/QVarLengthArray>
#include <QtCore/QCoreApplication>
#include <QtCore/QRegExp>
#include <QtCore/QFile>

#include <QtDBus/QtDBus>

#include <kdebug.h>
#include <kurl.h>
#include <kcomponentdata.h>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <ktemporaryfile.h>
#include <klocale.h>
#include <limits.h>
#include <kshell.h>
#include <kmountpoint.h>
#include <kstandarddirs.h>

#include <kio/ioslave_defaults.h>
#include <kde_file.h>
#include <kglobal.h>
#include <kmimetype.h>

#include <glib.h>
#include <gio/gio.h>

using namespace KIO;

static GMainLoop *main_loop;

static gboolean iterate_gmain_timeout_function(gpointer data)
{
    g_main_loop_quit (main_loop);
    return FALSE;
}

static void iterate_gmain()
{
    g_timeout_add(500, iterate_gmain_timeout_function, NULL);

    main_loop = g_main_loop_new (NULL, FALSE);
    g_main_loop_run (main_loop);
    g_main_loop_unref(main_loop);
}


static bool checkProtocol(const KUrl& url)
{
    return url.protocol() == "remote";
}

static bool checkRemotePath(GioBridge& gioBridge, const KUrl& url)
{
    if (!url.path().startsWith("/") || url.path().indexOf( '/', 1 ) > 0)
    {
        gioBridge.error( ERR_DOES_NOT_EXIST, url.url() );
        return false;
    }
    return true;
}

static void createList(UDSEntryList &list)
{
    // load daemon module

    QDBusInterface kdedInterface( "org.kde.kded", "/kded");
    kdedInterface.call( "loadModule", "giobridgeremotedirnotify" );

    // query volume monitor

    GVolumeMonitor* gVolumeMonitor = g_volume_monitor_get();

    iterate_gmain();
    {
        GList* mountList = g_volume_monitor_get_mounts(gVolumeMonitor);
        GList* el2 = mountList;

        while(el2)
        {
            GMount * gMount = (GMount *) el2->data;

            char * mountName = g_mount_get_name(gMount);
            GFile * gFileRoot = g_mount_get_root(gMount);

            char * pointsToUri = g_file_get_uri(gFileRoot);
            QString qstrPointsToUri = QString(pointsToUri);

            kDebug(GIOBRIDGE_DEBUG_AREA) << "mountname=" << mountName << " root=" << qstrPointsToUri << endl;

            if (!qstrPointsToUri.startsWith("file://")
                    && !qstrPointsToUri.startsWith("burn://"))
            {
                UDSEntry entry;
                entry.clear();

                entry.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1(CUSTOM_MIMETYTPE_GVFS_MOUNT));
                entry.insert( KIO::UDSEntry::UDS_NAME, QString(mountName));
                entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
                entry.insert( KIO::UDSEntry::UDS_ICON_NAME, "folder-remote");
                entry.insert( KIO::UDSEntry::UDS_ACCESS, S_IREAD );

                entry.insert( KIO::UDSEntry::UDS_TARGET_URL, qstrPointsToUri);
                entry.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, QString(mountName));

                list.append(entry);
            }

            g_object_unref(gFileRoot);
            g_free(mountName);
            g_free(pointsToUri);

            el2 = g_list_next(el2);
        }
    }

    UDSEntry entry;
    entry.clear();

    entry.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1("inode/directory"));
    entry.insert( KIO::UDSEntry::UDS_NAME, "Windows Network");
    entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );
    entry.insert( KIO::UDSEntry::UDS_ICON_NAME, "network-workgroup");
    entry.insert( KIO::UDSEntry::UDS_TARGET_URL, QString("smb:///"));

    list.append(entry);
}

static bool findEntry(UDSEntry & entry, UDSEntryList &list, const QString & filename)
{
    KIO::UDSEntryList::ConstIterator it = list.begin();
    const KIO::UDSEntryList::ConstIterator end = list.end();
    for(; it!=end; ++it)
    {
        if ((*it).stringValue(KIO::UDSEntry::UDS_NAME) == filename)
        {
            entry = (*it);
            return true;
        }
    }
    return false;
}


bool GioBridgeRemote::delegateListDir(GioBridge& gioBridge, const KUrl& url)
{
    if (!checkProtocol(url)) return false;
    if (!checkRemotePath(gioBridge, url)) return true;

    kDebug(GIOBRIDGE_DEBUG_AREA) << "========= LIST remote: " << url.url() << " =========";

    UDSEntryList remote_entries;

    createList(remote_entries);

    if (url.path() == "/")
    {
        KIO::UDSEntryList::ConstIterator it = remote_entries.begin();
        const KIO::UDSEntryList::ConstIterator end = remote_entries.end();
        for(; it!=end; ++it)
        {
          gioBridge.listEntry(*it, false);
        }

        UDSEntry entry;
        gioBridge.listEntry( entry, true ); // ready

        kDebug(GIOBRIDGE_DEBUG_AREA) << "============= remote: COMPLETED LIST ============";

        gioBridge.finished();
    }
    else
    {
        UDSEntry entry;
        bool found = findEntry(entry, remote_entries, url.path().mid(1));

        if (found)
        {
            // this never happens?
            QString redirection = entry.stringValue(KIO::UDSEntry::UDS_LINK_DEST);
            kDebug(GIOBRIDGE_DEBUG_AREA) << "**** redirection to: " << redirection;
            if (!redirection.isEmpty())
            {
                gioBridge.redirection(redirection);
                gioBridge.finished();
                return true;
            }
        }
        gioBridge.error( ERR_DOES_NOT_EXIST, url.url() );
    }
    return true;
}


bool GioBridgeRemote::delegateStat(GioBridge& gioBridge, const KUrl & url)
{
    if (!checkProtocol(url)) return false;
    if (!checkRemotePath(gioBridge, url)) return true;

    kDebug(GIOBRIDGE_DEBUG_AREA) << "========= STAT remote: " << url.url() << " =========";

    if (url.path() == "/")
    {
        UDSEntry entry;

        entry.insert( KIO::UDSEntry::UDS_NAME, QString::fromLatin1("."));
        entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
        entry.insert( KIO::UDSEntry::UDS_ACCESS, 0700);
        entry.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1("inode/directory"));
        //entry.insert( KIO::UDSEntry::UDS_MIME_TYPE, QString::fromLatin1("remote/gvfs-mount"));
        entry.insert( KIO::UDSEntry::UDS_ICON_NAME, QString::fromLatin1("folder-remote"));

        // push result

        gioBridge.statEntry( entry );

        gioBridge.finished();
    }
    else
    {
        QString filename = url.path().mid(1);

        UDSEntryList remote_entries;

        createList(remote_entries);

        UDSEntry entry;

        bool found = findEntry(entry, remote_entries, filename);

        if (found)
        {
            gioBridge.statEntry( entry );
            gioBridge.finished();
        }
        else
        {
            gioBridge.error( ERR_DOES_NOT_EXIST, url.url() );
        }
    }
    return true;
}
