/***************************************************************************
 *   Copyright (C) 2006 by Ken Werner                                      *
 *   ken.werner@web.de                                                     *
 *                                                                         *
 *   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 Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
 ***************************************************************************/

#include <list>

// TQt
#include <tqlabel.h>
#include <tqfile.h>
#include <tqspinbox.h>
#include <tqcombobox.h>
#include <tqtextedit.h>
#include <tqtimer.h>
#include <tqcursor.h>
#include <tdelistview.h>
#include <tqlistview.h> 
#include <tqwidgetstack.h> 

// KDE
#include <tdemessagebox.h>
#include <tdeaboutapplication.h>
#include <tdepopupmenu.h>
#include <kstdaction.h>
#include <tdeaction.h>
#include <tdeactioncollection.h>
#include <tdeactionclasses.h>
#include <tdeapplication.h>
#include <kdialogbase.h>
#include <tdeconfig.h>
//#include <tdeglobal.h>
#include <kiconloader.h>
#include <tdelocale.h>

// Kima
#include "kima.h"
#include "flowlayout.h"
#include "sourcelistitem.h"
#include "prefs.h"

// Kima Soures
#include "sources/acpithermalsrc.h"
#include "sources/ibmacpithermalsrc.h"
#include "sources/ibmacpifansrc.h"
#include "sources/ibmhdaps.h"
#include "sources/omnibookthermalsrc.h"
#include "sources/ibookg4thermalsrc.h"
#include "sources/hwmonthermalsrc.h"
#include "sources/hwmonfansrc.h"
#include "sources/sysfreqsrc.h"
#include "sources/cpuinfofreqsrc.h"
#include "sources/i8ksrc.h"
#include "sources/nvidiathermalsrc.h"
#include "sources/hddtempsrc.h"
#include "sources/uptimesrc.h"
#include "sources/batterysrc.h"

//#include "kdebug.h"

extern "C" {
TDE_EXPORT	KPanelApplet* init( TQWidget* inParent, const TQString& inConfigFile) {
		TDEGlobal::locale()->insertCatalogue("kima");
		return new Kima(inConfigFile, KPanelApplet::Normal,
		                      //KPanelApplet::About | KPanelApplet::Help | KPanelApplet::Preferences,
		                      KPanelApplet::About | KPanelApplet::Preferences,
		                      inParent, "kima");
	}
}

Kima::Kima(const TQString& inConfigFile, Type inType, int inActions, TQWidget* inParent, const char* inName):
		KPanelApplet(inConfigFile, inType, inActions, inParent, inName),
		TQToolTip(this),
		mCachedWFH(0),
		mCachedHeight(0),
		mDraggedSourceItem(NULL){
	mAboutDialog = 0; // aboutData is created in the about() method
	mPrefsDlg = 0; // the prefs dialog is created in the preferences() method
	mPrefs = 0; // the prefs ui is created in the preferences() method

	// Get the current application configuration handle
	mTDEConfig = config();
	mTDEConfig->setGroup("Kima");

	// automatically delete pointers
	mSources.setAutoDelete(true);

	// create layout
	mLayout = new FlowLayout(this, orientation() );
	mLayout->setSpacing(8);


	// add the sources into the sources list
	addSources(NVidiaThermalSrc::createInstances(this));
    addSources(ACPIThermalSrc::createInstances(this));
	addSources(IBMACPIThermalSrc::createInstances(this));
	addSources(IBMACPIFanSrc::createInstances(this));
	addSources(IBMHDAPSSrc::createInstances(this));
	addSources(OmnibookThermalSrc::createInstances(this));
	addSources(IbookG4ThermalSrc::createInstances(this));
	addSources(HwMonThermalSrc::createInstances(this));
	addSources(SysFreqSrc::createInstances(this));
	addSources(CpuinfoFreqSrc::createInstances(this));
	addSources(I8kSrc::createInstances(this));
	addSources(HDDTempSrc::createInstances(this));
	addSources(HwMonFanSrc::createInstances(this));
	addSources(UptimeSrc::createInstances(this));
	addSources(BatterySrc::createInstances(this));
	

	TQPtrListIterator<Source> itSync(mSources);
	Source* source;
	while((source = itSync.current()) != 0){
		++itSync;
        registerSource(source);
	}
	mLayout->updatePositions(mTDEConfig);

	// create the menu
	mMenu = new TDEPopupMenu(this);
	mMenu->insertTitle(SmallIcon("hwinfo"), i18n("Kima"));

	if (mCpufreqd.enabled()) {
		mMenu->insertItem(i18n("&Performance Profiles"), mCpufreqd.menu());
	}

	TDEActionCollection* actionCollection = new TDEActionCollection(this, "actionCollection", kapp);

	TDEAction* action = KStdAction::preferences(this, TQ_SLOT(preferences()), actionCollection);
	action->setText(i18n("&Preferences"));
	action->plug(mMenu);

	action = KStdAction::aboutApp(this, TQ_SLOT(about()), actionCollection);
	action->setText(i18n("&About Kima"));
	action->plug(mMenu);

	//menu->insertSeparator();
	//KStdAction::quit( kapp, TQ_SLOT( quit() ), actionCollection )->plug( menu );
}

