/***************************************************************************
 *
 * knetworkmanager-device_tray.cpp - A NetworkManager frontend for KDE
 *
 * Copyright (C) 2005, 2006 Novell, Inc.
 *
 * Author: Helmut Schaa       <hschaa@suse.de>, <helmut.schaa@gmx.de>
 *
 * 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
 *
 **************************************************************************/

class WirelessDialog;

// Qt includes
#include <qevent.h>
#include <qvbox.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qbitmap.h>
#include <qimage.h>
#include <qpixmap.h>
#include <qpixmapcache.h>
#include <qpainter.h>
#include <qstyle.h>
#include <qtimer.h>

// KDE includes
#include <dcopclient.h>
#include <kdebug.h>
#include <kdialogbase.h>
#include <knotifyclient.h>
#include <knotifydialog.h>
#include <kiconeffect.h>
#include <klocale.h>
#include <kstdguiitem.h>
#include <khelpmenu.h>
#include <kprocess.h>
#include <kiconloader.h>
#include <kconfig.h>
#include <kmessagebox.h>
#include <kglobalsettings.h>

// KNM includes
#include "knetworkmanager-device_tray.h"
#include "knetworkmanager-device.h"
#include "knetworkmanager-menu_subhead.h"
#include "knetworkmanager-connection_settings_dialog.h"
#include "knetworkmanager-connection_setting_info.h"
#include "knetworkmanager-nm_proxy.h"
#include "knetworkmanager-connection.h"

using namespace ConnectionSettings;

class DeviceTrayPrivate
{
	public:

		DeviceTrayPrivate() 
			: dev(NULL)
		{
			tooltips[NM_DEVICE_STATE_UNKNOWN] = i18n("Unknown");
			tooltips[NM_DEVICE_STATE_UNAVAILABLE] = i18n("Down");
			tooltips[NM_DEVICE_STATE_UNMANAGED] = i18n("Unmanaged");
			tooltips[NM_DEVICE_STATE_DISCONNECTED] = i18n("Disconnected");
			tooltips[NM_DEVICE_STATE_PREPARE] = i18n("Preparing");
			tooltips[NM_DEVICE_STATE_CONFIG] = i18n("Configuration");
			tooltips[NM_DEVICE_STATE_NEED_AUTH] = i18n("Awaiting authentication");
			tooltips[NM_DEVICE_STATE_IP_CONFIG] = i18n("IP configuration");
			tooltips[NM_DEVICE_STATE_ACTIVATED] = i18n("Activated");
			tooltips[NM_DEVICE_STATE_FAILED] = i18n("Failed");
		}
			
		~DeviceTrayPrivate() {}

		Device* dev;
		QMap<NMDeviceState, QMovie>  movies;
		QMap<NMDeviceState, QPixmap> pixmaps;
		QMap<NMDeviceState, QString> tooltips;
};

Device* DeviceTray::getDevice() const
{
	return d->dev;
}

QString DeviceTray::getTooltipText()
{
	NMDeviceState state = d->dev->getState();
	QString tooltip = QString::null;

	if (!d->tooltips[state].isEmpty())
		tooltip += i18n("State: %1").arg(d->tooltips[state]);

	return tooltip;
}

void DeviceTray::enterEvent (QEvent* /*e*/)
{
	// show tooltip
	QToolTip::remove (this);
	QString tooltip = getTooltipText();

	if (!tooltip.isEmpty())
		QToolTip::add (this, tooltip);
}


void DeviceTray::setPixmap(const QPixmap& pixmap)
{
	/*
  int oldPixmapWidth = pixmap.size().width();
	int oldPixmapHeight = pixmap.size().height();

	// we want to show the interface name
	QString iface = d->dev->getInterface();

	// grab a font
	QFont   iface_font = KGlobalSettings::generalFont();
//	iface_font.setBold(true);

	// resize the font to fit the icon's size
	float fontSize = iface_font.pointSizeFloat();
	QFontMetrics qfm(iface_font);
	int height = qfm.height();
	int width = qfm.width(iface);
	float factor = 1.0f;
	float factor2 = 1.0f;

	if (height > (oldPixmapHeight / 2.0f))
		factor = float(oldPixmapHeight / 2.0f) / float(height);

	if (width > (oldPixmapWidth / 1.1f))
		factor2 = float(oldPixmapWidth / 1.1f) / float(width);

	fontSize *= (factor2 < factor) ? factor2 : factor;

	iface_font.setPointSizeFloat( fontSize);

	// draw the text to a bitmap and put is as an overlay on top of the pixmap
	QPixmap iface_pixmap(oldPixmapWidth, oldPixmapHeight);
	iface_pixmap.fill(Qt::white);
	QPainter p(&iface_pixmap);
	p.setFont(iface_font);
	p.setPen(Qt::blue);
	p.drawText(iface_pixmap.rect(), Qt::AlignHCenter | Qt::AlignBottom, iface);
	iface_pixmap.setMask(iface_pixmap.createHeuristicMask());
	QImage iface_image = iface_pixmap.convertToImage();
	
	QImage pixmap_with_overlay = pixmap.convertToImage();
	KIconEffect::overlay(pixmap_with_overlay, iface_image);

	QPixmap new_pixmap;
	new_pixmap.convertFromImage(pixmap_with_overlay);
	// call base-class setPixmap
	KSystemTray::setPixmap(new_pixmap);
*/
	KSystemTray::setPixmap(pixmap);
}

