#include <qcstring.h>
#include <qsocket.h>
#include <qdatetime.h>
#include <qbitarray.h>
#include <qmap.h>

#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include <kapplication.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <kinstance.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <klocale.h>
#include <kurl.h>
#include <ksock.h>

#include <sys/stat.h>

#include "mtp.h"

#include <libmtp.h>

using namespace KIO;

LIBMTP_mtpdevice_t *devices = NULL;
LIBMTP_mtpdevice_t *iter = NULL;
LIBMTP_folder_t *folders = NULL;
LIBMTP_file_t *files = NULL;
QMap<QString, int> folders_map;
QMap<QString, int> files_item_map;
QMap<QString, int> files_parent_map;

extern "C"
{
    int kdemain(int argc, char **argv)
    {
        KInstance instance( "kio_mtp" );
        kdDebug() << "*** Starting kio_mtp " << endl;
        if (argc != 4) {
            kdDebug() << "Usage: kio_mtp  protocol domain-socket1 domain-socket2" << endl;
            exit(-1);
        }
        kio_mtpProtocol slave(argv[2], argv[3]);
        slave.dispatchLoop();

        kdDebug() << "*** kio_mtp Done" << endl;
        return 0;
    }
}

kio_mtpProtocol::kio_mtpProtocol(const QCString &pool_socket, const QCString &app_socket)
    : SlaveBase("kio_mtp", pool_socket, app_socket)
{
    kdDebug() << "kio_mtpProtocol::kio_mtpProtocol()" << endl;

    LIBMTP_Init();
    LIBMTP_Get_Connected_Devices(&devices);
    if (devices == NULL) {
        kdDebug() << "kio_mtpProtocol::kio_mtpProtocol(): no devices" << endl;
        return;
    }
    iter = devices;
    while (iter != NULL) {
        char *friendlyname = LIBMTP_Get_Friendlyname(iter);
        kdDebug() << "kio_mtpProtocol::kio_mtpProtocol(): Connected device " << friendlyname << endl;
        iter = iter->next;
    }
}

/*void kio_mtpProtocol::init_device_maps(device)
{
    folders = LIBMTP_Get_Folder_List(device);
    update_foldermap(folders);
    files = LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);
    update_filemap(files);
}
*/

kio_mtpProtocol::~kio_mtpProtocol()
{
    kdDebug() << "kio_mtpProtocol::~kio_mtpProtocol()" << endl;

    if (devices != NULL)
        LIBMTP_Release_Device_List(devices);
}


/*void kio_mtpProtocol::update_foldermap(LIBMTP_folder_t *folder)
{
    kdDebug() << "update_foldermap(): " << folder->name << endl;

    folders_map.insert(folder->name, folder->folder_id);

    if (folder->child != NULL)
        update_foldermap(folder->child);
    if (folder->sibling != NULL)
        update_foldermap(folder->sibling);

    return;
}*/

/*void kio_mtpProtocol::update_filemap(LIBMTP_file_t *file)
{
    kdDebug() << "update_filemap(): " << file->filename << endl;

    files_item_map.insert(file->filename, file->item_id);
    files_parent_map.insert(file->filename, file->parent_id);

    if (file->next != NULL)
        update_filemap(file->next);

    return;
}*/

void kio_mtpProtocol::stat(const KURL& url)
{
    kdDebug() << "kio_mtpProtocol::stat() -- url: " << url.prettyURL() << " filename: " << url.fileName() << endl;

    UDSEntry entry;
    UDSAtom atom;

    if (url.path().length() <= 1 ) {
        atom.m_uds = KIO::UDS_NAME;
        atom.m_str = "/";
        entry.append(atom);

        atom.m_uds = KIO::UDS_FILE_TYPE;
        atom.m_long = S_IFDIR;
        entry.append(atom);

        atom.m_uds = KIO::UDS_MIME_TYPE;
        atom.m_str = "inode/directory";
        entry.append(atom);

        statEntry(entry);
        finished();
        return;
    }

    folders = LIBMTP_Get_Folder_List(devices);
    while (folders->name != url.fileName())
        folders = folders->next

    atom.m_uds = KIO::UDS_NAME;
    atom.m_str = folder->name;
    entry.append(atom);

    atom.m_uds = KIO::UDS_FILE_TYPE;
    atom.m_long = S_IFDIR;
    entry.append(atom);

    atom.m_uds = KIO::UDS_MIME_TYPE;
    atom.m_str = "inode/directory";
    entry.append(atom);

    statEntry(entry);
    finished();
    return;

}