Kima::~Kima() {
	// super class deletes the widgets
}

void Kima::addSources(const std::list<Source*>& inList){
	for(std::list<Source*>::const_iterator it = inList.begin(); it != inList.end(); ++it){
		mSources.append(*it);
	}
}

void Kima::displaySource(bool inDisplay, Source* inSource){
	if(inDisplay){
		//kdDebug() << "Kima::displaySource mLayout->add: " << inSource->getName() << endl;
		mLayout->addSource(inSource); // add the source
		//kdDebug() << "Pos of " << inSource->getID() << ": " << inSource->getPosition() << endl;
	}else{
		//kdDebug() << "Kima::displaySource mLayout->remove: " << inSource->getName() << endl;
		mLayout->remove(inSource->getWidget());
	}
}

void Kima::about() {
	if(!mAboutDialog){
		TDEAboutData* aboutData = new TDEAboutData("libkima",
			"Kima",
			"0.7.3.2",
			I18N_NOOP("Kicker monitoring applet.\n\n"
				"This applet monitors various temperature, frequency and fan sources.\n"
				"Make sure you have enabled a supported kernel module.\n"),
			TDEAboutData::License_GPL,
			"(c) 2004-2007, Ken Werner");
		aboutData->addAuthor("Ken Werner", 0, "ken.werner@web.de");
		aboutData->addAuthor("Johannes Schaub", 0, "schaub-johannes@web.de");
		aboutData->addAuthor("Valentine Sinitsyn", I18N_NOOP("cpufreqd control module"), "e_val@inbox.ru");
		aboutData->addCredit("Franziska Simmank");
		aboutData->addCredit("Manfred Paul");
		aboutData->addCredit("Rainer Dorsch");
		aboutData->addCredit("Flavio Castelli");
		aboutData->addCredit("Jocke Andersson");
		aboutData->addCredit("Raoul Martin");
		aboutData->addCredit("Donnie Bhayangkara");
		aboutData->addCredit("Gonzalo Nemmi");
		aboutData->addCredit("Mariusz Ciesla");
		aboutData->addCredit("Mark Rosenstand");
		aboutData->addCredit("Santiago Bruno");
		aboutData->addCredit("Dark Apostrophe");
		aboutData->addCredit("Sascha Hoogen");
		aboutData->addCredit("Peter Avramucz");
		aboutData->addCredit("Oskar Ellström");
		aboutData->addCredit("Uğur Çetin");
		mAboutDialog = new TDEAboutApplication(aboutData, this, "aboutApp", false);
	}
	mAboutDialog->show();
}

void Kima::help() {
	KMessageBox::information(0, i18n("This is a help box"));
}

