/* -*- C++ -*-

   This file implements the KVaio class.

   $ Author: Mirko Boehm $
   $ Copyright: (C) 1996-2003, Mirko Boehm $
   $ Contact: mirko@kde.org
         http://www.kde.org
         http://www.hackerbuero.org $
   $ License: LGPL with the following explicit clarification:
         This code may be linked against any version of the Qt toolkit
         from Troll Tech, Norway. $

   $Id: kvaio.cpp 340218 2004-08-23 20:57:14Z kloecker $

   * Portions of this code are
   * (C) 2001-2002 Stelian Pop <stelian@popies.net> and
   * (C) 2001-2002 Alcove <www.alcove.com>.
   * Thanks to Stelian for the implementation of the sonypi driver.
*/

#include <kconfig.h>

#include "kvaio.h"

#include <qlabel.h>
#include <qcstring.h>
#include <qevent.h>
#include <qdatastream.h>
#include <kmainwindow.h>
#include <klocale.h>
#include <kdebug.h>
#include <kdialogbase.h>
#include <dcopclient.h>
#include <kapplication.h>

extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <getopt.h>
#include <errno.h>

#include "./sonypi.h"
}


KVaio::KVaio(QObject *parent, const char* name)
    : QObject(parent, name),
      mDisp(0),
      mTimer (new QTimer (this) )
{
    mDriver = new KVaioDriverInterface(this);

    if(!mDriver->connectToDriver())
    {
        delete mDriver; mDriver = 0L;
        kdDebug() << "KVaio: Cannot connect to driver." << endl;
    } else {
        kdDebug() << "KVaio: Connected to SonyPI driver." << endl;
        connect(mDriver, SIGNAL(vaioEvent(int)), SLOT(slotVaioEvent(int)));
	connect (mTimer, SIGNAL (timeout ()), SLOT (slotTimeout() ) );
	mTimer->start (10000, true);
    }

    mDisp = XOpenDisplay(NULL);
    if(!mDisp)
    {
        kdDebug() << "KVaio ctor: Failed to open display. Very strange."
		  << endl;
    }

    if(!mClient.attach())
    {
       kdDebug() << "KVaio ctor: cannot attach to DCOP server." << endl;
    }

    KConfig config("kmilodrc");

    loadConfiguration(&config);
}

KVaio::~KVaio()
{
    kdDebug() << "KVaio dtor: shutting down." << endl;
    if(mDriver!=0)
    {
        mDriver->disconnectFromDriver();
    }
    if(mClient.isAttached())
    {
        mClient.detach();
    }
}

void KVaio::slotVaioEvent(int event)
{
    QString text;
    QTextStream stream(text, IO_WriteOnly);

    switch(event)
    {
//    case SONYPI_EVENT_FNKEY_F3:
//        break;
//    case SONYPI_EVENT_FNKEY_F5:
//        showBrightnessDialog();
//        break;
	case SONYPI_EVENT_MEMORYSTICK_INSERT:
	    showTextMsg( i18n ("Memory Stick inserted") );
	    break;
	case SONYPI_EVENT_MEMORYSTICK_EJECT:
	    showTextMsg( i18n ("Memory Stick ejected") );
	    break;
	case SONYPI_EVENT_BACK_PRESSED:
	    if (mShowPowerStatusOnBackButton)
	    {
		showBatteryStatus (true);
	    }
	    break;
	default:
	    stream << i18n("Unhandled event: ") << event;
	    if(mReportUnknownEvents) showTextMsg(text);
	    kdDebug() << "KVaio::slotVaioEvent: event not handled."
		      << endl;
    }
}

bool KVaio::showTextMsg(const QString& msg)
{
    if(isKMiloDAvailable())
    {
        QByteArray data, replyData;
        QDataStream arg(data, IO_WriteOnly);
        QCString replyType;

        arg << msg;
        if (!mClient.call("kded", "kmilod", "displayText(QString,QPixmap)",
                         data, replyType, replyData))
        {
            kdDebug() << "KVaio::showTextMsg: there was some error using DCOP."
		      << endl;
            return false;
        } else {
            return true;
        }
    } else {
        return false;
    }
}

bool KVaio::showProgressMsg(const QString& msg, int value)
{
    if(isKMiloDAvailable())
    {
        QByteArray data, replyData;
        QDataStream arg(data, IO_WriteOnly);
        QCString replyType;

        arg << msg << value;
        if (!mClient.call("kded", "kmilod", "displayProgress(QString,int,QPixmap)",
                         data, replyType, replyData))
        {
            kdDebug() << "KVaio::showProgressMsg: there was some error "
		      << "using DCOP." << endl;
            return false;
        } else {
            return true;
        }
    } else {
        return false;
    }
}

