/*
   This file is part of the KDE project

   Copyright (c) 2003 Willi Richert <w.richert@gmx.net>
   Pretty much ripped off from :
	 George Staikos <staikos@kde.org> :)

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.

*/

#include <kgenericfactory.h>
#include <kdebug.h>
#include <kprocess.h>
#include <tdeconfig.h>

#include <sys/types.h>
#include <unistd.h>

#include "generic_monitor.h"
#include "kmilointerface.h"
#include <tqmessagebox.h>
#include <tqfile.h>
#include <tqdir.h>
#include <tqtimer.h>

#define CONFIG_FILE "kmilodrc"


using namespace KMilo;

// now the key data (from kkeyserver_x11.h and $TQTDIR/include/tqnamespace.h)
struct ShortcutInfo
{
	const char* name;
	int symbol;
	const char *slot;
};

static const ShortcutInfo shortcuts[] =
{
	{ "Search", TDEShortcut("XF86Search"), TQ_SLOT(launchSearch()) },
	{ "Home Folder", TDEShortcut("XF86MyComputer"), TQ_SLOT(launchHomeFolder()) },
	{ "Mail", TDEShortcut("XF86Mail"), TQ_SLOT(launchMail()) },
	{ "Audio Media", TDEShortcut("XF86AudioMedia"), TQ_SLOT(launchMusic()) },
	{ "Music", TDEShortcut("XF86Music"), TQ_SLOT(launchMusic()) },
	{ "Browser", TDEShortcut("XF86WWW"), TQ_SLOT(launchBrowser()) },
	{ "Calculator", TDEShortcut("XF86Calculator"), TQ_SLOT(launchCalculator()) },
	{ "Terminal", TDEShortcut("XF86Terminal"), TQ_SLOT(launchTerminal()) },
	{ "Eject", TDEShortcut("XF86Eject"), TQ_SLOT(eject()) },
	{ "Help", TDEShortcut("XF86Launch0"), TQ_SLOT(launchHelp()) },
	{ "Light Bulb", TDEShortcut("XF86LightBulb"), TQ_SLOT(lightBulb()) },
	{ "Battery", TDEShortcut("XF86LaunchB"), TQ_SLOT(pmBattery()) },
	{ "FastVolumeUp", TQt::Key_VolumeUp, TQ_SLOT(fastVolumeUp()) },
	{ "FastVolumeDown", TQt::Key_VolumeDown, TQ_SLOT(fastVolumeDown()) },
	{ "SlowVolumeUp", TQt::CTRL+TQt::Key_VolumeUp, TQ_SLOT(slowVolumeUp()) },
	{ "SlowVolumeDown", TQt::CTRL+TQt::Key_VolumeDown, TQ_SLOT(slowVolumeDown()) },
	{ "Mute", TDEShortcut("XF86AudioMute"), TQ_SLOT(toggleMute()) },
	{ "BrightnessUp", TDEShortcut("XF86MonBrightnessUp"), TQ_SLOT(brightnessUp()) },
	{ "BrightnessDown", TDEShortcut("XF86MonBrightnessDown"), TQ_SLOT(brightnessDown()) },
	{ "BrightnessSlowUp", TDEShortcut("Ctrl+XF86MonBrightnessUp"), TQ_SLOT(brightnessSlowUp()) },
	{ "BrightnessSlowDown", TDEShortcut("Ctrl+XF86MonBrightnessDown"), TQ_SLOT(brightnessSlowDown()) }
};

GenericMonitor::GenericMonitor(TQObject *parent, const char *name, const TQStringList& args)
: Monitor(parent, name, args), kmixClient(NULL), kmixWindow(NULL), tdepowersave(NULL),
  m_progress(0), m_displayType(Monitor::None)
{
	_poll = false;
}

GenericMonitor::~GenericMonitor()
{
	if (ga)
	{
		int len = (int)sizeof(shortcuts)/sizeof(ShortcutInfo);
		for (int i = 0; i < len; i++)
		{
			ga->remove(shortcuts[i].name);
		}
		ga->updateConnections();
		delete ga;
	}
}

bool GenericMonitor::init()
{
	config = new TDEConfig(CONFIG_FILE);
	reconfigure(config);

	if(!m_enabled)
		return false; // exit early if we are not supposed to run


	ga = new TDEGlobalAccel(this, "miloGenericAccel");

	ShortcutInfo si;
	int len = (int)sizeof(shortcuts)/sizeof(ShortcutInfo);
	for (int i = 0; i < len; i++) {
		si = shortcuts[i];

		ga->insert(si.name, TQString(), TQString(),
							 si.symbol, si.symbol,
							 this,
							 si.slot, false);
	}

	ga->readSettings();
	ga->updateConnections();

	kmixClient = new DCOPRef("kmix", "kmix");
	kmixWindow = new DCOPRef("kmix", "kmix-mainwindow#1");
	tdepowersave = new DCOPRef("tdepowersave", "tdepowersaveIface");

	return true;
}

void GenericMonitor::reconfigure(TDEConfig *config)
{
	config->setGroup("generic monitor");
	m_volumeStepFast = config->readNumEntry("volumeStepFast", 10);
	m_volumeStepSlow = config->readNumEntry("volumeStepSlow", 1);
	m_enabled = config->readBoolEntry("enabled", true);
}

