/***************************************************************************
 *   Copyright (C) 2006 by   Daniel Gollub                                 *
 *                            <dgollub@suse.de>                            *
 *                 2006-2007 Danny Kukawka                                 *
 *                            <dkukawka@suse.de>, <danny.kukawka@web.de>   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of version 2 of the GNU General Public License     *
 *   as published by the Free Software Foundation.                         *
 *                                                                         *
 *   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 Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
 ***************************************************************************/

/*! 
 * \file	detaileddialog.cpp
 * \brief	In this file can be found the detailed dialog related code.
 * \author	Daniel Gollub <dgollub@suse.de>
 * \author	Danny Kukawka, <dkukawka@suse.de>, <danny.kukawka@web.de>
 * \date	2006-2007
 */

// KDE headers:
#include <kled.h>
#include <kiconloader.h>
#include <klocale.h>

// QT headers:
#include <tqpushbutton.h>
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqtimer.h>
#include <tqgroupbox.h>

// own headers
#include "detaileddialog.h"

/*! 
 * This is the default constructor of the class detaileddialog. 
 */
detaileddialog::detaileddialog( HardwareInfo *_hwinfo, TQPixmap *_pixmap, Settings *_set, 
				TQWidget* parent, const char* name )
    			      : detailed_Dialog( parent, name, false, WDestructiveClose ) {
	kdDebugFuncIn(trace);
	hwinfo = _hwinfo;
	config = _set;
	pixmap = _pixmap;
	primaryBatteries = hwinfo->getPrimaryBatteries();
	cpuInfo = new CPUInfo();

	int batteries = primaryBatteries->getNumBatteries();
	numOfCPUs = cpuInfo->getCPUNum();

	this->setCaption(i18n("KPowersave Information Dialog"));
	
	// use this as compromise with current translation process
	// TODO: remove them in the next translation round
	GeneralGroup->setTitle(i18n("Miscellaneous"));
	ProcessorGroup->setTitle(i18n("CPUs"));

	ProcessorGridLayout = new TQGridLayout(ProcessorFrame, numOfCPUs, 2, 0, 5, "ProcessorGridLayout");
	
	if (batteries > 0) {
		if (batteries > 1) batteries++;

		BatteryGroup->setTitle(i18n("Battery state:").remove(":"));
		BatteryGridLayout = new TQGridLayout(BatteryFrame, batteries, 2, 0, 5, "BatteryGridLayout");

		for (int i = 0;  i < batteries; i++) {
			TQLabel *Label = new TQLabel(BatteryFrame, "BatteryLabel");
			if ((primaryBatteries->getNumBatteries() > 1) && (i == 0))
				Label->setText( i18n( "Total:" ));
			else if ((primaryBatteries->getNumBatteries() > 1) && (i > 0))
				Label->setText( i18n( "Battery %1" ).arg(i));
			else 
				Label->setText( i18n( "Battery %1" ).arg(i + 1));
	
			BatteryGridLayout->addWidget( Label, i , 0);
	
			KProgress *PBar = new KProgress(BatteryFrame, "BatteryPBar");
			PBar->setTextEnabled(true);
	
			BatteryPBar.append( PBar );
			BatteryGridLayout->addWidget( PBar, i , 1);
		}
		BatteryFrame->adjustSize();
		tl_powerConsDesc->hide();
		tl_powerConsValue->hide();
		connect(hwinfo, TQT_SIGNAL(generalDataChanged()), this, TQT_SLOT(setBattery()));
		connect(primaryBatteries, TQT_SIGNAL(batteryChanged()), this, TQT_SLOT(setBattery()));
		connect(primaryBatteries, TQT_SIGNAL(batteryChargingStateChanged(int)), this,
			TQT_SLOT(setPowerConsumption()));
		connect(primaryBatteries, TQT_SIGNAL(batteryRateChanged()), this, 
			TQT_SLOT(setPowerConsumption()));
		setBattery();
		setPowerConsumption();
	} else {
		BatteryGroup->hide();
	}

	cpuInfo->checkCPUSpeed();

	ProcessorPictogram->setPixmap(SmallIcon("processor", 22));

	for (int i = 0; i < numOfCPUs; i++) {
		TQLabel *Label = new TQLabel(ProcessorFrame, "ProcessorLabel");
		Label->setText( i18n( "Processor %1" ).arg(i + 1));
		ProcessorGridLayout->addWidget( Label, i , 0);

		KProgress *CPUPBar = new KProgress(ProcessorFrame, "ProcessorPBar");
		CPUPBar->setTextEnabled(true);

		ProcessorPBar.append( CPUPBar );
		ProcessorGridLayout->addWidget( CPUPBar, i , 1);
	}
	ProcessorFrame->adjustSize();
	
	connect(OkButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(closeDetailedDlg()));
	connect(hwinfo, TQT_SIGNAL(ACStatus(bool)), this, TQT_SLOT(setAC()));
	// TODO: replace event
	//connect(pd, TQT_SIGNAL(schemeDataChanged()), this, TQT_SLOT(setInfos()));
	connect(hwinfo, TQT_SIGNAL(generalDataChanged()), this, TQT_SLOT(setInfos()));

	if (hwinfo->supportCPUFreq() || cpuInfo->cpuFreqHW) {
		// Check if cpufreq is available
		cpuInfo->getCPUMaxSpeed();
		setProcessor();
		connect(hwinfo, TQT_SIGNAL(currentCPUFreqPolicyChanged()), this, TQT_SLOT(setInfos()));
	} else {
		// .. if not, use cpu throttling
		if (!cpuInfo->getCPUThrottlingState() || numOfCPUs <= 1) {
			connect(hwinfo, TQT_SIGNAL(generalDataChanged()), this, TQT_SLOT(setProcessorThrottling()));
		}
		setProcessorThrottling();
	}

	setAC();
	setInfos();

	kdDebugFuncOut(trace);
}