bool KVaio::isKMiloDAvailable()
{
    if(mClient.isAttached())
    {
        // kdDebug() << "KVaio::showTextMsg: attached to DCOP server." << endl;
        if(mClient.isApplicationRegistered("kded"))
        {
            QCStringList objects;

            // kdDebug() << "KVaio::showTextMsg: kded is registered at dcop server."
            //           << endl;
            objects = mClient.remoteObjects("kded");
            if(objects.contains("kmilod"))
            {
                // kdDebug() << "KVaio::showTextMsg: kmilod is available at kded."
                //           << endl;
                return true;
            } else {
                kdDebug() << "KVaio::isKMiloDAvailable: "
                          << "kmilod is NOT available at kded." << endl;
                return false;
            }
        } else {
            kdDebug() << "KVaio::isKMiloDAvailable: "
                      << "kded is NOT registered at dcop server." << endl;
            return false;
        }
    } else {
        kdDebug() << "KVaio::isKMiloDAvailable: "
                  << "kded is NOT registered at dcop server." << endl;
        return false;
    }
}

void KVaio::loadConfiguration(KConfig *k)
{
    k->setGroup("KVaio");

    mReportUnknownEvents =
	k->readBoolEntry("Report_Unknown_Events", false);
    mReportPowerStatus =
	k->readBoolEntry("PeriodicallyReportPowerStatus", false);
    mShowPowerStatusOnBackButton =
	k->readBoolEntry("PowerStatusOnBackButton", true);

    kdDebug() << "KVaio::loadConfiguration: " << endl
              << "       mReportUnknownEvents:      "
	      << mReportUnknownEvents << endl
	      << "       mReportPowerStatus:        "
	      << mReportPowerStatus << endl
	      << "mShowPowerStatusOnBackButton:     "
	      << mShowPowerStatusOnBackButton << endl;
}

const KVaioDriverInterface* KVaio::driver()
{
    return mDriver;
}

void KVaio::slotTimeout ()
{
    showBatteryStatus ();
    mTimer->start (4000, true);
}

bool KVaio::showBatteryStatus ( bool force )
{
    static bool acConnectedCache  = false;
    static int previousChargeCache = -1;
    bool bat1Avail = false, bat2Avail = false, acConnected = false;
    int bat1Remaining = 0, bat1Max = 0, bat2Remaining = 0, bat2Max = 0;
    bool displayBatteryMsg = false;
    bool displayACStatus = false;

    QString text, acMsg;
    QTextStream stream(text, IO_WriteOnly);

    // -----
    // only display on startup if mReportPowerStatus is true:
    if (mReportPowerStatus==false || !force)
    {
        return true;
    }

    // query all necessary information:
    if(mDriver->getBatteryStatus(bat1Avail, bat1Remaining, bat1Max,
                                 bat2Avail, bat2Remaining, bat2Max,
                                 acConnected) );

    int remaining;
    if ( bat1Avail || bat2Avail )
        remaining = (int)(100.0*(bat1Remaining+bat2Remaining)
                               / (bat1Max+bat2Max));
    else
        remaining = -1; // no battery available

    if (acConnectedCache != acConnected || force)
    {
	displayACStatus = true;
	acConnectedCache = acConnected;
    }

    displayBatteryMsg = ( previousChargeCache * 100 / remaining > 1000 )
	|| ( previousChargeCache * 100 / remaining > 200 && remaining < 10 )
	|| force;


    if (displayBatteryMsg)
    {
	previousChargeCache = remaining;
    }

    // ----- prepare text messages
    if (displayACStatus || displayBatteryMsg)
    {

	if (displayACStatus)
	{
	    acMsg = acConnected ? i18n ("AC Connected") : i18n ("AC Disconnected");
	}

	switch (remaining)
	{
	    case 100:
		stream << i18n("Battery is Fully Charged. ");
		break;
	    case 5:
	    case 4:
	    case 3:
	    case 2:
	    case 1:
		stream << i18n("Caution: Battery is Almost Empty (%1% remaining).").arg(remaining);
		break;
	    case 0:
		stream << i18n("Alert: Battery is Empty!");
		break;
            case -1:
                stream << i18n("No Battery Inserted.");
                break;
	    default:
		stream << i18n("Remaining Battery Capacity: %1%").arg( remaining );
	};

	// show a message if the battery status changed by more then 10% or on startup
	if (displayACStatus)
	{
	    stream << endl << acMsg;
	}

	return showTextMsg (text);
    } else {
	return true;
    }
}


#include "kvaio.moc"
