/***************************************************************************
 *
 * knetworkmanager-device.cpp - A NetworkManager frontend for KDE 
 *
 * Copyright (C) 2005, 2006 Novell, Inc.
 *
 * Author: Timo Hoenig     <thoenig@suse.de>, <thoenig@nouse.net>
 *         Will Stephenson <wstephenson@suse.de>, <wstephenson@kde.org>
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 **************************************************************************/

// KDE includes
#include <kdebug.h>

// QtDBus includes
#include <dbus/qdbusconnection.h>
#include <dbus/qdbusproxy.h>
#include <dbus/qdbusdata.h>
#include <dbus/qdbusdatalist.h>
#include <dbus/qdbuserror.h>
#include <dbus/qdbusobjectpath.h>

// NM includes
#include <NetworkManager.h>

// KNM includes
#include "knetworkmanager.h"
#include "knetworkmanager-nm_proxy.h"
#include "knetworkmanager-device.h"
#include "knetworkmanager-devicestore.h"
#include "knetworkmanager-connection.h"
#include "knetworkmanager-connection_store.h"
#include "dbus/activeconnectionproxy.h"

class NMProxyPrivate
{
	public:
		NMProxyPrivate()
		{}

		static NMProxy* nm;
};

NMProxy* NMProxyPrivate::nm = NULL;

Device* NMProxy::getDefaultDevice()
{
	QDBusObjectPath connpath = getDefaultActiveConnection();
	if (!connpath.isEmpty())
	{
		QDBusObjectPath devpath = getDeviceForActiveConnection(connpath);
		if (!devpath.isEmpty())
			return DeviceStore::getInstance()->getDevice(devpath);
	}
	return NULL;
}

QDBusObjectPath NMProxy::getDeviceForActiveConnection(QDBusObjectPath act_conn_path)
{
	QDBusError      err;

	// we need a proxy for every active connection
	DBus::ActiveConnectionProxy* act_conn = new DBus::ActiveConnectionProxy(NM_DBUS_SERVICE, act_conn_path);
	act_conn->setConnection(QDBusConnection::systemBus());

	if (act_conn)
	{
		// get details about the active connection
		QValueList<QDBusObjectPath> devs   = act_conn->getDevices(err);
		if (!devs.isEmpty())
			return devs.first();
		delete act_conn;
	}
	
	return QDBusObjectPath();

}

QDBusObjectPath NMProxy::getDefaultActiveConnection()
{
	QDBusError      err;
	QValueList<QDBusObjectPath> connections;

	// get a list of all active connections from NM
	connections = NetworkManagerProxy::getActiveConnections(err);

	for (QValueList<QDBusObjectPath>::Iterator it = connections.begin(); it != connections.end(); ++it)
	{
		// we need a proxy for every active connection
		DBus::ActiveConnectionProxy* act_conn = new DBus::ActiveConnectionProxy(NM_DBUS_SERVICE, (*it));
		act_conn->setConnection(QDBusConnection::systemBus());

		if (act_conn)
		{
			if (act_conn->getDefault(err))
			{
				delete act_conn;
				return *it;
			}
			delete act_conn;
		}
	
	}

	return QDBusObjectPath();

}

ConnectionSettings::Connection* NMProxy::getActiveConnection(const Device* dev)
{
	QDBusError      err;
	QValueList<QDBusObjectPath> connections;

	// get a list of all active connections from NM
	connections = NetworkManagerProxy::getActiveConnections(err);

	for (QValueList<QDBusObjectPath>::Iterator it = connections.begin(); it != connections.end(); ++it)
	{
		// we need a proxy for every active connection
		DBus::ActiveConnectionProxy* act_conn = new DBus::ActiveConnectionProxy(NM_DBUS_SERVICE, (*it));
		act_conn->setConnection(QDBusConnection::systemBus());

		if (act_conn)
		{
			// get details about the active connection
			QString         service      = act_conn->getServiceName(err);
			QDBusObjectPath conn         = act_conn->getConnection(err);
			QDBusObjectPath specific_obj = act_conn->getSpecificObject(err);
			QValueList<QDBusObjectPath> devs   = act_conn->getDevices(err);
			for (QValueList<QDBusObjectPath>::Iterator it2 = devs.begin(); it2 != devs.end(); ++it2)
			{
				if (QString(*it2) == dev->getObjectPath())
				{
					// here is the connection we were looking for
					ConnectionStore* cstore = ConnectionStore::getInstance();
					if (cstore)
						return cstore->getConnection(QString(conn));
				}
			}
			delete act_conn;
		}
	
	}

	return NULL;
}

