/*
 *
 *  Object Manager implementation of bluez5
 *
 *  Copyright (C) 2018  Emanoil Kotsev <deloptes@gmail.com>
 *
 *
 *  This file is part of libtdebluez.
 *
 *  libtdebluez 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.
 *
 *  libtdebluez 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 kbluetooth; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

// QT - Header
#include <tqtimer.h>
//
// debug
#include <kdebug.h>

// declaration include
#include <tqdbusproxy.h>
#include <tqdbusmessage.h>
#include <tqdbusobjectpath.h>
#include <tqdbusdatamap.h>
#include <tqdbusdata.h>
//
#include <tqstringlist.h>

#include "obexobjectmanagerImpl.h"
#include "../libtdebluez/btuuids.h"

namespace TDEObex
{

ObexObjectManagerImpl::ObexObjectManagerImpl(const TQString& service, const TQString& path, TQObject* parent, const char* name) :
        org::freedesktop::DBus::ObjectManagerProxy(service, path, parent, name)
{
    kdDebug() << k_funcinfo << endl;
    // init connection to dbus
    initDBUS();
}

ObexObjectManagerImpl::~ObexObjectManagerImpl()
{
    kdDebug() << k_funcinfo << endl;
    close();
}

/*!
 * This function try a reconnect to D-Bus.
 * \return boolean with the result of the operation
 * \retval true if successful reconnected to D-Bus
 * \retval false if unsuccessful
 */
bool ObexObjectManagerImpl::reconnect()
{
    kdDebug() << k_funcinfo << endl;
    // close D-Bus connection
    close();
    // init D-Bus conntection
    return (initDBUS());
}

/*!
 * This function return information about connection status to the DBUS daemon.
 * \return boolean with the state of the connection to D-Bus
 * \retval true if connected
 * \retval false if disconnected
 */
bool ObexObjectManagerImpl::isConnectedToDBUS()
{
    kdDebug() << k_funcinfo << endl;
    return dBusConn.isConnected();
}

/*!
 * This function returns pointer to connection of the DBUS.
 * \return TQT_DBusConnection* of the connection to D-Bus
 * \retval TQT_DBusConnection*
 */
TQT_DBusConnection* ObexObjectManagerImpl::getConnection()
{
    kdDebug() << k_funcinfo << endl;
    return &dBusConn;
}

/*!
 * This function close the connection to manager over the D-Bus daemon.
 * \return boolean with the result of the operation
 * \retval true if successful closed the connection
 * \retval false if any problems
 */
bool ObexObjectManagerImpl::close()
{
    kdDebug() << k_funcinfo << endl;

    if (mSession)
        delete mSession;
    if (mFileTransfer)
        delete mFileTransfer;
    if (mClient)
        delete mClient;
    if (dBusConn.isConnected())
        dBusConn.closeConnection(DBUS_CONN_NAME);
    return true;
}

/*!
 * This function initialise the connection to the D-Bus daemon.
 * \return boolean with the result of the operation
 * \retval true if successful initialised D-Bus connection
 * \retval false if unsuccessful
 */
bool ObexObjectManagerImpl::initDBUS()
{
    kdDebug() << k_funcinfo << endl;
    dBusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SessionBus, DBUS_CONN_NAME);
    if (!dBusConn.isConnected())
    {
        kdError() << "Failed to open connection to system message bus: " << dBusConn.lastError().message() << endl;
        TQTimer::singleShot(4000, this, TQT_SLOT(reconnect()));
        return false;
    }
    setConnection(dBusConn);

    TQT_DBusDataMap<TQT_DBusObjectPath> objects;
    TQT_DBusError dbuserror;
    if (!GetManagedObjects(objects, dbuserror))
    {
        tqDebug(i18n("GetManagedObjects(objects, dbuserror) failed: %1").arg(dbuserror.message()));
        return false;
    }

    TQT_DBusDataMap<TQT_DBusObjectPath>::const_iterator it = objects.begin();
    for (it; it != objects.end(); ++it)
    {
        bool ok = false;
        TQT_DBusDataMap<TQString> tqMap1 = it.data().toStringKeyMap(&ok);
        if (!ok)
        {
            tqWarning(i18n("Failed to convert dbus data to string map: %1").arg(it.key()));
            return false;
        }
        slotInterfacesAdded(it.key(), tqMap1);
    }

    connect(this, SIGNAL(InterfacesAdded(const TQT_DBusObjectPath&, const TQT_DBusDataMap< TQString >&)), this, SLOT(slotInterfacesAdded(const TQT_DBusObjectPath&, const TQT_DBusDataMap< TQString >& )));
    connect(this, SIGNAL(InterfacesRemoved(const TQT_DBusObjectPath& , const TQStringList& )), this, SLOT(slotInterfacesRemoved(const TQT_DBusObjectPath& , const TQStringList& )));
    return true;
}