void Kima::preferences() {
	//KMessageBox::information(0, i18n("This is a preferences box"));
	if(!mPrefsDlg){
		//create the prefs dialog
		mPrefsDlg = new KDialogBase( this, "prefsDlg", false, i18n("Configuration"), KDialogBase::Ok|KDialogBase::Apply|KDialogBase::Cancel, KDialogBase::Ok, false );
		//create the prefs ui
		mPrefs = new Prefs( mPrefsDlg, "prefsui" ); //the uic generated class

		//setup the dialog
		//mPrefsDlg->setFixedSize(mPrefs->size());
		mPrefsDlg->setMainWidget(mPrefs); //embed the uic generated class into the kde dialog
		connect(mPrefsDlg, TQ_SIGNAL(applyClicked()), this, TQ_SLOT(savePreferences()));
		connect(mPrefsDlg, TQ_SIGNAL(okClicked()), this, TQ_SLOT(savePreferences()));
		connect(mPrefsDlg, TQ_SIGNAL(cancelClicked()), this, TQ_SLOT(cancelPreferences()));

		// create new list items and the widgetStack widgets
		TQPtrListIterator<Source> it(mSources);
		Source* source;
		while((source = it.current()) != 0){
			++it;
			// create the specific source prefs and add them to the widgetStack
			mPrefs->widgetStack->addWidget(source->createPrefs(mPrefs->widgetStack));
			
            // create the SourceListItem to switch and to enable/disable the widgetstack item (the source)
            // and connect the apply/ok signals to the item, so it can change it's text to a potentially
            // new source name.
			SourceListItem * item = new SourceListItem(source, mPrefs->sourceListView, TQCheckListItem::CheckBox);
            connect(mPrefsDlg, TQ_SIGNAL(applyClicked()), item, TQ_SLOT(updateText()));
            connect(mPrefsDlg, TQ_SIGNAL(okClicked()), item, TQ_SLOT(updateText()));
		}		
		
		if(mPrefs->sourceListView->firstChild()){
			mPrefs->sourceListView->setSelected(mPrefs->sourceListView->firstChild(), true);  // select the first list item
			raiseSourcePrefsWidget(mPrefs->sourceListView->firstChild()); // raise that item
		}

		connect(mPrefs->sourceListView, TQ_SIGNAL(selectionChanged(TQListViewItem*)), this, TQ_SLOT(raiseSourcePrefsWidget(TQListViewItem*)));
	}

	// update prefs gui
	TQPtrListIterator<Source> srcIt(mSources);
	Source* source;
	while((source = srcIt.current()) != 0){
		++srcIt;
		source->updatePrefsGUI();
	}

	// update the sourcelist checkbox
	TQPtrList<TQListViewItem> lst;
	TQListViewItemIterator lvIt(mPrefs->sourceListView);
	while(lvIt.current()){
		SourceListItem* sli = static_cast<SourceListItem*>(lvIt.current());
		sli->setOn(sli->getSource()->isEnabled());
		++lvIt;
	}

	//show the dialog
	mPrefsDlg->show();
}

void Kima::raiseSourcePrefsWidget(TQListViewItem* inListViewItem){
	mPrefs->widgetStack->raiseWidget(static_cast<SourceListItem*>(inListViewItem)->getSource()->getPrefs());
}

void Kima::cancelPreferences(){
	// update prefs gui
	TQPtrListIterator<Source> it(mSources);
	Source* source;
	while((source = it.current()) != 0){
		++it;
		source->updatePrefsGUI();
	}
}

void Kima::savePreferences(){
	// save prefs
	TQPtrListIterator<Source> it(mSources);
	Source* source;
	while((source = it.current()) != 0){
		++it;
		source->applyPrefs();
		source->savePrefs(mTDEConfig);
	}
	// save the position of all sources because they might have changed.
	mLayout->updatePositions(mTDEConfig);
	// update the source widgets
	updateSourceWidgets();
	// write config
	mTDEConfig->sync();
	// reset cached witdh for height to force recalculation of the applets width
	mCachedWFH = 0;
}

int Kima::widthForHeight(int inHeight) const{
	//kdDebug() << "widthForHeight: " << height << endl;
	mLayout->setOrientation(TQt::Horizontal);
	if(mCachedHeight != inHeight){
		mCachedHeight = inHeight;
		mCachedWFH = 0;
	}
 	mCachedWFH = TQMAX(mLayout->widthForHeight(inHeight), mCachedWFH);
	return mCachedWFH;
}

int Kima::heightForWidth(int inWidth) const{
	//kdDebug() << "heightForWidth: " << width << endl;
	mLayout->setOrientation(TQt::Vertical);
	return mLayout->heightForWidth(inWidth);
	//return sizeHint().height();
}