QValueList<QPair<ConnectionSettings::Connection*, Device*> > NMProxy::getActiveConnectionsMap()
{
	QDBusError      err;
	QValueList<QDBusObjectPath> connections;
	QValueList<QPair<ConnectionSettings::Connection*, Device*> > map;
	ConnectionStore* cstore = ConnectionStore::getInstance();
	DeviceStore* dstore = DeviceStore::getInstance();
	bool found = false;

	if (!dstore || !cstore)
		return map;

	// get a list of all active connections from NM
	connections = NetworkManagerProxy::getActiveConnections(err);

	for (QValueList<QDBusObjectPath>::Iterator it = connections.begin(); it != connections.end(); ++it)
	{
		// we need a proxy for every active connection
		DBus::ActiveConnectionProxy* act_conn = new DBus::ActiveConnectionProxy(NM_DBUS_SERVICE, (*it));
		act_conn->setConnection(QDBusConnection::systemBus());

		if (act_conn)
		{
			// get details about the active connection
			QString         service      = act_conn->getServiceName(err);
			QDBusObjectPath conn         = act_conn->getConnection(err);
			QDBusObjectPath specific_obj = act_conn->getSpecificObject(err);
			QValueList<QDBusObjectPath> devs   = act_conn->getDevices(err);
			found = false;
			for (QValueList<QDBusObjectPath>::Iterator it2 = devs.begin(); it2 != devs.end(); ++it2)
			{
				Device* device = dstore->getDevice(*it2);
				ConnectionSettings::Connection* connection = cstore->getConnection(QString(conn));
				if (connection)
				{
					map.append(QPair<ConnectionSettings::Connection*, Device*>(connection, device));
					found = true;
				}
			}
			if (!found)
			{
				// no device found for this connection -> just add it without device
				ConnectionSettings::Connection* connection = cstore->getConnection(QString(conn));
				if (connection)
					map.append(QPair<ConnectionSettings::Connection*, Device*>(connection, NULL));
			}
			delete act_conn;
		}
	
	}

	return map;
}

NMProxy::NMProxy()
	: NetworkManagerProxy(NM_DBUS_SERVICE, NM_DBUS_PATH)
{
	d = new NMProxyPrivate();
	NetworkManagerProxy::setConnection(QDBusConnection::systemBus());
}

void NMProxy::deactivateConnection(const ConnectionSettings::Connection* conn, const Device* dev)
{
	QDBusError      err;
	QValueList<QDBusObjectPath> connections;

	// get a list of all active connections from NM
	connections = NetworkManagerProxy::getActiveConnections(err);

	for (QValueList<QDBusObjectPath>::Iterator it = connections.begin(); it != connections.end(); ++it)
	{
		// we need a proxy for every active connection
		DBus::ActiveConnectionProxy* act_conn = new DBus::ActiveConnectionProxy(NM_DBUS_SERVICE, (*it));
		act_conn->setConnection(QDBusConnection::systemBus());

		if (act_conn)
		{
			if (act_conn->getConnection(err) == conn->getObjectPath())
			{
				if (dev)
				{
					// get details about the active connection
					QValueList<QDBusObjectPath> devs   = act_conn->getDevices(err);
					for (QValueList<QDBusObjectPath>::Iterator it2 = devs.begin(); it2 != devs.end(); ++it2)
					{
						if (QString(*it2) == dev->getObjectPath())
						{
							// this is the right one
							DeactivateConnection(*it, err);
							return;
						}
					}
				}
				else
				{
					DeactivateConnection(*it, err);
				}
			}
			delete act_conn;
		}
	}

}

void NMProxy::deactivateDevice(const Device* dev)
{
	QDBusError      err;
	QValueList<QDBusObjectPath> connections;

	// get a list of all active connections from NM
	connections = NetworkManagerProxy::getActiveConnections(err);

	for (QValueList<QDBusObjectPath>::Iterator it = connections.begin(); it != connections.end(); ++it)
	{
		// we need a proxy for every active connection
		DBus::ActiveConnectionProxy* act_conn = new DBus::ActiveConnectionProxy(NM_DBUS_SERVICE, (*it));
		act_conn->setConnection(QDBusConnection::systemBus());

		if (act_conn)
		{
			// get details about the active connection
			QValueList<QDBusObjectPath> devs   = act_conn->getDevices(err);
			for (QValueList<QDBusObjectPath>::Iterator it2 = devs.begin(); it2 != devs.end(); ++it2)
			{
				if (QString(*it2) == dev->getObjectPath())
				{
					// this is the right one
					DeactivateConnection(*it, err);
					return;
				}
			}
			delete act_conn;
		}
	}
}

bool NMProxy::isNMRunning()
{
	// Ask DBus if the NetworkManager service is available
	QDBusProxy* proxy = new QDBusProxy("org.freedesktop.DBus", "/", "org.freedesktop.DBus", QDBusConnection::systemBus());
	QValueList<QDBusData> params;
	params.append(QDBusData::fromString(NM_DBUS_SERVICE));
	QDBusMessage reply = proxy->sendWithReply("NameHasOwner", params);
	bool ret = reply.first().toBool();
	delete proxy;
	return ret;
}

NMProxy::~NMProxy()
{
	delete d;
}

NMProxy* NMProxy::getInstance()
{
	if (NMProxyPrivate::nm)
		return NMProxyPrivate::nm;
	return (NMProxyPrivate::nm = new NMProxy());
}


#include "knetworkmanager-nm_proxy.moc"
