
#include "__call.h"
#include "Exception.h"
#include "MString.h"
#include <ostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <filesystem>

namespace jet {
   
   __call::__call(coreutils::ZString &in, coreutils::MString &parentOut, Global &global, Tag *parent, Tag *local) : Tag(in, parentOut, global, parent, local) {
      if(hasContainer && keywordDefined("input"))
	throw coreutils::Exception("call tag cannot have both input keyword and have a container.");	
      if(!keywordDefined("pgm"))
	throw coreutils::Exception("pgm keyword must be specified.");
      for(ix = 0; ix <= 50; ++ix)
	argv[ix] = NULL;
      argv[0] = resolveKeyword("pgm").c_str(); // TODO: Need to peel off the program name only and pass as argv[0].
      for(ix = 1; ix <= 50; ++ix) {    
	 coreutils::MString arg("arg");
	 arg << ix;
	 if(keywordDefined(arg)) {	      
	   argv[ix] = resolveKeyword(arg).c_str();
	 } else
	   break;
      }
      pipe(fdo);
      pid = fork();
      if(pid == 0) {
	 close(fdo[0]);
	 dup2(fdo[1], 1);
	 if(hasContainer) { 
	    pipe(fdi);
	    if(fork() == 0) {
	       close(fdi[0]);
	       write(fdi[1], container.getData(), container.getLength());
	       close(fdi[1]);
	       exit(0);
	    }
	    close(fdi[1]);
	    dup2(fdi[0], 0);
	 } else if(keywordDefined("input")) {
	    coreutils::MString input(resolveKeyword("input"));
	    pipe(fdi);
	    if(fork() == 0) {
	       close(fdi[0]);
	       write(fdi[1], input.getData(), input.getLength());
	       close(fdi[1]);
	       exit(0);
	    }
	    close(fdi[1]);
	    dup2(fdi[0], 0);
	 }
	 rc = execvpe(resolveKeyword("pgm").c_str(), argv, global.envp);
	 close(fdo[1]);
	 exit(errno);
      }
      close(fdo[1]);
      if(keywordDefined("name")) {
	 coreutils::MString value;
	 value.read(fdo[0]);
	 storeVariable(resolveKeyword("name"), value, resolveKeyword("scope"));
      } else 
	out.read(fdo[0]);               
      waitpid(pid, &status, 0);
      if(keywordDefined("error")) {	   
	 global.variables[resolveKeyword("error")] = (status >> 8 & 255);
      }      
   }
   
}