void DeviceTray::contextMenuAboutToShow (KPopupMenu* menu)
{
	menu->clear();

	// insert title
	menu->insertTitle (SmallIcon ("knetworkmanager",  QIconSet::Automatic), "KNetworkManager", -1, -1);

	// let the specific device_tray add its items
	addMenuItems(menu);

	// quit
	menu->insertSeparator ();
	KAction* quitAction = actionCollection ()->action (KStdAction::name (KStdAction::Quit));
	if (quitAction)
		quitAction->plug (menu);
}

void DeviceTray::setPixmapForState(NMDeviceState state, QMovie movie)
{
	d->movies[state] = movie;
	slotUpdateDeviceState();
}

void DeviceTray::setPixmapForState(NMDeviceState state, QPixmap pixmap)
{
	d->pixmaps[state] = pixmap;
	slotUpdateDeviceState();
}

void DeviceTray::updateTrayIcon(NMDeviceState state)
{
	// stop the old movie to avoid unnecessary wakups
	if (movie())
		movie()->pause();

	if (d->movies.find(state) != d->movies.end() && !d->movies[state].isNull())
	{
		// animation desired
		int frame = -1;
		if (movie())
			frame = movie()->frameNumber();

		// set the movie
		setMovie(d->movies[state]);

		// start at the same frame as the movie before
		if (frame > 0)
			movie()->step(frame);

		// start the animation
		movie()->unpause();
	}
	else if (d->pixmaps.find(state) != d->pixmaps.end() && !d->pixmaps[state].isNull())
		setPixmap(d->pixmaps[state]);
	else
		setPixmap(loadIcon("KNetworkManager"));
}

void DeviceTray::updateActions(NMDeviceState state)
{
	// allow device deactivation only when device is activated
	KAction* deactivate = actionCollection()->action("deactivate_device");
	if (deactivate)
		deactivate->setEnabled( (state == NM_DEVICE_STATE_ACTIVATED || 
		                         state == NM_DEVICE_STATE_IP_CONFIG ||
		                         state == NM_DEVICE_STATE_PREPARE ||
		                         state == NM_DEVICE_STATE_CONFIG || 
		                         state == NM_DEVICE_STATE_NEED_AUTH) );
}

void DeviceTray::updateActiveConnection(NMDeviceState state)
{
	if (state != NM_DEVICE_STATE_ACTIVATED)
		return;

	NMProxy* nm = NMProxy::getInstance();
	Connection* active_conn = nm->getActiveConnection(d->dev);
	if (active_conn)
	{
		Info* info = dynamic_cast<Info*>(active_conn->getSetting(NM_SETTING_CONNECTION_SETTING_NAME));
		if (info)
			info->setTimestamp(QDateTime::currentDateTime());
	}
}

void DeviceTray::slotUpdateDeviceState(NMDeviceState state)
{
	updateTrayIcon(state);
	updateActions(state);
	updateActiveConnection(state);
}

void DeviceTray::slotUpdateDeviceState()
{
	slotUpdateDeviceState(d->dev->getState());
}

DeviceTray::DeviceTray (Device* dev) : KSystemTray ()
{
	d = new DeviceTrayPrivate();
	d->dev = dev;

	d->pixmaps[NM_DEVICE_STATE_UNKNOWN] = loadIcon("nm_no_connection");
	d->pixmaps[NM_DEVICE_STATE_UNMANAGED] = loadIcon("nm_no_connection");
	d->pixmaps[NM_DEVICE_STATE_UNAVAILABLE] = loadIcon("nm_no_connection");
	d->pixmaps[NM_DEVICE_STATE_DISCONNECTED] = loadIcon("nm_no_connection");

	d->movies[NM_DEVICE_STATE_PREPARE] = QMovie( KGlobal::iconLoader()->moviePath("nm_stage01_connecting", KIcon::Panel));
	d->movies[NM_DEVICE_STATE_PREPARE].pause();

	d->movies[NM_DEVICE_STATE_CONFIG] = QMovie( KGlobal::iconLoader()->moviePath("nm_stage02_connecting", KIcon::Panel));
	d->movies[NM_DEVICE_STATE_CONFIG].pause();

	d->movies[NM_DEVICE_STATE_IP_CONFIG] = QMovie( KGlobal::iconLoader()->moviePath("nm_stage03_connecting", KIcon::Panel));
	d->movies[NM_DEVICE_STATE_IP_CONFIG].pause();

	d->movies[NM_DEVICE_STATE_NEED_AUTH] = d->movies[NM_DEVICE_STATE_CONFIG];
	d->movies[NM_DEVICE_STATE_NEED_AUTH].pause();

	d->pixmaps[NM_DEVICE_STATE_ACTIVATED] = loadIcon("ok");

	d->pixmaps[NM_DEVICE_STATE_FAILED] = loadIcon("nm_no_connection");

	// get notified when the device state changes
	connect(dev, SIGNAL(StateChanged(NMDeviceState)), this, SLOT(slotUpdateDeviceState(NMDeviceState)));

	setMouseTracking (true);

	// defer the initial call to slotUpdateDeviceState as it will crask knm when called directly from here
	// virtual method calls are not allowed in constructor
	QTimer::singleShot(0, this, SLOT(slotUpdateDeviceState()));

	// Actions used for plugging into the menu
	new KAction (i18n ("Deactivate connection..."),
					     SmallIcon ("no",  QIconSet::Automatic), 0,
					     dev, SLOT (slotDeactivate()), actionCollection (), "deactivate_device");
}

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


#include "knetworkmanager-device_tray.moc"
