// pppload - A PPP Load Monitor
// Copyright (C) 1996  Sean Vyain
// svyain@mail.tds.net
// smvyain@softart.com
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.

#include <qpainter.h>

#include "MainWindow.H"
#include "Options.H"

MainWindow::MainWindow( QWidget* parent, const char* name )
: QWidget( parent, name ), _historySize( 0 ), _txHistory( 0 ), _rxHistory( 0 ), _txAverage( 0 ), _rxAverage( 0 ), _max( 1 )
{
	// Allocate data arrays.
	_dataSize = options->period() / options->interval();
	_txData = new int[ _dataSize ];
	_rxData = new int[ _dataSize ];
	for ( int i = 0; i < _dataSize; i++ ) {
		_txData[i] = 0;
		_rxData[i] = 0;
	}
	
	// Get font metrics.
	_fontWidth    = fontMetrics().width( '0' );
	_fontHeight   = fontMetrics().height();
	_fontBaseline = _fontHeight - fontMetrics().descent()-1;

	resize( 200, 100 );
}

void MainWindow::resizeEvent( QResizeEvent* )
{
	int* txNew = new int[ width() ];
	int* rxNew = new int[ width() ];
	
	for ( int i = 0; (i < _historySize) && (i < width()); i++ ) {
		txNew[i] = _txHistory[i];
		rxNew[i] = _rxHistory[i];
	}
	for ( int i = _historySize; i < width(); i++ ) {
		txNew[i] = 0;
		rxNew[i] = 0;
	}
	
	delete [] _txHistory;
	delete [] _rxHistory;

	_historySize = width();
	_txHistory = txNew;
	_rxHistory = rxNew;
	
	// Redraw the graph.
	_pixmap.resize( width(), height() );
	redrawGraph();
}

void MainWindow::updateStats( unsigned int rxDelta, unsigned int txDelta, unsigned int rxTotal, unsigned int txTotal )
{
	int oldMax = _max;

	// Compute the new transmit and receive load averages
	_txAverage = _txAverage - _txData[_dataSize-1] + txDelta;
	_rxAverage = _rxAverage - _rxData[_dataSize-1] + rxDelta;
	
	// Shift the transmit and receive data.
	for ( int i = _dataSize-1; i > 0; i-- ) {
		_txData[i] = _txData[i-1];
		_rxData[i] = _rxData[i-1];
	}
	_txData[0] = txDelta;
	_rxData[0] = rxDelta;
	
	// Move the existing data over one pixel.
	bitBlt( &_pixmap, 0, 0, &_pixmap, 1, 0, width() - 1, height(), CopyROP );
	
	// Find a new maximum, if needed.
	if (( _txHistory[_historySize-1] == _max ) || ( _rxHistory[_historySize-1] == _max )) {
		_max = 1;
		for ( int i = 0; i < _historySize-1; i++ ) {
			if ( options->showTx() && _txHistory[i] > _max ) _max = _txHistory[i];
			if ( options->showRx() && _rxHistory[i] > _max ) _max = _rxHistory[i];
		}
	}

	// Shift the history by one.
	for ( int i = _historySize-1; i > 0; i-- ) {
		_txHistory[i] = _txHistory[i-1];
		_rxHistory[i] = _rxHistory[i-1];
	}
	
	// Store the new transfer rates.
	_txHistory[0] = _txAverage / _dataSize;
	_rxHistory[0] = _rxAverage / _dataSize;
	
	// Update the maximum rate (again).
	if ( options->showTx() && _txHistory[0] > _max ) _max = _txHistory[0];
	if ( options->showRx() && _rxHistory[0] > _max ) _max = _rxHistory[0];

	// Rescale, if needed.
	if ( oldMax != _max ) {
		redrawGraph();
	}

	// Draw the new transfer rates.
	QPainter p;
	p.begin( &_pixmap );
	p.setBackgroundColor( backgroundColor() );
	p.eraseRect( width() - 1, 0, width() - 1, height() );
	if ( options->showRx() ) {
		p.setPen( options->rxColor() );
		p.drawLine( width() - 1, height(), width() - 1, height() - _rxHistory[0] * height() / _max );
	}
	if ( options->showTx() ) {
		p.setPen( options->txColor() );
		p.drawLine( width() - 1, height(), width() - 1, height() - _txHistory[0] * height() / _max );
	}
	p.setPen( black );
	for ( int i = options->divider()*options->interval(); i < _max; i += options->divider()*options->interval() ) {
		p.drawPoint( width()-1, height() - i * height() / _max );
	}

	// Draw the total number of bytes transfered.
	int length = 0;
	if ( options->showTx() ) length += _txStr.length();
	if ( options->showRx() ) length += _rxStr.length();
	if ( options->showTx() && options->showRx() ) length++;
	p.eraseRect( 0, 0, length*_fontWidth+2, _fontHeight );
	_txStr = bytesToString( txTotal );
	_rxStr = bytesToString( rxTotal );
	length = 0;
	if ( options->showTx() ) {
		p.setPen( options->txColor() );
		p.drawText( 1+length, _fontBaseline, (const char*)_txStr );
		length += _txStr.length();
	}
	if ( options->showTx() && options->showRx() ) {
		p.setPen( black );
		p.drawText( 1+length*_fontWidth, _fontBaseline, "/" );
		length++;
	}
	if ( options->showRx() ) {
		p.setPen( options->rxColor() );
		p.drawText( 1+length*_fontWidth, _fontBaseline, (const char*)_rxStr );
	}
	p.end();
	
	paintEvent( 0 );
}

