/***************************************************************************
 * $Id: statgraph.cpp,v 1.7 2008/07/31 19:56:26 hoganrobert Exp $
 *   Copyright (C) 2006 - 2008 Robert Hogan                                *
 *   robert@roberthogan.net                                                *
 *                                                                         *
 *   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.,                                       *
 *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
 ***************************************************************************/
/***************************************************************************
 *                                                                         *
 *   KCPULoad and KNetLoad are copyright (c) 1999-2000, Markus Gustavsson  *
 *                                       (c) 2002, Ben Burton              *
 *                                       (c) 2004-2005, Diego Pettenò      *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <tqpainter.h>
#include <tqlabel.h>

#include <kdebug.h>

#include "statgraph.h"


#define SOFT_STEP 3

const TQColor StatGraph::defaultBgColor = TQt::black;
const TQColor StatGraph::defaultReadingColor = TQt::yellow;
const TQColor StatGraph::defaultLabelColor = TQt::white;
const TQColor StatGraph::defaultGridColor = TQt::lightGray;

/// Color used to pass transparent colors
//const TQColor StatGraph::invalidColor = TQColor(-1, -1, -1);

StatGraph::StatGraph(TQWidget *parent, ushort pace, ushort gridPace, const TQString &label, const TQColor &bgColor, const char *name)
  : TQLabel(parent, name), m_style(Shades), m_gridPace(gridPace), m_pace(pace)
{
	setLabel(label);
	setBgColor(bgColor);
	
	m_numReadings = width() / pace;
	m_currReading = 0;
	m_readings = new uint[m_numReadings]; memset(m_readings, 0, m_numReadings*sizeof(uint));
	
}

StatGraph::~StatGraph()
{
	delete[] m_readings;
}

void StatGraph::setBgColor(const TQColor &color)
{
	m_bgColor = color;

	if ( m_bgColor.isValid() )
		setBackgroundColor(m_bgColor);
}

inline void StatGraph::paintGrid(TQPainter &p)
{
	p.setPen(m_gridColor);
	
	const uint gridLines = height() / m_gridPace;
	static uint graphWidth = width();
	for(uint i = 0; i < gridLines; i++)
	{
		const int lineHeight = i*m_gridPace;
		p.drawLine(0, lineHeight, graphWidth-1, lineHeight);
	}
}

inline void StatGraph::paintShades(TQPainter &p)
{
	//kdDebug() << "StatGraph::paintShades()" << endl;
	const uint graphHeight = height();
        for(uint i = 0; i < m_numReadings; i++)
	{
		ushort tmpPos = (m_currReading + i + 1) % m_numReadings;
		if ( m_readings[tmpPos] > graphHeight )
			m_readings[tmpPos] = graphHeight;
		
		for(uint j = 0; j < m_readings[tmpPos]; j++)
		{
			if (m_readings[tmpPos] == 0 || j == 0)
				p.setPen(m_bgColor);
			else
				p.setPen(m_readingColor.dark((100 * m_readings[tmpPos]) / j));

			p.drawPoint(i, graphHeight - 1 - j);
		}
	}
}

inline void StatGraph::paintBars(TQPainter &p)
{
	//kdDebug() << "StatGraph::paintBars()" << endl;
	const uint graphHeight = height();
	// Draw the readings bars, then the lower to save on pen adjustments.
	p.setPen(m_readingColor);
	for(uint i = 0; i < m_numReadings; i++)
	{
		ushort tmpPos = (m_currReading + i + 1) % m_numReadings;
		p.drawLine(i, graphHeight - 1 - m_readings[tmpPos], i, graphHeight - 1);
	}
}

inline void StatGraph::paintLines(TQPainter &p)
{
	//kdDebug() << "StatGraph::paintLines()" << endl;
	const uint graphHeight = height();
	// Draw the reading line, then the lower to save on pen adjustments.
	p.setPen(m_readingColor);
	for(uint i = 0; i < m_numReadings; i++)
	{
		ushort tmpPos = (m_currReading + i + 1) % m_numReadings;
		p.drawPoint(i, graphHeight - 1 - m_readings[tmpPos]);
	}
}

inline void StatGraph::paintLabel(TQPainter &p)
{
	//kdDebug() << "StatGraph::paintLabel()" << endl;
	p.setFont(TQFont("Helvetica", 8));
	p.setPen(m_labelColor);
	p.drawText(rect(), AlignLeft | AlignTop, m_label);
}

void StatGraph::clear()
{
	memset(m_readings, 0, m_numReadings*sizeof(uchar));
	update();
}

void StatGraph::addPercentReading(uchar reading, bool soft)
{
	//kdDebug() << "StatGraph::addPercentReading(" << (uint)reading << ", " << soft << ")" << endl;
	// Rescale the readings to a measure in pixels.
	uint pix = ( reading * height() )/100;
	
	if ( soft )
		softenReadings(pix);
	
	m_currReading = (m_currReading+1) % m_numReadings;
	m_readings[m_currReading] = pix;
	update();
    update();
}

void StatGraph::softenReadings(uint &reading)
{
	//kdDebug() << "StatGraph::softenReadings(" << reading << ")" << endl;
	uint old = m_readings[m_currReading];
	
	// Modify the reading.
	if (reading > old + SOFT_STEP)
		reading = old + SOFT_STEP;
	else if (reading > SOFT_STEP && reading < old - SOFT_STEP)
		reading = old - SOFT_STEP;
}

void StatGraph::resizeEvent(TQResizeEvent *e)
{
	TQLabel::resizeEvent(e);
	
	uint oldNumReadings = m_numReadings;
	m_numReadings = width() / m_pace;
	
	if ( m_numReadings != oldNumReadings )
	{
		uint *oldReadings = m_readings;
			
		m_readings = new uint[m_numReadings];
		memset(m_readings, 0, m_numReadings*sizeof(uint));
		
		if ( m_numReadings < oldNumReadings )
			memcpy(m_readings, oldReadings, m_numReadings*sizeof(uint));
		else
			memcpy(m_readings, oldReadings, oldNumReadings*sizeof(uint));
		delete oldReadings;
		m_currReading %= m_numReadings;
	}
}

void StatGraph::paintEvent(TQPaintEvent *e)
{
	TQLabel::paintEvent(e);
	if ( ! m_readingColor.isValid() ) m_readingColor = defaultReadingColor;
	if ( ! m_labelColor.isValid() ) m_labelColor = defaultLabelColor;
	if ( ! m_gridColor.isValid() ) m_gridColor = defaultGridColor;
	
	TQPainter p(this);
	if ( m_gridPace )
		paintGrid(p);
	
	switch(m_style)
	{
	case Shades:
		paintShades(p); break;
	case Bars:
		paintBars(p); break;
	case Lines:
		paintLines(p); break;
	default:
		kdDebug() << "Unknown style " << m_style << endl;
	}

	if ( ! m_label.isNull() )
		paintLabel(p);
}

void StatGraph::mousePressEvent(TQMouseEvent *e)
{
	TQLabel::mousePressEvent(e);
	m_button = e->button();
}

void StatGraph::mouseReleaseEvent(TQMouseEvent *e)
{
	TQLabel::mouseReleaseEvent(e);
	if ( m_button == e->button() )
	{
		switch(m_button)
		{
		case LeftButton:
			emit clickedLeft();
			break;
		case RightButton:
			emit clickedRight();
			break;
		default:
			kdDebug() << "Unknown button combination" << endl;
		}
	}
	m_button = TQt::NoButton;
}

#include "statgraph.moc"