#
#  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
#
#
#  High level module for managing the lookup of R objects.
#
#  $Id: rpy.py,v 1.9 2004/02/04 21:26:46 warnes Exp $
#
#
from __future__ import nested_scopes

import rpy_io
import UserDict
import time, os, sys

# If we cannot import Numeric, it should have been detected at
# installation time and RPy should have been compiled properly. So,
# don't complain.
try:
    from Numeric import *
except ImportError:
    pass

# try to import rpy binary library using current path
try:
    import _rpy
except ImportError:
    if sys.platform == 'win32':
        import win32api, win32con

        hkey = win32api.RegOpenKeyEx( win32con.HKEY_LOCAL_MACHINE,
                                      "Software\\R-core\\R",
                                      0, win32con.KEY_QUERY_VALUE )
        # get the base directory
        rpath = win32api.RegQueryValueEx( hkey, "InstallPath" )[0]
        win32api.RegCloseKey( hkey )
        Rlib = os.path.join( rpath, 'bin', 'R.dll')
        
        # Now, load the library into the python address space and retry the
        # import
        win32api.LoadLibraryEx( Rlib, 0,
                                win32con.LOAD_WITH_ALTERED_SEARCH_PATH )
        import _rpy
    else:
        raise

# Version
from rpy_version import rpy_version

# Symbolic names for conversion modes
PROC_CONVERSION = 3
CLASS_CONVERSION = 2
BASIC_CONVERSION = 1
NO_CONVERSION = 0
NO_DEFAULT = -1

# Wrap a function in safe modes to avoid infinite recursion when
# called from within the conversion system
def with_mode(i, fun):
    def f(*args, **kwds):
        try:
            e = get_default_mode()
            set_default_mode(i)
            return fun(*args, **kwds)
        finally:
            set_default_mode(e)
    return f

# Manage the global mode
def set_default_mode(mode):
    _rpy.set_mode(mode)

def get_default_mode():
    return _rpy.get_mode()

# The new exception
RException = _rpy.RException

# I/O setters
set_rpy_output = _rpy.set_output
set_rpy_input = _rpy.set_input
get_rpy_output = _rpy.get_output
get_rpy_input = _rpy.get_input

if sys.platform != 'win32':
    set_rpy_showfiles = _rpy.set_showfiles
    get_rpy_showfiles = _rpy.get_showfiles

# Default I/O to functions in the 'rpy_io' module
set_rpy_output(rpy_io.rpy_output)
set_rpy_input(rpy_io.rpy_input)
if sys.platform != 'win32':
    set_rpy_showfiles(rpy_io.rpy_showfiles)

# Functions for processing events
import threading

r_events = _rpy.r_events
_r_thread = None
_r_events_running = threading.Event()
_r_lock = threading.Lock()

def r_eventloop():
    while _r_events_running.isSet():
        _r_lock.acquire()
        r_events()
        _r_lock.release()
        time.sleep(0.2)

def start_r_eventloop():
    global _r_thread
    
    if _r_thread and _r_thread.isAlive():
        return
    
    _r_thread = threading.Thread(target=r_eventloop)
    _r_thread.setDaemon(1)
    _r_events_running.set()
    _r_thread.start()
    return _r_thread

def stop_r_eventloop():
    _r_events_running.clear()

if sys.platform != 'win32':
    start_r_eventloop()


# This function unifies the case of results of length one, which RPy
# returns as single values, and results of length greater than one,
# which are lists.
def as_list(obj):
    try:
        obj+[]
        return obj
    except:
        return [obj]


# A special dict to wrap the arguments in safe modes. It would be
# easier with 2.2, subclassing directly from type 'dict'.
class Dict_With_Mode(UserDict.UserDict):
    def __init__(self, initialdata):
        self.data = initialdata
        
    def __setitem__(self, key, value):
        val = with_mode(BASIC_CONVERSION, value)
        if type(key) in [type(''), type(())]:
            self.data[key] = val
        else:
            self.data[with_mode(BASIC_CONVERSION, key)] = val

# Tables for {PROC,CLASS}_CONVERSION modes
class_table = Dict_With_Mode(_rpy.__class_table__)
proc_table = Dict_With_Mode(_rpy.__proc_table__)

# main class
class R:

    def __init__(self):
        _rpy.set_mode(NO_DEFAULT)
        self.TRUE = self.__getitem__('T')
        self.FALSE = self.__getitem__('F')
        
    def __getattr__(self, name):
        if len(name) > 1 and name[-1] == '_' and name[-2] != '_':
            name = name[:-1]
        name = name.replace('__', '<-')
        name = name.replace('_', '.')
        return self.__getitem__(name)
    
    def __getitem__(self, name):
        obj = self.__dict__[name] = self.__dict__.get(name, _rpy.get(name))
        return obj

    def __call__(self, s):
        return r.eval(r.parse(text=s))
    
# main instance
r = R()

# disable the printing of errors from within R
r.options(show_error_messages=0)


# That's all...


syntax highlighted by Code2HTML, v. 0.9.1