/* 
 * © 2009 Sun Microsystems, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */


#ifndef _GRT_PYTHON_CONTEXT_H_
#define _GRT_PYTHON_CONTEXT_H_

#include "grtpp.h"

#ifdef ENABLE_PYTHON_MODULES

#ifdef __APPLE__
# include <Python/Python.h>
#else
# include <Python.h>
#endif

#if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION < 5)
// stuff that doesn't exist in 2.4
typedef int Py_ssize_t;

typedef int (*lenfunc)(PyObject *);
typedef PyObject *(*ssizeargfunc)(PyObject*, Py_ssize_t);
typedef PyObject *(*ssizeargfunc)(PyObject*, Py_ssize_t);
#define ssizeobjargproc intobjargproc

#endif

namespace grt {
  extern const std::string LanguagePython;
  
  struct AutoPyObject
  {
    PyObject *object;
    
    AutoPyObject()
      : object(0)
    {
    }

    AutoPyObject(PyObject *py)
    : object(py)
    {
      Py_INCREF(object);
    }
    
    ~AutoPyObject()
    {
      Py_XDECREF(object);
    }

    AutoPyObject &operator= (PyObject *other)
    {
      Py_XINCREF(other);
      Py_XDECREF(object);
      object= other;

      return *this;
    }
    
    operator PyObject*()
    {
      return object;
    }    
  };
  
  class MYSQLGRT_PUBLIC PythonContext
  {
  public:
    PythonContext(GRT *grt);
    ~PythonContext();

    static PythonContext *get();
    static PythonContext *get_and_check();

    static PyObject *internal_cobject_from_value(const ValueRef &value);
    static ValueRef value_from_internal_cobject(PyObject *value);

    void add_module_path(const std::string &path);
    
    PyObject *from_grt(const ValueRef &value);
    grt::ValueRef from_pyobject(PyObject *object);
    grt::ValueRef from_pyobject(PyObject *object, const grt::TypeSpec &expected_type);

    int run_file(const std::string &file, bool interactive);
    
    int call_grt_function(const std::string &module, const std::string &function,
                          const BaseListRef &args);
    
    PyObject *eval_string(const std::string &expression);
    
    PyObject *get_grt_module();
    
    int refresh();
        
    GRT *get_grt() const { return _grt; }
    
    bool set_cwd(const std::string &path);
    std::string get_cwd() const { return _cwd; }
    
    void acquire();
    void release();
    
    
    static void set_python_error(const grt::type_error &exc);
    static void set_python_error(const grt::bad_item &exc);
    static void set_python_error(const std::exception &exc);
    
  protected:
    GRT *_grt;    
    std::string _cwd;
    AutoPyObject _grt_module;
    AutoPyObject _grt_classes_module;
    AutoPyObject _grt_modules_module;

    AutoPyObject _grt_module_class;
    AutoPyObject _grt_function_class;

    AutoPyObject _grt_list_class;
    AutoPyObject _grt_dict_class;
    AutoPyObject _grt_object_class;
    AutoPyObject _grt_method_class;
    
    std::map<std::string, AutoPyObject> _grt_class_wrappers;
    
  private:
    ValueRef simple_type_from_pyobject(PyObject *object, const grt::SimpleTypeSpec &type);
    
    void register_grt_module();
    void register_grt_functions();
    void redirect_python_output();

    void init_grt_module_type();
    void init_grt_list_type();
    void init_grt_dict_type();
    void init_grt_object_type();
  };
  
  struct LockPython
  {
    PythonContext *context;
    LockPython(PythonContext *ctx)
    : context(ctx)
    {
      context->acquire();
    }
    
    ~LockPython()
    {
      context->release();
    }
  };
  
};

#endif

#endif