void kio_mtpProtocol::listDir(const KURL& url)
{
    kdDebug() << "kio_mtpProtocol::listDir() -- url: " << url.prettyURL() << " filename: " << url.fileName() << endl;

    if (url.path().length() <= 1) {
        listRoot();
        return;
    }

    iter = devices;
    
    while (LIBMTP_Get_Friendlyname(iter) != url.host())
        iter = iter->next;
    kdDebug() << "kio_mtpProtocol::listDir() -- host: " << url.host() << endl;

    LIBMTP_folder_t *folder = LIBMTP_Get_Folder_List(iter);

    if (folder == NULL) {
        error(KIO::ERR_DOES_NOT_EXIST, url.prettyURL());
        return;
    }

    UDSEntry entry;
    UDSAtom atom;
/*    LIBMTP_file_t* file = files;
    while (file != NULL) {
    kdDebug() << "listdir - filename:" << file->filename << endl;
        if (file->parent_id == folder->folder_id) {
            entry.clear();
            UDSAtom atom;

            atom.m_uds = UDS_NAME;
            atom.m_str = file->filename;
            entry.append(atom);

            atom.m_uds = KIO::UDS_FILE_TYPE;
            atom.m_long = S_IFREG;
            entry.append( atom );

            atom.m_uds = KIO::UDS_MIME_TYPE;
            atom.m_str = getType(file);
            entry.append(atom);

            listEntry(entry, false);
        }
            file = file->next;
    }
    if (url.path().length() > 1)
        folder = folder->child;
*/
    while (folder != NULL) {
        entry.clear();

        atom.m_uds = UDS_NAME;
        atom.m_str = folder->name;
        entry.append(atom);

        atom.m_uds = KIO::UDS_FILE_TYPE;
        atom.m_long = S_IFDIR;
        entry.append(atom);

        atom.m_uds = KIO::UDS_MIME_TYPE;
        atom.m_str = "inode/directory";
        entry.append(atom);

        listEntry(entry, false);
        folder = folder->sibling;
    }

    listEntry(entry, true);
    finished();

}

void kio_mtpProtocol::statRoot()
{
    kdDebug() << "kio_mtpProtocol::statRoot()" << endl;

    UDSEntry entry;
    UDSAtom atom;

    atom.m_uds = KIO::UDS_NAME;
    atom.m_str = "/";
    entry.append(atom);

    atom.m_uds = KIO::UDS_FILE_TYPE;
    atom.m_long = S_IFDIR;
    entry.append(atom);

    atom.m_uds = KIO::UDS_MIME_TYPE;
    atom.m_str = "inode/directory";
    entry.append(atom);

    statEntry(entry);
    finished();
    return;
}

void kio_mtpProtocol::listRoot()
{
    kdDebug() << "kio_mtpProtocol::listRoot()" << endl;
    UDSEntry entry;
    UDSAtom atom;
    iter = devices;
    while (iter != NULL)
    {
        entry.clear();

	atom.m_uds = KIO::UDS_NAME;
        atom.m_str = LIBMTP_Get_Friendlyname(iter);
        entry.append(atom);

        atom.m_uds = KIO::UDS_FILE_TYPE;
        atom.m_long = S_IFDIR;
        entry.append(atom);

        atom.m_uds = KIO::UDS_MIME_TYPE;
        atom.m_str = "inode/directory";
        entry.append(atom);

        listEntry(entry, false);
        iter = iter->next;
    }
    listEntry(entry, true);
    finished();
    return;
}