/*! This is the default destructor of class detaileddialog. */
detaileddialog::~detaileddialog() {	
	kdDebugFuncIn(trace);
	// no need to delete child widgets, TQt does it all for us
}

/*!
 * \b TQT_SLOT called if the dialog is closed by the user.
 * We do some cleanups here.
 */
void detaileddialog::closeDetailedDlg() {
	kdDebugFuncIn(trace);

	this->close();
	delete(this);
}

/*!
 * \b TQT_SLOT to set up the battery progress widgets.
 */
void detaileddialog::setBattery() {
	kdDebugFuncIn(trace);

	TQString minutes;
	int batteries = 0;

	
	// refresh battery collection
	primaryBatteries = hwinfo->getPrimaryBatteries();
	TQPtrList<Battery> allBatteries = hwinfo->getAllBatteries();

	batteries = primaryBatteries->getNumBatteries();

	if (batteries > 1) batteries++;

	for (int i=0; i < batteries ; i++) {
		int _r_min = 0;
		int _r_per = 0;
		int _c_state = UNKNOWN_STATE;
		bool _present = false;

		BatteryPBar[i]->setTextEnabled(true);
		BatteryPBar[i]->reset();

		if ( (primaryBatteries->getNumBatteries() > 1) && (i == 0) ) {
			// first progressbar with overall infos
			
			_r_min = primaryBatteries->getRemainingMinutes();
			_r_per = primaryBatteries->getRemainingPercent();
			_c_state = primaryBatteries->getChargingState();
			if (primaryBatteries->getNumPresentBatteries() > 0)
				_present = true;
		}
		else {
			// find the related primary battery
			int _current = 0;
			Battery *bat;
			for (bat = allBatteries.first(); bat; bat = allBatteries.next() ) {
				if (bat->getType() ==  primaryBatteries->getBatteryType()) {
					_current++;
					
					if (!bat->isPresent()) {
						_present = false;
					}
					else {
						_r_min = bat->getRemainingMinutes();
						_r_per = bat->getPercentage();
						_c_state = bat->getChargingState();
						_present = true;
					}

					if (_current == i) {
 						break;
					}
					
				}
			}
		}

		if (!_present) {
			BatteryPBar[i]->setFormat(i18n("not present"));
			BatteryPBar[i]->setProgress(0);
			BatteryPBar[i]->setEnabled(false);
		} else {
			int hours = _r_min / 60;
			minutes.setNum(_r_min % 60);
			minutes = minutes.rightJustify(2, '0');	
	
			// CHARG_STATE_CHARG_DISCHARG --> display only the percentage
			if (_c_state == UNKNOWN_STATE || _r_min < 0 ) {
				BatteryPBar[i]->setFormat("%p%");
			} else if (_c_state == CHARGING && hwinfo->hasAPM() ) {
				// this should fix apm, where we have no time info if charging
				BatteryPBar[i]->setFormat("%p% " + i18n("charged"));
			} else if (_c_state == CHARGING) {
				TQString temp = i18n("%1:%2 h until charged").arg(hours).arg(minutes);
				BatteryPBar[i]->setFormat(temp);
			} else if (_c_state == DISCHARGING) {
				TQString temp = i18n("%1:%2 h remaining").arg(hours).arg(minutes);
				BatteryPBar[i]->setFormat(temp);
			
			} else {
				//fallback 
				BatteryPBar[i]->setFormat(i18n("unknown"));
			}
	
			if (_r_per < 0)
				BatteryPBar[i]->setProgress(0);
			else	
				BatteryPBar[i]->setProgress(_r_per);
			BatteryPBar[i]->setEnabled(true);
		}
	}

	BatteryPictogram->setPixmap(*pixmap);
	kdDebugFuncOut(trace);
}

