#pragma once

#define BOOST_PYTHON_STATIC_LIB
#include <boost/python.hpp>
#include <boost/ref.hpp>

#include <cassert>


namespace util
{


//! boost::pythonのラッパクラス
//! 簡単にpythonコードを実行するための機能.
class PythonRunner
{
public:
	typedef boost::python::object PythonObject;


public:
	//! 指定されたソースを実行する
	static bool RunSourceCode( boost::python::object& global_ns , const char* source )
	{
		namespace bpy = boost::python;

		try
		{
			bpy::exec( source , global_ns , global_ns );
		}
		catch(const bpy::error_already_set&)
		{
			PyErr_Print();

			return false;
		}

		return true;
	}

	//! 指定されたソースファイルを実行する
	static bool RunSourceCodeFromFile( boost::python::object& global_ns , const char* filename )
	{
		std::ifstream ifs( filename );
		if( !ifs.is_open() )
			return false;

		std::string src;
		while( !ifs.eof() )
		{
			std::string s;
			std::getline( ifs , s );
			src += s + "\n";
		}

		return RunSourceCode( global_ns , src.c_str() );
	}


public:
	PythonRunner()
	{
		m_GlobalNS = NULL;
	}

	virtual ~PythonRunner()
	{
		if( IsInitialized() )
			Finalize();
	}

	//! 初期化. 初期化->終了間で処理を実行できる.
	bool Initialize(void)
	{
		assert( !IsInitialized() );
		if( IsInitialized() )
			return false;

		// Python インタプリタ初期化
		try
		{
			Py_Initialize();
		}
		catch(...)
		{
			PyErr_Print();

			assert(false);
			return false;
		}

		// グローバル名前空間を取得
		m_GlobalNS = new PythonObject();
		(*m_GlobalNS) = boost::python::import("__main__").attr("__dict__");
		
		return true;
	}

	//! 終了処理.
	bool Finalize(void)
	{
		if( !IsInitialized() )
			return false;

		bool bFinalized = true;

		try
		{
			Py_Finalize();
		}
		catch(...)
		{
			PyErr_Print();

			assert(false);
			bFinalized = false;
		}

		delete m_GlobalNS;
		m_GlobalNS = NULL;

		return bFinalized;
	}


	//! 初期化されているか確かめる.
	bool IsInitialized(void) const
	{
		return ( m_GlobalNS != NULL );
	}

	//! ソースコードを実行する.
	bool RunSourceCode( const char* source )
	{
		return RunSourceCode( GetGlobal() , source );
	}

	//! ソースファイルを実行する.
	bool RunSourceCodeFromFile( const char* filename )
	{
		return RunSourceCodeFromFile( GetGlobal() , filename );
	}

	//! Pythonのグローバル名前空間を取得
	PythonObject& GetGlobal(void)
	{
		assert( m_GlobalNS != NULL );
		return *m_GlobalNS;
	}

	//! Pythonのグローバル名前空間を取得
	const PythonObject& GetGlobal(void) const
	{
		assert( m_GlobalNS != NULL );
		return *m_GlobalNS;
	}

private:  // noncopyable
	PythonRunner(const PythonRunner&);
	const PythonRunner& operator=(const PythonRunner&);

	
private:
	PythonObject* m_GlobalNS;  //!< python global namespace

};


}
