/***************************************************************************
 *   Copyright (C) 2005 by Thierry CHARLES   *
 *   thierry@les-charles.net   *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "tprocess.h"

#include <wx/utils.h>
#include <wx/txtstrm.h>

#include "lib_logging.h"

/** défini la ligne de commande a exécuter */
void TProcess::setCommandLine(const wxString & sCommandLine)
{
    if(this->isRunning())
        return;
    this->sCommandLine = sCommandLine;
}

/** défini le répertoire de travail dans lequel le process sera executé */
void TProcess::setWorkingDirectory(const wxString & sWorkingDir)
{
    if(this->isRunning())
        return;
    this->sWorkingDir = sWorkingDir;
}

/** indique si le process est en cours d'exécution */
bool TProcess::isRunning()
{
    if(this->iPID <= 0)
        return false;

    wxKillError error;
    wxKill(this->iPID,wxSIGNONE, &error);
    if(error == wxKILL_NO_PROCESS)
    {
        this->iPID = -1;
        this->iExitCode = -1;
        return false;
    }

    return true;
}

/** démarre le process */
bool TProcess::start()
{
    if(this->isRunning())
        return false;

    this->iPID = -1;
    this->iExitCode = -1;

    wxString sCWD = wxGetCwd();
    if(this->sWorkingDir.length())
        wxSetWorkingDirectory(this->sWorkingDir);
    this->process = new InternalProcess(this);
    this->iPID = wxExecute(this->sCommandLine, wxEXEC_ASYNC | wxEXEC_MAKE_GROUP_LEADER, this->process);
    if(this->sWorkingDir.length())
        wxSetWorkingDirectory(sCWD);
    if(!this->iPID)
    {
        this->iPID = -1;
        delete this->process;
        this->process = NULL;
    }

    return this->isRunning();
}

/** arrete le process */
bool TProcess::stop(bool bForce)
{
    if(!this->isRunning())
        return false;

    bool bRes = wxKill(this->iPID, bForce ? wxSIGKILL : wxSIGTERM, NULL, wxKILL_CHILDREN) == 0;

    return bRes;
}

bool TProcess::isErrorAvailable() const
{
    if(!this->process)
        return this->errorBuffer.length() > 0;
    return this->process->IsErrorAvailable() && this->process->GetErrorStream()->CanRead();
}

bool TProcess::isOutputAvailable() const
{
    if(!this->process)
        return this->outputBuffer.length() > 0;
    return this->process->IsInputAvailable() && this->process->GetInputStream()->CanRead();
}

wxString TProcess::GetErrorData()
{
    if(!this->isErrorAvailable())
        return wxString();

    if(!this->process)
    {
        wxString s = this->errorBuffer;
        this->errorBuffer = wxT("");
        return s;
    }

    wxString sLine;
    while(this->process->GetErrorStream()->CanRead())
        sLine += this->process->GetErrorStream()->GetC();
    return sLine;
}

wxString TProcess::GetOutputData()
{
    if(!this->isOutputAvailable())
        return wxString();

    if(!this->process)
    {
        wxString s = this->outputBuffer;
        this->outputBuffer = wxT("");
        return s;
    }

    wxString sLine;
    while(this->process->GetInputStream()->CanRead())
        sLine += this->process->GetInputStream()->GetC();
    return sLine;
}


/** It is called when the process with the pid pid finishes */
void TProcess::InternalProcess::OnTerminate(int pid, int status)
{
    if(pid != this->owner->iPID)
        return;

    this->owner->errorBuffer = wxT("");
    this->owner->outputBuffer = wxT("");

    while(this->owner->process->IsErrorAvailable())
    {
        wxInputStream * stream = this->owner->process->GetErrorStream();
        while(stream->CanRead())
            this->owner->errorBuffer += stream->GetC();
    }

    while(this->owner->process->IsInputAvailable())
    {
        wxInputStream * stream = this->owner->process->GetInputStream();
        while(stream->CanRead())
            this->owner->outputBuffer += stream->GetC();
    }

    this->owner->iPID = -1;
    this->owner->iExitCode = status;
    this->owner->process = NULL;
}