void Kima::mousePressEvent(TQMouseEvent* inEvent ){
	if(inEvent->button() == TQt::RightButton){
		mMenu->popup( inEvent->globalPos() );
		if(mDraggedSourceItem)
			mDraggedSourceItem->widget()->unsetCursor(); // unset drag cursor
	}
	else if(inEvent->button() == TQt::LeftButton){
		TQLayoutIterator it = mLayout->iterator();
		while(it.current()){
			TQWidget * c = it.current()->widget();
			if(c->rect().contains(c->mapFromGlobal(inEvent->globalPos()))){
				mDraggedSourceItem = it.current(); // remenber the clicked source
				c->setCursor(TQt::SizeAllCursor);   // set drag cursor
				mDragFactor = (c->rect().height()/2.0) / (double)c->mapFromGlobal(inEvent->globalPos()).y();
				break;
			}
			++it;
		}
	}
}

void Kima::mouseReleaseEvent(TQMouseEvent* inEvent){
	//if(inEvent->button() == TQMouseEvent::LeftButton && mDraggedSourceItem){
	if(mDraggedSourceItem){
		mCachedWFH = 0; // reset cached witdh for height to force recalculation of the applets width
		mDraggedSourceItem->widget()->unsetCursor(); // unset drag cursor
		mDraggedSourceItem = NULL;
	}
}

void Kima::mouseMoveEvent( TQMouseEvent* inEvent ) {
	if(!mDraggedSourceItem)
		return;
	TQLayoutIterator it = mLayout->iterator();
	while(it.current()){
		TQWidget * c = it.current()->widget();
		if(c->rect().contains(c->mapFromGlobal(inEvent->globalPos()))){
			if(it.current() == mDraggedSourceItem)
                		break;
			// we are over a source-widget.
			// move the dragged widget above / below that 
			// widget, depending where the cursor is.
			TQRect crect = c->rect();
			double relPos = c->mapFromGlobal(inEvent->globalPos()).y() * mDragFactor;
			if(mLayout->moveItem(mDraggedSourceItem, it.current(), crect.height()/2.0 > relPos ? FlowLayout::ABOVE : FlowLayout::BELOW)){
				mLayout->updatePositions(mTDEConfig);
				updateGeometry();
				mTDEConfig->sync(); // write config
				updateSourceWidgets();
			}
			break;
		}
		++it;
	}
	// outside kima?
	if(!rect().contains(mapToParent(inEvent->pos())))
		mDraggedSourceItem->widget()->setCursor(TQt::ForbiddenCursor);
	else
		mDraggedSourceItem->widget()->setCursor(TQt::SizeAllCursor);
}

void Kima::paintEvent(TQPaintEvent* inEvent){
	KPanelApplet::paintEvent(inEvent);
	updateSourceWidgets();
}

void Kima::updateSourceWidgets(){
	// repaint the source widgets
	for(Source* source = mSources.first(); source; source = mSources.next())
		if(source->showOnApplet())
			source->getWidget()->update();
}

void Kima::registerSource(Source* source) {
	// then, tell the source to set up its widget
	source->realizeWidget();
	
	// enable transparency
	source->getWidget()->setBackgroundMode(X11ParentRelative);
	
	// load prefs from the configuration
	// this call also emits enabledChanged
	source->loadPrefs(mTDEConfig);
	
	// add the source to the layout if necessary
	displaySource(source->isEnabled() && source->showOnApplet(), source);
	
	// connection to add and remove sources from mLayout
	connect(source, TQ_SIGNAL(displaySource(bool, Source*)), this, TQ_SLOT(displaySource(bool, Source*)));
}

void Kima::maybeTip(const TQPoint& inPos){
	if(!rect().contains(inPos))
		return;
	TQString text = "<b>" + i18n("Sources:") + "</b><br><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">";

	TQPtrListIterator<Source> it(mSources);
	Source* source;
	while((source = it.current()) != 0){
		++it;
		if(source->isEnabled() && source->isToolTipEnabled())
			text.append("<tr><td>" + 
				source->getName() + "</td><td>" +
				source->getValue() + "</td><td>");
	}
	text.append("</table>");
	tip(rect(), text);
}
#include "kima.moc"
