#include <kdebug.h>

#include "kping.h"


void KPingPool::add( QString host ) {
  if ( hostMap.contains( host ) ) {
    hostMap[host]++;  // increase a number of clients
  } else {
    KPing *pinger = new KPing(); // create a new pinger and start pinging
    pingMap.insert( host, pinger );
    hostMap.insert( host, 1 );

    connect( pinger, SIGNAL( speed( QString, float ) ),
	     this, SIGNAL( speed( QString, float ) ) );
    connect( pinger, SIGNAL( error( QString ) ),
	     this, SLOT( slotError( QString ) ) );
    pinger->start( host );
  }
}


void KPingPool::remove( QString host ) {
  ASSERT( hostMap.contains( host ) ); 

  --hostMap[host];
  if ( hostMap[host] == 0 ) {
    pingMap[host]->stop();
    delete pingMap[host]; // !!! needed ?
    pingMap.remove( host );
  }
}


void KPingPool::slotError( QString host ) {
  ASSERT( hostMap.contains( host ) );

  hostMap.remove( host );
  delete pingMap[host]; // !!! needed ?
  pingMap.remove( host );

  speed( host, 0.0 );  // this will indicate problems with this ping
}


////////////////////////////////

KPing::~KPing() {
  if (childProcess.isRunning()) {
    childProcess.kill(15);
  }
}


void KPing::start( QString _host ) {

  host = _host;

  connect(&childProcess, SIGNAL(processExited(KProcess *)), 
	  SLOT(slotProcessDead(KProcess *)));
  connect(&childProcess, SIGNAL(receivedStdout(KProcess *, char *, int)), 
	  this, SLOT(slotPingOutput(KProcess *, char *, int)));
  connect(&childProcess, SIGNAL(receivedStderr(KProcess *, char *, int)), 
	  this, SLOT(slotPingOutput(KProcess *, char *, int)));

  childProcess.setExecutable( "ping" );
  childProcess << host;

  if (!childProcess.start(KProcess::NotifyOnExit, KProcess::All)){
    kdDebug( 7012 ) << "Ping not started" << endl;
    emit error( host );
  }
}


void KPing::slotProcessDead( KProcess* ) {
  // disconnect KProcess
  disconnect(&childProcess, SIGNAL(receivedStdout(KProcess *, char *, int)), 
	     this, SLOT(slotPingOutput(KProcess *, char *, int)));
  disconnect(&childProcess, SIGNAL(receivedStderr(KProcess *, char *, int)), 
	     this, SLOT(slotPingOutput(KProcess *, char *, int)));
  disconnect(&childProcess, SIGNAL(processExited(KProcess *)), 
	     this, SLOT(slotProcessDead(KProcess *)));
}


void KPing::slotPingOutput( KProcess*, char* buffer, int buflen ) {
  QString newstuff = buffer;
  newstuff.truncate( buflen );

  buf += newstuff;
  processOutput();
}


void KPing::processOutput() {
  int pos;

  while ( (pos = buf.find('\n')) != -1) {
    QString item = buf.left(pos);
    if (!item.isEmpty()) {
  
      int start = item.find( "time=" );
      int end = item.find( " ms" );

      QString spd  = item.mid( start+5, end );

      if ( spd.length() > 0 )
	emit speed( host, spd.toFloat() );
      else {
	emit error( host );
	slotProcessDead( 0L );
      }

    }
    buf = buf.right(buf.length()-pos-1);
  }
}


void KPing::stop() {
  kdDebug( 7013 ) << "Ping interrupted" << endl;
  childProcess.kill( SIGKILL );

  // no need to emit anything ( because we called stop() programatically )
}


#include "kping.moc"
