#ifndef BALL_PYTHON_PYKERNEL_H
#define BALL_PYTHON_PYKERNEL_H

#include <BALL/COMMON/global.h>

#include <Python.h>

#include <map>
#include <string>
#include <utility>

namespace BALL
{
	class PyKernel
	{
		public:
			using KeyValArgs = std::map<std::string, std::string>;

			PyKernel() = default;
			virtual ~PyKernel() = default;

			/**
			 * Checks whether the kernel is started.
			 *
			 * @return true if kernel is started, else otherwise
			 */
			virtual bool isStarted() const = 0;

			/**
			 * Returns the most recent error message emitted by the Python interpreter.
			 *
			 * @return most recent error message
			 */
			virtual std::string getErrorMessage() const = 0;

			/**
			 * Executes a single Python string.
			 *
			 * @param str correctly indented Python string
			 * @return The first value indicated whether the execution succeeded. The second value is the output
			 * 		generated by the execution, if any.
			 */
			virtual std::pair<bool, std::string> run(std::string str) = 0;

			/**
			 * Executes a single Python file.
			 *
			 * @param filename Python file name
			 * @return true if the execution succeeded
			 *
			 * @deprecated Use Jupyter notebook plugin instead
			 */
			BALL_DEPRECATED virtual bool runFile(std::string filename) = 0;

			/**
			 * Calls a single function from a given module.
			 *
			 * @param module a Python module
			 * @param func a function from the given module
			 * @param args function arguments as key-value pairs
			 * @return true if the execution succeeded
			 */
			virtual bool execute(const std::string& module, const std::string& func, const KeyValArgs& args) = 0;

		protected:

			/**
			 * Appends the 'python' directory in the BALL data path to `sys.path`. This is where additional
			 * BALL-specific Python scripts would be located.
			 *
			 * This function should be called by every kernel implementation on initialization!
			 */
			virtual void loadScriptDir();
	};
}

#endif // BALL_PYTHON_PYKERNEL_H