/*!
 * This function initialise the connection to the D-Bus daemon.
 * \return pointer to AgentManager1
 */
org::bluez::obex::AgentManager1Proxy * ObexObjectManagerImpl::getAgentManager()
{
    kdDebug() << k_funcinfo << endl;
    return mAgentManager;
}

/*!
 * This function initialise the connection to the D-Bus daemon.
 * \return pointer to AgentManager1
 */
org::bluez::obex::Client1Proxy * ObexObjectManagerImpl::getClient()
{
    kdDebug() << k_funcinfo << endl;
    return mClient;
}

void ObexObjectManagerImpl::slotInterfacesAdded(const TQT_DBusObjectPath& object, const TQT_DBusDataMap<TQString>& interfaces)
{
    kdDebug() << k_funcinfo << endl;

    TQT_DBusDataMap<TQString>::const_iterator it1 = interfaces.begin();
    for (it1; it1 != interfaces.end(); it1++)
    {
        TQString interface = it1.key();
        if (interface == "org.bluez.obex.AgentManager1")
        {
            mAgentManager = new org::bluez::obex::AgentManager1Proxy("org.bluez.obex", object);
            if (mAgentManager)
            {
                mAgentManager->setConnection(dBusConn);
            }
            else
            {
                tqDebug(i18n("org.bluez.obex.AgentManager1 initialization failed"));
            }
        }
        else if (interface == "org.bluez.obex.Client1")
        {
            mClient = new org::bluez::obex::Client1Proxy("org.bluez.obex", object);
            if (mClient)
            {
                mClient->setConnection(dBusConn);
            }
            else
            {
                tqDebug(i18n("org.bluez.obex.Client1 initialization failed"));
            }
        }
        else if (interface == "org.bluez.obex.Session1")
        {
            mSession = new org::bluez::obex::Session1Proxy("org.bluez.obex", object);
            if (mSession)
            {
                mSession->setConnection(dBusConn);
            }
            else
            {
                tqDebug(i18n("org.bluez.obex.Session1 initialization failed"));
            }
        }
        else if (interface == "org.bluez.obex.FileTransfer1")
        {
            mFileTransfer = new org::bluez::obex::FileTransfer1Proxy("org.bluez.obex", object);
            if (mFileTransfer)
            {
                mFileTransfer->setConnection(dBusConn);
            }
            else
            {
                tqDebug(i18n("org.bluez.obex.FileTransfer1 initialization failed"));
            }
        }
        else if (interface == "org.freedesktop.DBus.Introspectable")
        {
            // do nothing
        }
        else
        {
            tqWarning(i18n("Interface not implemented: %1").arg(interface));
        }
    }
}

void ObexObjectManagerImpl::slotInterfacesRemoved(const TQT_DBusObjectPath& object, const TQStringList& interfaces)
{
    kdDebug() << k_funcinfo << endl;
    // TODO: remove interface
    for (TQValueListConstIterator<TQString> it = interfaces.begin();
            it != interfaces.end(); ++it)
    {
        if ((*it) == "org.bluez.obex.AgentManager1")
        {
            // TODO: remove AgentManager1
        }
        else if ((*it) == "org.bluez.obex.Client1")
        {
            // TODO: remove Client1
        }
        else if ((*it) == "org.bluez.obex.Session1")
        {
            // TODO: remove Session1
        }
        else if ((*it) == "org.bluez.obex.FileTransfer1")
        {
            // TODO: remove FileTransfer1
        }
        else
        {
            tqWarning(i18n("Interface not implemented: %1").arg((*it)));
        }
    }
}

};
// namespace TDEObex

#include "obexobjectmanagerImpl.moc"
// End of File

