/**
 ** Execbox.h - Execute a command-line program and display its output.
 **
 ** Written: 10/02/02 - JSF
 **/

#ifndef INCL_EXECBOX_H
#define INCL_EXECBOX_H  1

/*
Copyright (C) 2002-2022 The Exult Team

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.
*/

class Exec_box;
class Exec_process;

#include "studio.h"

// Called when child is done:
using Exec_done_fun = void (*)(int exit_code, Exec_box *box,
                               gpointer user_data);

#ifndef _WIN32

/*
 *  A class for executing a child process and capturing its output in a
 *  GTK program.
 */
class Exec_process {
public:
	// Function called when data is read
	//   from child.  If datalen == 0,
	//   child is done & exit_code is set.
	using Reader_fun = void (*)(char *data, int datalen, int exit_code,
	                            gpointer user_data);
private:
	// Pipes for talking to child:
	int child_stdin, child_stdout, child_stderr;
	int child_pid;          // Child's process ID.
	gint stdout_tag, stderr_tag;    // GDK tags for getting child's output.
	Reader_fun reader;      // Called when data read from child.
	void *reader_data;      // User data passed back.
public:
	Exec_process();
	~Exec_process();
	void kill_child();      // Kill process.
	void read_from_child(int id);   // Read and call 'reader'.
	// Execute.
	bool exec(const char *file, const char *argv[], Reader_fun rfun,
	          void *udata);
	bool check_child(int &exit_code);   // Is child still running?
};

#else

class Exec_process {
public:
	using Reader_fun = void (*)(char *data, int datalen, int exit_code,
	                            gpointer user_data);
	void kill_child() {}
	void read_from_child(int id) {
		ignore_unused_variable_warning(id);
	}
	bool exec(const char *file, const char *argv[], Reader_fun rfun,
	          void *udata) {
		ignore_unused_variable_warning(file, argv, rfun, udata);
		return false;
	}
	bool check_child(int &exit_code) {
		ignore_unused_variable_warning(exit_code);
		return false;
	}
};

#endif

/*
 *  This class can execute a command-line program and display its output.
 */
class Exec_box {
	Exec_process *executor;     // Handles child process.
	GtkTextView *box;       // Where we show responses.
	GtkStatusbar *status;       // For showing status.
	guint status_ctx;       // Context for status.
	Exec_done_fun done_fun;     // Called when child has exited.
	gpointer user_data;     // Passed to done_fun.
public:
	Exec_box(GtkTextView *b, GtkStatusbar *s, Exec_done_fun dfun = nullptr,
	         gpointer udata = nullptr);
	~Exec_box();
	void show_status(const char *msg);  // Set status bar.
	// Handle data from child.
	void read_from_child(char *data, int datalen, int exit_code);
	void add_message(const char *txt);  // Add text to box.
	// Execute.
	bool exec(const char *file, const char *argv[]);
	void kill_child();      // End.
};

#endif
