//
// C++ Implementation: global
//
// Description:
//
//
// Author: Paulo Moura Guedes <moura@kdewebdev.org>, (C) 2004
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "global.h"

#include <tqstring.h>
#include <tqtimer.h>

#include <dcopclient.h>
#include <dcopref.h>
#include <kdebug.h>
#include <tdeapplication.h>
#include <kstaticdeleter.h>
#include <kurl.h>
#include <kprocess.h>

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


Global* Global::m_self_ = 0;
static KStaticDeleter<Global> staticDeleter;


Global* Global::self()
{
    if (!m_self_)
    {
        staticDeleter.setObject(m_self_, new Global());
    }

    return m_self_;
}

Global::Global(TQObject *parent, const char *name)
        : TQObject(parent, name), loop_started_(false)
{
    m_self_ = this;
    dcop_client_ = kapp->dcopClient();
}

Global::~Global()
{
    if(m_self_ == this)
        staticDeleter.setObject(m_self_, 0, false);
}

bool Global::isKLinkStatusEmbeddedInQuanta()
{
    TQCString app_id = "quanta-" + TQCString().setNum(getpid());
    return self()->dcop_client_->isApplicationRegistered(app_id);
}

bool Global::isQuantaRunningAsUnique()
{
    return self()->dcop_client_->isApplicationRegistered("quanta");
}

bool Global::isQuantaAvailableViaDCOP()
{
    if(isQuantaRunningAsUnique() || isKLinkStatusEmbeddedInQuanta())
        return true;

    else
    {
        self()->execCommand("ps h -o pid -C quanta -C quanta_be");
        TQStringList ps_list = TQStringList::split("\n", self()->script_output_);

        for(uint i = 0; i != ps_list.size(); ++i)
        {
            ps_list[i] = ps_list[i].stripWhiteSpace ();
            if(self()->dcop_client_->isApplicationRegistered("quanta-" + ps_list[i].local8Bit()))
            {
                //kdDebug(23100) << "Application registered!" << endl;
                return true;
            }
        }
        return false;
    }
}

TQCString Global::quantaDCOPAppId()
{
    DCOPClient* client = kapp->dcopClient();
    TQCString app_id;

    if(client->isApplicationRegistered("quanta")) // quanta is unnique application
        app_id = "quanta";

    else if(self()->isKLinkStatusEmbeddedInQuanta()) // klinkstatus is running as a part inside quanta
    {
        TQCString app = "quanta-";
        TQCString pid = TQCString().setNum(getpid());
        app_id = app + pid;
    }

    else
    {
        self()->execCommand("ps h -o pid -C quanta -C quanta_be");
        TQStringList ps_list = TQStringList::split("\n", self()->script_output_);

        for(uint i = 0; i != ps_list.size(); ++i)
        {
            ps_list[i] = ps_list[i].stripWhiteSpace ();
            if(self()->dcop_client_->isApplicationRegistered("quanta-" + ps_list[i].local8Bit()))
                app_id = "quanta-" + ps_list[i].utf8();
        }
    }

    if(self()->dcop_client_->isApplicationRegistered(app_id))
        return app_id;
    else
    {
        kdError(23100) << "You didn't check if Global::isQuantaAvailableViaDCOP!" << endl;
        return "";
    }
}

KURL Global::urlWithQuantaPreviewPrefix(KURL const& url)
{
    Q_ASSERT(isKLinkStatusEmbeddedInQuanta());

    DCOPRef quanta(Global::quantaDCOPAppId(),"WindowManagerIf");
    TQString string_url_with_prefix = quanta.call("urlWithPreviewPrefix", url.url());
    //kdDebug(23100) << "string_url_with_prefix: " << string_url_with_prefix << endl;

    return KURL(string_url_with_prefix);
}

void Global::openQuanta(TQStringList const& args)
{
    TQString command(args.join(" "));
    Global::execCommand("quanta " + command);    
}

void Global::execCommand(TQString const& command)
{

    //We create a TDEProcess that executes the "ps" *nix command to get the PIDs of the
    //other instances of quanta actually running
    self()->process_PS_ = new TDEProcess();
    *(self()->process_PS_) << TQStringList::split(" ",command);

    connect( self()->process_PS_, TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)),
             self(), TQ_SLOT(slotGetScriptOutput(TDEProcess*,char*,int)));
    connect( self()->process_PS_, TQ_SIGNAL(receivedStderr(TDEProcess*,char*,int)),
             self(), TQ_SLOT(slotGetScriptError(TDEProcess*,char*,int)));
    connect( self()->process_PS_, TQ_SIGNAL(processExited(TDEProcess*)),
             self(), TQ_SLOT(slotProcessExited(TDEProcess*)));

    //if TDEProcess fails I think a message box is needed... I will fix it
    if (!self()->process_PS_->start(TDEProcess::NotifyOnExit,TDEProcess::All))
        kdError() << "Failed to query for running KLinkStatus instances!" << endl;
    //TODO: Replace the above error with a real messagebox after the message freeze is over
    else
    {
        //To avoid lock-ups, start a timer.
        TQTimer* timer = new TQTimer(self());
        connect(timer, TQ_SIGNAL(timeout()),
                self(), TQ_SLOT(slotProcessTimeout()));
        timer->start(120*1000, true);
        self()->loop_started_ = true;
        kapp->enter_loop();
        delete timer;
    }
}

void Global::slotGetScriptOutput(TDEProcess* /*process*/, char* buf, int buflen)
{
    TQCString tmp( buf, buflen + 1 );
    script_output_ = TQString();
    script_output_ = TQString::fromLocal8Bit(tmp).remove(" ");
}

void Global::slotGetScriptError(TDEProcess*, char* buf, int buflen)
{
    //TODO: Implement some error handling?
    Q_UNUSED(buf);
    Q_UNUSED(buflen);
}

void Global::slotProcessExited(TDEProcess*)
{
    slotProcessTimeout();
}

void Global::slotProcessTimeout()
{
    if (loop_started_)
    {
        kapp->exit_loop();
        loop_started_ = false;
    }
}


#include "global.moc"
