/***************************************************************************
 *   Copyright (C) 2006 by Valentine Sinitsyn                              *
 *   e_val@inbox.ru                                                        *
 *                                                                         *
 *   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 "cpufreqd.h"
#include <tqdir.h>
#include <tqkeysequence.h>
#include <tqstringlist.h>
#include <tdelocale.h>

#define CHUNK_SIZE 4096

/**
 * cpufreqd control module main class
 *@author: Valentine Sinitsyn (Valentine.Sinitsyn@usu.ru)
 *@todo: We assume that cpufreqd is in dynamic mode when applet is started because as for now it has
 * no means to detect mode. This could lead to inconsistency if, ex. applet is restarted after making
 * some changes to cpufreqd state.
 */

CPUFreqd::CPUFreqd() {
	m_menu = new TQPopupMenu();
	TQObject::connect(m_menu, TQT_SIGNAL(aboutToShow()), this, TQT_SLOT(updateMenu()));

	m_dynamic = new TQAction(i18n("Select dynamically"), TQKeySequence(), this);
	TQObject::connect(m_dynamic, TQT_SIGNAL(activated()), this, TQT_SLOT(setDynamic()));
	m_dynamic->setToggleAction(true);
	m_dynamic->setOn(true);

	m_items = new TQActionGroup(this);
	m_items->setExclusive(true);

	m_actions = new TQPtrList<TQAction>();
	m_actions->setAutoDelete(true);

	m_mapper = new TQSignalMapper(this);
	TQObject::connect(m_mapper, TQT_SIGNAL(mapped(int)), this, TQT_SLOT(setProfile(int)));
}

CPUFreqd::~CPUFreqd() {
}

bool CPUFreqd::enabled() const {
	return m_conn.available();
}

TQValueVector<CPUFreqdProfile> & CPUFreqd::getProfiles(bool reconnect) {
	char chunk[CHUNK_SIZE];
	TQString buffer;

	if (!m_profiles.empty())
		m_profiles.clear();

	if (!m_conn.open())
		if (reconnect) {
			m_dynamic->setOn(m_conn.lookup());
			return getProfiles(false);
		} else {
			return m_profiles;
		}
	
	if (!m_conn.write(CMD_LIST_PROFILES, 0))
		return m_profiles;

	int bytes = 0;
	while ( (bytes = m_conn.read(chunk, CHUNK_SIZE - 1)) ) {
		chunk[bytes] = '\0';
		buffer.append(chunk);
	}

	TQStringList profiles = TQStringList::split("\n", buffer);
	for (TQStringList::Iterator it = profiles.begin(); it != profiles.end(); it++)
		m_profiles.push_back( CPUFreqdProfile(*it) );

	m_conn.close();

	return m_profiles;
}

TQPopupMenu* CPUFreqd::menu() {
	return m_menu;
}

void CPUFreqd::updateMenu() {
	TQAction *cur;

	m_menu->clear();
	m_actions->clear();

	getProfiles(true);
	if (!m_profiles.isEmpty()) {
		m_dynamic->addTo(m_menu);
		m_menu->insertSeparator();

		for (unsigned int i = 0; i < m_profiles.count(); i++)
			if (m_profiles[i].isValid()) {
				cur = new TQAction(m_profiles[i].name(), TQKeySequence(), m_items);
				TQObject::connect(cur, TQT_SIGNAL(activated()), m_mapper, TQT_SLOT(map()));
				cur->setToggleAction(true);
				cur->setOn(m_profiles[i].active());

				m_mapper->setMapping(cur, i+1);
				m_actions->append(cur);
			}
		m_items->addTo(m_menu);
	} else {
		int errmsg = m_menu->insertItem(i18n("Can't talk to cpufreqd"), 0, 0);
		m_menu->setItemEnabled(errmsg, false);
	}
}

void CPUFreqd::setManual() {
	setMode(ARG_MANUAL);
	m_dynamic->setOn(false);
}

void CPUFreqd::setDynamic() {
	setMode(ARG_DYNAMIC);
	m_dynamic->setOn(true);
}

void CPUFreqd::setProfile(int id) {
	//@fixme: make it return bool and bail out if it falis
	if (m_dynamic->isOn())
		setManual();

	if (!m_conn.open())
		return;

	m_conn.write(CMD_SET_PROFILE, (uint32_t)id);
	m_conn.close();
}

void CPUFreqd::setMode(uint32_t mode) {
	if (!m_conn.open())
		return;

	m_conn.write(CMD_SET_MODE, mode);
	m_conn.close();
}