/*!
 * \b TQT_SLOT to set up the Processor/CPU progress bar widgets.
 */
void detaileddialog::setPowerConsumption() {
	kdDebugFuncIn(trace);

	// refresh battery collection
	primaryBatteries = hwinfo->getPrimaryBatteries();
	int rate = primaryBatteries->getCurrentRate();

	if (rate > 0 && !primaryBatteries->getChargeLevelUnit().isEmpty()) {	

		TQString _val;
		_val.setNum(rate);
		_val += " " + primaryBatteries->getChargeLevelUnit().remove('h');

		tl_powerConsValue->setText(_val);

		if (!tl_powerConsDesc->isShown()) {
			tl_powerConsDesc->show();
			tl_powerConsValue->show();
		}
	} else {
		if (tl_powerConsDesc->isShown()) {
			tl_powerConsDesc->hide();
			tl_powerConsValue->hide();
		}
	}

	kdDebugFuncOut(trace);
}

/*!
 * \b TQT_SLOT to set up the Processor/CPU progress bar widgets.
 */
void detaileddialog::setProcessor() {
	kdDebugFuncIn(trace);

	cpuInfo->checkCPUSpeed();

	for (int i=0; i < numOfCPUs; i++) {
		kdDebug() << "ID: " << i << "(" << cpuInfo->cpufreq_speed.count()
			  << ") cur_freq: " << cpuInfo->cpufreq_speed[i] << " max_freq: "
			  << cpuInfo->cpufreq_max_speed[i] << endl; 

		//ProcessorPBar[i]->setTextEnabled(true);
		if (cpuInfo->cpufreq_speed[i] > 0) {
			// CPU/Core is back from offline
			if(ProcessorPBar[i]->progress() == 0)
				cpuInfo->getCPUMaxSpeed();

			if(ProcessorPBar[i]->progress() != cpuInfo->cpufreq_speed[i]) {
				// get max cpu freq and set it to the max of the progressbar
				int maxfreq = cpuInfo->cpufreq_max_speed[i];
				ProcessorPBar[i]->setTotalSteps(maxfreq);
	
				// display  1400 MHz instead of 1400%
				ProcessorPBar[i]->setFormat(i18n("%v MHz"));
				ProcessorPBar[i]->setProgress(cpuInfo->cpufreq_speed[i]);
				ProcessorPBar[i]->setEnabled(true);
			}
		} else {
			ProcessorPBar[i]->setFormat(i18n("deactivated"));
			ProcessorPBar[i]->setProgress(0);
			ProcessorPBar[i]->setEnabled(false);
		}
	}
	TQTimer::singleShot(333, this, TQT_SLOT(setProcessor()));	
	kdDebugFuncOut(trace);
}

/*!
 * \b TQT_SLOT to set up the Processor/CPU bar widgets for cpu throttling machines.
 */
void detaileddialog::setProcessorThrottling() {
	kdDebugFuncOut(trace);

	bool throttling = cpuInfo->getCPUThrottlingState();
	cpuInfo->checkCPUSpeedThrottling();

	for (int i=0; i < numOfCPUs; i++) { 
		if (throttling)
			kdDebug() << "Throttling CPU : " << i << " - freq: " << cpuInfo->cpufreq_speed[i]
				  << " - throttling state: " << cpuInfo->cpu_throttling[i] << "%" << endl;
		else
			kdDebug() << "CPU - freq: " << cpuInfo->cpufreq_speed[i] << endl;
	
		if (throttling && cpuInfo->cpufreq_speed[i] > 0 && cpuInfo->cpu_throttling[i] >= 0) {
			// get max cpu freq and set it to the max of the progressbar
			ProcessorPBar[i]->setTotalSteps(100);
			TQString ProgressString = TQString("%1% (%2 MHz)").arg(100 - cpuInfo->cpu_throttling[i]).arg(cpuInfo->cpufreq_speed[i]);
			ProcessorPBar[i]->setFormat(i18n(ProgressString.ascii()));
			ProcessorPBar[i]->setProgress(100 - cpuInfo->cpu_throttling[i]);
			ProcessorPBar[i]->setEnabled(true);
		} else if (cpuInfo->cpufreq_speed[i] < 0) {
			ProcessorPBar[i]->setFormat(i18n("deactivated"));
			ProcessorPBar[i]->setProgress(0);
			ProcessorPBar[i]->setEnabled(false);
		} else {
			ProcessorPBar[i]->setTotalSteps(cpuInfo->cpufreq_speed[i]);
			ProcessorPBar[i]->setFormat(i18n("%v MHz"));
			ProcessorPBar[i]->setProgress(cpuInfo->cpufreq_speed[i]);
			ProcessorPBar[i]->setEnabled(true);
		}
	}

	if (throttling || numOfCPUs > 1) {
		// currently there are no events we can use to get actual data
		// so we recheck data ever 2 secs to register changes in the 
		// throttling state and if a CPU/core online state change
		TQTimer::singleShot(2000, this, TQT_SLOT(setProcessorThrottling()));
	}

	kdDebugFuncOut(trace);
}