bool GenericMonitor::retrieveVolume(int &volume)
{
	DCOPReply reply = kmixClient->call("volume");
	if (reply.isValid())
	{
		volume = reply;
		return true;
	}

	// maybe the error occurred because kmix wasn't running. Try to start it
	_interface->displayText(i18n("Starting KMix..."));
	if (kapp->startServiceByDesktopName("kmix") == 0)
	{
		// trying again
		reply = kmixClient->call("volume");
		if (reply.isValid())
		{
			volume = reply;
			kmixWindow->send("hide");
			return true;
		}
	}
	kdDebug() << "KMilo: GenericMonitor could not access kmix via dcop"	<< endl;
	_interface->displayText(i18n("It seems that KMix is not running."));
	return false;
}

void GenericMonitor::volumeChange(int direction, int percentage)
{
	int volume;
	if (!direction || !retrieveVolume(volume))
	{
		return;
	}

	if (direction > 0)
	{
		volume += percentage;
		if (volume > 100)
		{
			volume = 100;
		}
	}
	else
	{
		volume -= percentage;
		if (volume < 0)
		{
			volume = 0;
		}
	}

	_interface->displayProgress(i18n("Volume"), volume);
	kmixClient->send("setVolume", volume);

	// if mute then unmute
	bool muted = false;
	if (retrieveMute(muted) && muted)
	{
		kmixClient->send("setMute", false);
	}
}

void GenericMonitor::slowVolumeUp()   { volumeChange( 1, m_volumeStepSlow); }
void GenericMonitor::slowVolumeDown() { volumeChange(-1, m_volumeStepSlow); }
void GenericMonitor::fastVolumeUp()   { volumeChange( 1, m_volumeStepFast); }
void GenericMonitor::fastVolumeDown() { volumeChange(-1, m_volumeStepFast); }

bool GenericMonitor::retrieveMute(bool &muted)
{
	DCOPReply reply = kmixClient->call("mute");
	if (reply.isValid())
	{
		muted = reply;
		return true;
	}

	// maybe the error occurred because kmix wasn't running. Try to start it
	_interface->displayText(i18n("Starting KMix..."));
	if (kapp->startServiceByDesktopName("kmix") == 0)
	{
		// trying again
		reply = kmixClient->call("mute");
		if (reply.isValid())
		{
			muted = reply;
			kmixWindow->send("hide");
			return true;
		}
	}
	kdDebug() << "KMilo: GenericMonitor could not access kmix via dcop"	<< endl;
	_interface->displayText(i18n("It seems that KMix is not running."));
	return false;
}

void GenericMonitor::toggleMute()
{
	bool muted = false;
	if (!retrieveMute(muted))
	{
		return;
	}

	muted = !muted;
	TQString muteText;
	if (muted)
	{
		muteText = i18n("System muted");
	}
	else
	{
		muteText = i18n("System unmuted");
	}

	kmixClient->send("setMute", muted);
	_interface->displayText(muteText);
}

void GenericMonitor::brightnessUp()
{
	brightnessChange(1, 10);
}

void GenericMonitor::brightnessDown()
{
	brightnessChange(-1, 10);
}

void GenericMonitor::brightnessSlowUp()
{
	brightnessChange(1, 1);
}

void GenericMonitor::brightnessSlowDown()
{
	brightnessChange(-1, 1);
}

void GenericMonitor::brightnessChange(int direction, int step)
{
	if (!tdepowersave || direction == 0)
	{
		return;
	}

	if (direction > 0)
	{
		tdepowersave->call("do_brightnessUp", step);
	}
	else
	{
		tdepowersave->call("do_brightnessDown", step);
	}
	TQTimer::singleShot(250, this, TQ_SLOT(brightnessValueUpdate()));
}

void GenericMonitor::brightnessValueUpdate()
{
	DCOPReply reply = tdepowersave->call("brightnessGet");
	if (reply.isValid())
	{
		// Display real brightness value. This may differ from the set value
		// on machines with few brightness steps.
		_interface->displayProgress(i18n("Brightness"), (int)reply);
	}
}

int GenericMonitor::progress() const
{
	return m_progress;
}

Monitor::DisplayType GenericMonitor::poll()
{
	return m_displayType;
}

void GenericMonitor::launch(TQString configKey, TQString defaultApplication)
{
	TQString application = config->readEntry(configKey, defaultApplication);
	TDEProcess proc;
	proc << application;
	proc.start(TDEProcess::DontCare);
}

void GenericMonitor::launchMail()
{
	kdDebug() << "launchMail" << endl;
	kapp->invokeMailer("", "", "", "", "", "", "", "");
}

void GenericMonitor::launchBrowser()
{
	kapp->invokeBrowser("");
}

void GenericMonitor::launchSearch()
{
	launch("search", "kfind");
}

void GenericMonitor::launchHomeFolder()
{
	TQString home = TQDir::home().path();
	TDEProcess proc;
	proc << "kfmclient" << "exec" << home;
	proc.start(TDEProcess::DontCare);
}

void GenericMonitor::launchMusic()
{
	launch("search", "amarok");
}

void GenericMonitor::launchCalculator()
{
	launch("search", "speedcrunch");
}

void GenericMonitor::launchTerminal()
{
	launch("search", "konsole");
}

void GenericMonitor::launchHelp()
{
	launch("search", "khelpcenter");
}

void GenericMonitor::eject()
{
	launch("search", "eject");
}

void GenericMonitor::lightBulb()
{
	kdDebug() << "lightBulb()" << endl;
	_interface->displayText("Screen Light");
}

void GenericMonitor::pmBattery()
{
    DCOPRef("guidance*", "power-manager").send("showTip");
}

K_EXPORT_COMPONENT_FACTORY(kmilo_generic, KGenericFactory<GenericMonitor>("kmilo_generic"))

#include "generic_monitor.moc"