QString kio_mtpProtocol::getType(LIBMTP_file_t *file)
{
    if (file->filetype == LIBMTP_FILETYPE_WAV)
        return ("audio/wav");
    else if (file->filetype == LIBMTP_FILETYPE_MP3)
        return ("audio/x-mp3");
    else if (file->filetype == LIBMTP_FILETYPE_WMA)
        return ("audio/x-ms-wma");
    else if (file->filetype == LIBMTP_FILETYPE_OGG)
        return ("audio/x-vorbis+ogg");
    else if (file->filetype == LIBMTP_FILETYPE_AUDIBLE)
        return ("");
    else if (file->filetype == LIBMTP_FILETYPE_MP4)
        return ("audio/mp4");
    else if (file->filetype == LIBMTP_FILETYPE_UNDEF_AUDIO)
        return ("");
    else if (file->filetype == LIBMTP_FILETYPE_WMV)
        return ("video/x-ms-wmv");
    else if (file->filetype == LIBMTP_FILETYPE_AVI)
        return ("video/x-msvideo");
    else if (file->filetype == LIBMTP_FILETYPE_MPEG)
        return ("video/mpeg");
    else if (file->filetype == LIBMTP_FILETYPE_ASF)
        return ("video/x-ms-asf");
    else if (file->filetype == LIBMTP_FILETYPE_QT)
        return ("video/quicktime");
    else if (file->filetype == LIBMTP_FILETYPE_UNDEF_VIDEO)
        return ("");
    else if (file->filetype == LIBMTP_FILETYPE_JPEG)
        return ("image/jpeg");
    else if (file->filetype == LIBMTP_FILETYPE_JFIF)
        return ("");
    else if (file->filetype == LIBMTP_FILETYPE_TIFF)
        return ("image/tiff");
    else if (file->filetype == LIBMTP_FILETYPE_BMP)
        return ("image/bmp");
    else if (file->filetype == LIBMTP_FILETYPE_GIF)
        return ("image/gif");
    else if (file->filetype == LIBMTP_FILETYPE_PICT)
        return ("image/x-pict");
    else if (file->filetype == LIBMTP_FILETYPE_PNG)
        return ("image/png");
    else if (file->filetype == LIBMTP_FILETYPE_VCALENDAR1)
        return ("text/x-vcalendar");
    else if (file->filetype == LIBMTP_FILETYPE_VCALENDAR2)
        return ("text/x-vcalendar");
    else if (file->filetype == LIBMTP_FILETYPE_VCARD2)
        return ("text/x-vcard");
    else if (file->filetype == LIBMTP_FILETYPE_VCARD3)
        return ("text/x-vcard");
    else if (file->filetype == LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT)
        return ("image/x-wmf");
    else if (file->filetype == LIBMTP_FILETYPE_WINEXEC)
        return ("application/x-ms-dos-executable");
    else if (file->filetype == LIBMTP_FILETYPE_TEXT)
        return ("text/plain");
    else if (file->filetype == LIBMTP_FILETYPE_HTML)
        return ("text/html");
    else if (file->filetype == LIBMTP_FILETYPE_FIRMWARE)
        return ("");
    else if (file->filetype == LIBMTP_FILETYPE_AAC)
        return ("");
    else if (file->filetype == LIBMTP_FILETYPE_MEDIACARD)
        return ("");
    else if (file->filetype == LIBMTP_FILETYPE_FLAC)
        return ("audio/x-flac");
    else if (file->filetype == LIBMTP_FILETYPE_MP2)
        return ("video/mpeg");
    else if (file->filetype == LIBMTP_FILETYPE_M4A)
        return ("audio/mp4");
    else if (file->filetype == LIBMTP_FILETYPE_DOC)
        return ("application/msword");
    else if (file->filetype == LIBMTP_FILETYPE_XML)
        return ("text/xml");
    else if (file->filetype == LIBMTP_FILETYPE_XLS)
        return ("application/vnd.ms-excel");
    else if (file->filetype == LIBMTP_FILETYPE_PPT)
        return ("application/vnd.ms-powerpoint");
    else if (file->filetype == LIBMTP_FILETYPE_MHT)
        return ("");
    else if (file->filetype == LIBMTP_FILETYPE_JP2)
        return ("image/jpeg2000");
    else if (file->filetype == LIBMTP_FILETYPE_JPX)
        return ("application/x-jbuilder-project");
    else if (file->filetype == LIBMTP_FILETYPE_UNKNOWN)
        return ("");
    else return ("");
}



/*


void kio_mtpProtocol::get(const KURL& url )
{
    kdDebug() << "kio_mtp::get(const KURL& url)" << endl;
    QString path = url.path();
    kdDebug() << "Url: " << url.prettyURL() << " Path: " << path << endl ;
    error(KIO::ERR_IS_DIRECTORY, path);
}


void kio_mtpProtocol::mimetype(const KURL & url)
{
    mimeType("text/plain");
    finished();
}


*/