void MainWindow::paintEvent( QPaintEvent* )
{
	bitBlt( this, 0, 0, &_pixmap, 0, 0, width(), height(), CopyROP );
}

QString MainWindow::bytesToString( int bytes )
{
	QString str;
	
	if ( bytes < 1024 ) {
		str.sprintf( "%db", bytes );
	} else if ( bytes < 1024 * 1024 ) {
		str.sprintf( "%.1fk", float( bytes ) / 1024.0 );
	} else {
		str.sprintf( "%.1fM", float( bytes ) / 1024.0 / 1024.0 );
	}

	return str;
}

void MainWindow::linkDown()
{
	for ( int i = 0; i < _dataSize; i++ ) {
		_txData[i] = 0;
		_rxData[i] = 0;
	}
	
	for ( int i = 0; i < _historySize; i++ ) {
		_txHistory[i] = 0;
		_rxHistory[i] = 0;
	}
	
	_max = 1;
	_txAverage = 0;
	_rxAverage = 0;

	redrawGraph();
	paintEvent( 0 );
}

void MainWindow::redrawGraph()
{
	QPainter p;
	p.begin( &_pixmap );
	p.setBackgroundColor( backgroundColor() );
	p.eraseRect( 0, 0, width(), height() );
	for ( int i = 0; i < _historySize; i++ ) {
		if ( options->showRx() ) {
			p.setPen( options->rxColor() );
			p.drawLine( width() - i - 1, height(), width() - i - 1, height() - _rxHistory[i] * height() / _max );
		}
		if ( options->showTx() ) {
			p.setPen( options->txColor() );
			p.drawLine( width() - i - 1, height(), width() - i - 1, height() - _txHistory[i] * height() / _max );
		}
	}
	p.setPen( black );
	for ( int i = options->divider()*options->interval(); i < _max; i += options->divider()*options->interval() ) {
		p.drawLine( 0, height() - i * height() / _max, width(), height() - i * height() / _max );
	}
	
	// Draw the total number of bytes transfered.
	int length = 0;
	if ( options->showTx() ) length += _txStr.length();
	if ( options->showRx() ) length += _rxStr.length();
	if ( options->showTx() && options->showRx() && length ) length++;
	p.eraseRect( 0, 0, length*_fontWidth+2, _fontHeight );
	length = 0;
	if ( options->showTx() ) {
		p.setPen( options->txColor() );
		p.drawText( 1+length, _fontBaseline, (const char*)_txStr );
		length += _txStr.length();
	}
	if ( options->showTx() && options->showRx() && length ) {
		p.setPen( black );
		p.drawText( 1+length*_fontWidth, _fontBaseline, "/" );
		length++;
	}
	if ( options->showRx() ) {
		p.setPen( options->rxColor() );
		p.drawText( 1+length*_fontWidth, _fontBaseline, (const char*)_rxStr );
	}
	p.end();
}
