/***************************************************************************
 *   Copyright (C) 2007 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 "nvidiathermalsrc.h"
#include <tqstringlist.h>
#include <tqregexp.h>
#include <tdelocale.h>
#include <kdebug.h>

#ifndef HAVE_NVCONTROL
    #include <kprocio.h>
#else
    #include <tqpaintdevice.h> // for the Device* pointer
    
    // include the NVCtrl include stuff
    #include <X11/Xlib.h>
    #include <fixx11h.h> // needed for TQt, to include X11 header
extern "C" {
    #include <NVCtrlLib.h>
}
#endif

#ifndef HAVE_NVCONTROL
NVidiaThermalSrc::NVidiaThermalSrc(TQWidget* inParent, const TQString& inID, const TQString& inName):
		LabelSource(inParent), mProcess(0) {
#else
NVidiaThermalSrc::NVidiaThermalSrc(TQWidget* inParent, const TQString& inID, const TQString& inName, unsigned int attrib):
        LabelSource(inParent), mAttrib(attrib) {
#endif
	mID = inID;
    mName = inName;
	mDescription = i18n("This source is provided by the nVidia GPU card driver tools");

	mRefreshTimer = new TQTimer(this, "default refresh handler" );
	// connect the timer
	connect(mRefreshTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(fetchValue()));
	connect(this, TQ_SIGNAL(enabledChanged(bool, Source*)), this, TQ_SLOT(enable(bool)));
}

NVidiaThermalSrc::~NVidiaThermalSrc(){
#ifndef HAVE_NVCONTROL
	delete mProcess;
#endif
}

std::list<Source*>NVidiaThermalSrc::createInstances(TQWidget* inParent){
	std::list<Source*> list;
#ifndef HAVE_NVCONTROL 
	// see if the path contains nvidia-settings. if yes, 
	// execute it and look for the query type "GPUCoreTemp"
	// and "GPUAmbientTemp" and create two instances for each
	// of them
	// start nvidia-settings, if available and wait for it to exit.
	KProcIO proc;
    proc << "nvidia-settings"
	     << "-n" // don't load config
	     << "-q" << "GPUCoreTemp"
	     << "-q" << "GPUAmbientTemp";
	if(!proc.start(TDEProcess::Block))
		return list;
	
	// now see what it printed...
    TQString ln;
    TQString pout;
    while(proc.readln(ln) != -1)
        pout+= ln + '\n';

	if(pout.contains("Attribute 'GPUCoreTemp'"))
		list.push_back(new NVidiaThermalSrc(inParent, "GPUCoreTemp", "NVidiaCore"));
	if(pout.contains("Attribute 'GPUAmbientTemp'"))
		list.push_back(new NVidiaThermalSrc(inParent, "GPUAmbientTemp", "NVidiaAmbient"));
#else
    int evt_base = 0, err_base = 0, temp;
    Display * dpy = TQPaintDevice::x11AppDisplay();
    
    // do we have the XNVCtrl extension loaded?
    if(!XNVCTRLQueryExtension(dpy, &evt_base, &err_base))
        return list;
    
    // core temp support?
    if(XNVCTRLQueryAttribute (dpy, 0, 0, 
       NV_CTRL_GPU_CORE_TEMPERATURE, &temp)
      )
         list.push_back(new NVidiaThermalSrc(inParent, "GPUCoreTemp", "NVidiaCore",
                        NV_CTRL_GPU_CORE_TEMPERATURE));
    
    // ambient temp support?
    if(XNVCTRLQueryAttribute (dpy, 0, 0, 
       NV_CTRL_AMBIENT_TEMPERATURE, &temp)
      )
         list.push_back(new NVidiaThermalSrc(inParent, "GPUAmbientTemp", "NVidiaAmbient",
                        NV_CTRL_AMBIENT_TEMPERATURE));
#endif
	return list;
}

void NVidiaThermalSrc::enable(bool inEnable){
	if(inEnable && !mRefreshTimer->isActive()){ // start the timer
		fetchValue();
		mRefreshTimer->start(3000);
	}else if(!inEnable && mRefreshTimer->isActive()) // stops the timer
		mRefreshTimer->stop();
}


void NVidiaThermalSrc::evaluateStdout(){
#ifndef HAVE_NVCONTROL
		TQString val = i18n("n/a");
        
        // now see what it printed...
        TQString ln;
        TQString pout;
        while(mProcess->readln(ln) != -1)
            pout+= ln + '\n';
		TQRegExp regexp("Attribute\\s'" + mID + "'.*(\\d+)\\.");
		if(regexp.search(pout) != -1)
		    val = formatTemperature(regexp.cap(1));
		mValue = val;
		emit valueUpdated(mValue); // calls updateLabel(mValue) of LabelSource
        
        // delete the object, to be ready for a new run
        delete mProcess;
        mProcess = 0;
#endif
}

#ifndef HAVE_NVCONTROL
void NVidiaThermalSrc::createProcess() {
    mProcess = new KProcIO;
    connect(mProcess, TQ_SIGNAL(processExited(TDEProcess*)), this, TQ_SLOT(evaluateStdout()));
    *mProcess << "nvidia-settings" << "-n"
                << "-q" << mID;
}
#endif

TQString NVidiaThermalSrc::fetchValue(){
#ifndef HAVE_NVCONTROL
	if(!mProcess) {
        createProcess();
		if(!mProcess->start()) {
			mValue = "n/a";
            delete mProcess;
            mProcess = 0;
        }
    }
	return getValue();
#else
    int temp;
    Display * dpy = TQPaintDevice::x11AppDisplay();
    if(XNVCTRLQueryAttribute (dpy, 0, 0, mAttrib, &temp))
        mValue = formatTemperature(TQString::number(temp));
    else
        mValue = "n/a";
    emit valueUpdated(mValue); // calls updateLabel(mValue) of LabelSource
    return mValue;
#endif
}
#include "nvidiathermalsrc.moc"
