/****************************************************************************
** Implementation of class MediaInfo
**
**   Created : Tue Nov 9 07:53:05 2004
**        by : Varol Okan using the kate editor
** Copyright : (c) Varol Okan
**   License : GPL v 2.0
**
** This class collects all possible information about
** the current set stream.
**
****************************************************************************/

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
//#ifdef QDVD_LINUX 
#include <unistd.h>
#include <sys/wait.h>
//#endif
#include <sys/types.h>
#define BUFLEN 512

#include "run.h"

Run::Run ( )
{
  m_iChildPID = -1;
  m_bStarted  = false;
  m_bFinished = false;
}

Run::~Run ( )
{
}

void Run::setArguments ( QStringList &args )
{
	m_qsCommand = args.join ( " " );	
}

void Run::setCommand ( QString &qsCommand )
{
	m_qsCommand = qsCommand;
}

void Run::tryTerminate ( )
{
  if ( ( started ( ) ) && ( m_iChildPID > 0 ) )
    ::kill ( m_iChildPID, SIGTERM );
}

void Run::kill ( )
{
  if ( ( started ( ) ) && ( m_iChildPID > 0 ) )
    ::kill ( m_iChildPID, SIGKILL );
}

bool Run::started ( )
{
  return m_bStarted;
}

bool Run::finished ( )
{
  return m_bFinished;
}

int Run::start ( QStringList * /*pEnvironment*/ )
{
  if ( m_qsCommand.length ( ) < 1 )
    return 1;

  if ( started ( ) && ! finished ( ) )
    return 1; // previous process still running.

  m_bStarted  = true;
  m_bFinished = false;

  int iWait;
  //int iRead;
  char buf [BUFLEN+1];

  int childToParent[2],parentToChild[2];
  if (pipe(childToParent) == -1)	{
    perror("pipe failed");
    //exit(1);
    return 1;
  }
  if (pipe(parentToChild) == -1)	{
    perror("pipe failed");
    //exit(1);
    return 1;
  }
  // The kernel does not distinguish between the two pipes.
  
  pid_t iWhich = fork ();
  if (iWhich < 0)	{
    perror("fork failed");
    //exit(2);
    return 1;
  }
  else if ( iWhich == 0 ) { // child process
    // The child inherits all open file descriptors, including the pipes.
    int toParent   = childToParent[1];
    // The writable end of one pipe.
    int fromParent = parentToChild[0];
    // The readable end of the other.
    close(childToParent[0]);
    close(parentToChild[1]);

    toParent   = toParent;
    fromParent = fromParent;
    // Close the end of each pipe the child is not going to use.
    // This permits the kernel to correctly transmit end of file.
    // write( toParent,   whatever, length_of_whatever );
    // read ( fromParent, whatever, length_of_whatever );
    
    // The child or parent can also do an exec to run a separate program. The
    // open pipe file descriptors remain open through an exec, so if, for
    // example, toParent equals 17 after the fork, you can exec another program
    // and still write to file descriptor 17 and it will be sent to the parent.
    // In such cases, the usual practice is to rename the descriptors to
    // well-known descriptors such as 0 (for input) and 1 (for output) using dup,
    // dup2, etc. For example, if the child process is to execute "xyz" and
    // doesn't need the parent's stdin or stdout,
    int fromParentDup = dup2 ( fromParent, 0 ); /* turn the pipe from-parent into stdin. */
    int toParentDup   = dup2 (   toParent, 1 );   /* turn the pipe to-parent into stdout. */
	fromParentDup = fromParentDup;
	toParentDup   = toParentDup;
    // the child process can then read and write its stdin and stdout and never know it is
    // actually communicating through a pipe to another process.
//execlp ("more","more","main.cpp",NULL);
//fflush ( stdout );
//printf ("Child still here ... <%d> <%s>\n", iWhich, qsCommand.ascii ( ) );

    //int iRet = system ( m_qsCommand.ascii ( ) ); iRet = iRet; //ooo
    int iRet = system ( m_qsCommand.toLatin1 ( ).data ( ) ); iRet = iRet;   //xxx
    exit   ( 0 );
  }
  else	{ // parent process
    m_iChildPID = iWhich;
    // Sort of the mirror image of what we did with the child.
    int fromChild = childToParent[0];
    // The readable end of one pipe.
    int toChild   = parentToChild[1];

    fromChild = fromChild;
    toChild   = toChild;
    // The writeable end of the other.
//printf ("Parent::childToParent <%d><%d><%d>\n", iWhich, childToParent[0], childToParent[1]);
//printf ("Parent::parentToChild <%d><%d><%d>\n", iWhich, parentToChild[0], parentToChild[1]);
    close(childToParent[1]);
    close(parentToChild[0]);
    // Close the end of each pipe the parent is not going to use.
    // This permits the kernel to correctly transmit end of file.
    pid_t   thePid = 0;
    QString qsReturn;
    ssize_t iRead = read ( fromChild, buf, BUFLEN );
    // string terminator
    buf [ iRead ] = 0;
    while ( iRead )	{
//printf ("iWait !!!<%d> iWhich<%d>\n", iWait, iWhich);
      thePid = waitpid ( iWhich, &iWait, WNOHANG );
//      printf ("------> Parent:<%d> <%s> PID<%d>\n", (int)iRead, (char *)buf, (int)thePid );
      qsReturn += buf;
      iRead = read ( fromChild, buf, BUFLEN );
      buf [ iRead ] = 0;
    }
//	qsReturn = qsReturn.simplifyWhiteSpace ( );
//printf ( "+++++++++>>>>buf<%s>", buf );
    // call pure virtual function with the result ...
    stdOut ( qsReturn );
    // write(toChild,whatever,length_of_whatever);
    // wait for child process to finish ..
    wait ( &iWait );
//printf ("Parental EXIT !!!<%d><%d><%d>\n", iWait, thePid, iWhich);
  }

  m_iChildPID = -1;
  m_bFinished = true;
  return 0;
}