/*!
 * \b TQT_SLOT to set up the AC status within the Led widget.
 */
void detaileddialog::setAC() {
	kdDebugFuncIn(trace);

	if (hwinfo->getAcAdapter()) {
		LabelACStatus->setText( i18n("plugged in") );
		LedAC->on();
	} else {
		LedAC->off();
		LabelACStatus->setText( i18n("unplugged") );
	}

	setInfos();
	kdDebugFuncOut(trace);
}

/*!
 * \b TQT_SLOT to set all additional informtation as e.g. CPUFrequency policy
 * or current scheme
 */
void detaileddialog::setInfos() {
	kdDebugFuncOut(trace);

	TQString display;
	TQString displayValue;

	if(!config->currentScheme.isEmpty())
		display += i18n("Current Scheme: ") + "\n";
		displayValue += i18n(config->currentScheme.ascii()) + "\n";
		if(config->currentScheme == config->ac_scheme)
			InfoPictogram->setPixmap(SmallIcon("scheme_power", 22));
		else if(config->currentScheme == config->battery_scheme)
			InfoPictogram->setPixmap(SmallIcon("scheme_powersave", 22));
		else if(config->currentScheme == "Acoustic")
			InfoPictogram->setPixmap(SmallIcon("scheme_acoustic", 22));
		else if(config->currentScheme == "Presentation")
			InfoPictogram->setPixmap(SmallIcon("scheme_presentation", 22));
		else if(config->currentScheme == "AdvancedPowersave")
			InfoPictogram->setPixmap(SmallIcon("scheme_advanced_powersave", 22));
		else
			InfoPictogram->setPixmap(SmallIcon("kpowersave", 22));

	if(hwinfo->isOnline()) {
		if (hwinfo->supportCPUFreq()) {
			display += i18n("Current CPU Frequency Policy:") + "\n";
			switch (hwinfo->getCurrentCPUFreqPolicy()){
				case PERFORMANCE:
					displayValue += i18n("Performance")  + "\n";
					break;
				case DYNAMIC:
					displayValue += i18n("Dynamic") + "\n";
					break;
				case POWERSAVE:
					displayValue += i18n("Powersave") + "\n";
					break;
				default:
					displayValue += i18n("unknown") + "\n";
					break;
			}
		}

		// refresh battery collection
		primaryBatteries = hwinfo->getPrimaryBatteries();
		int batteries = primaryBatteries->getNumBatteries();
		TQPtrList<Battery> allBatteries = hwinfo->getAllBatteries();

		if (batteries > 0 && primaryBatteries->getNumPresentBatteries() > 0) {

			display += i18n("Battery state:") + "\n";
			switch (primaryBatteries->getBatteryState()){
				case BAT_CRIT:
					displayValue += i18n("Critical") + "\n";
					break;
				case BAT_LOW:
					displayValue += i18n("Low") + "\n";
					break;
				case BAT_WARN:
					displayValue += i18n("Warning") + "\n";
					break;
				case BAT_NORM:
					displayValue += i18n("ok") + "\n";
					break;
				default:
					displayValue += i18n("unknown") + "\n";
					break;
			}
		}
		
		if(hwinfo->supportBrightness()) {
			display += i18n("Set brightness supported:") + "\n";
			displayValue += i18n("yes") + "\n";
		} else {
			display += i18n("Set brightness supported:") + "\n";
			displayValue += i18n("no") + "\n";
		}

		display += i18n("TDE hardware subsystem:");
		displayValue += i18n("active");
	}
	else {
		display += i18n("TDE hardware subsystem:");
		displayValue += i18n("not available");
	}

	if(!display.isEmpty()) 
		InfoLabel->setText(display);
	
	InfoLabelValue->setText(displayValue);
	kdDebugFuncOut(trace);
}

#include "detaileddialog.moc"