/*
    knetd, KDE Network Daemon

    Copyright (c) 2005 by Engin AYDOGAN		<engin @ bzzzt.biz>

    *************************************************************************
    *                                                                       *
    * 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.                                   *
    *                                                                       *
    *************************************************************************
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <kservice.h>
#include <kdebug.h>
#include <klocale.h>
#include <kconfig.h>
#include <kpassivepopup.h>

#include <qtimer.h>

#include <limits>

#include "knetd.h"
#include "systemtray.h"
#include "popupmanager.h"
#include "popup.h"

#include "sysfsclass.h"
#include "device.h"

extern "C" {
   KDE_EXPORT KDEDModule *create_knetd(const QCString &name)
	{
		return new KNetD(name);
	}
};

class KNetD::Private
{
public:
	Private( KNetD* p )
	{
		tray = new SystemTray( p );
		popup = new PopupManager;
		instance = new KInstance( "knetd" );
		cl = SYSFSClass::build( "net" );
	}
	~Private()
	{
		delete popup;
		delete instance;
		delete tray;
		if( cl ) delete cl;
	}
	SystemTray* tray;
	QValueList<AbstractDevice*> deviceList;
	KInstance* instance;
	SYSFSClass* cl;
	PopupManager *popup;
};

KNetD::KNetD( const QCString& n )
 : KDEDModule( n ), d( new Private( this ) )
{
	if( d->cl )
	{
		readConfig();
		connect( d->cl, SIGNAL( deviceFound( const QString& ) ),
			this, SLOT( slotDeviceFound( const QString& ) ) );
		connect( d->cl, SIGNAL( deviceRemoved( const QString& ) ),
			this, SLOT( slotDeviceRemoved( const QString& ) ) );
	}
	else
	{
		// sysfs is not available, warn the user and do nothing.
		d->tray->message( i18n( "Could not fetch net class from sysfs." ) );
		kdError() << k_funcinfo << "Could not fetch net class from sysfs." << endl;
	}
}

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

int
KNetD::version() const
{
	return (VER_MAJ << 16) + (VER_MID << 8) + VER_MIN;
}

void
KNetD::readConfig()
{
	KConfig* config = KGlobal::config();
	config->setGroup( "Daemon" );
	int interval = config->readNumEntry( "interval", 100 );
	d->cl->killTimers();
	d->cl->startTimer( interval );
}
void
KNetD::slotDeviceFound( const QString& dev )
{
	d->popup->enqueue( new Popup( "Device found: " + dev ) );
	Device *newDev = Device::build( dev );
	if( newDev )
	{
		connect( newDev, SIGNAL( linkUp( AbstractDevice* ) ),
			this, SLOT( slotLinkUp( AbstractDevice* ) ) );
		connect( newDev, SIGNAL( linkDown( AbstractDevice* ) ),
			this, SLOT( slotLinkDown( AbstractDevice* ) ) );
		connect( newDev, SIGNAL( interfaceUp( AbstractDevice* ) ),
			this, SLOT( slotInterfaceUp( AbstractDevice* ) ) );
		connect( newDev, SIGNAL( interfaceDown( AbstractDevice* ) ),
			this, SLOT( slotInterfaceDown( AbstractDevice* ) ) );
		connect( newDev, SIGNAL( ipChanged( AbstractDevice* ) ),
			this, SLOT( slotIpChanged( AbstractDevice* ) ) );
		d->deviceList.push_back( newDev );
	} else
	{
		kdError() << k_funcinfo << "Could not create device [ " << dev << " ]" << endl;
	}
	selectBestDevice();
}

void
KNetD::slotDeviceRemoved( const QString& dev )
{
	d->popup->enqueue( new Popup( "Device removed: " + dev ) );

	AbstractDevice* ref = find( dev );
	if( !ref )
	{
		d->deviceList.remove( ref );
		delete ref;
	}
	else
	{
		kdWarning() << k_funcinfo << "This should never have happened." << endl;
	}
	/*
	for( QValueList<Device*>::iterator it = d->deviceList.begin(); it != d->deviceList.end(); ++it )
	{
		if( QString((*it)->name()) == dev )
		{
			delete *it;
			it = d->deviceList.remove( it );
		}
	}
	*/
	selectBestDevice();
}

void
KNetD::slotIpChanged( AbstractDevice* dev )
{
	d->popup->enqueue( new Popup( dev->name() + "'s IP changed to " + dev->ip4() ) );
/*
 * 	KPassivePopup* p = new KPassivePopup();
	p->setView( "IP Changed", dev->name() + "'s IP Changed to " + dev->ip4() );
	p->setTimeout( 0 );
	d->popup->enqueue( p );
	*/
// 	d->popup->enqueue( KPassivePopup::message( "IP Changed", dev->name() + "'s IP Changed to " + dev->ip4(),0 ) );
}

void
KNetD::slotLinkUp( AbstractDevice* dev )
{
	d->popup->enqueue( new Popup( "Link found on " + dev->name() ) );
	selectBestDevice();
}

void
KNetD::slotLinkDown( AbstractDevice* dev )
{
	d->popup->enqueue( new Popup( "Link lost on " + dev->name() ) );
	selectBestDevice();
}

void
KNetD::slotInterfaceUp( AbstractDevice* dev )
{
	d->popup->enqueue( new Popup( "Interface up on " + dev->name() ) );
	selectBestDevice();
}

void
KNetD::slotInterfaceDown( AbstractDevice* dev )
{
	d->popup->enqueue( new Popup( "Interface down on " + dev->name() ) );
	selectBestDevice();
}

void
KNetD::selectBestDevice()
{
}

QStringList
KNetD::devices() const
{
	return d->cl->devices();
}

AbstractDevice*
KNetD::find( const QString& n )
{
	for( QValueList<AbstractDevice*>::iterator it = d->deviceList.begin(); it != d->deviceList.end(); ++it )
	{
		if( (*it)->name() == n )
		{
			return *it;
		}
	}
	return 0;
}

bool
KNetD::isWireless( const QString& n )
{
	return find( n )->isWireless();
}

bool
KNetD::isEthernet( const QString& n )
{
	return find( n )->isEthernet();
}

QString
KNetD::ip4( const QString& n )
{
	return find( n )->ip4();
}

QString
KNetD::ip6( const QString& n )
{
	return find( n )->ip6();
}

QString
KNetD::mac( const QString& n )
{
	return find( n )->mac();
}

QString
KNetD::netmask( const QString& n )
{
	return find( n )->netmask();
}

QString
KNetD::gateway( const QString& n )
{
	return find( n )->gateway();
}

void
KNetD::disableTray()
{
	d->tray->hide();
}

void
KNetD::enableTray()
{
	d->tray->show();
}

void
KNetD::toggleTray()
{
	if( d->tray->isVisible() )
		d->tray->hide();
	else
		d->tray->show();
}

bool
KNetD::isTrayEnabled()
{
	return d->tray->isVisible();
}

#include "knetd.moc"
