# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of logilab-common.
#
# logilab-common 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.1 of the License, or (at your option) any
# later version.
#
# logilab-common 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 logilab-common.  If not, see <http://www.gnu.org/licenses/>.
"""Python Remote Object utilities

Main functions available:

* `register_object` to expose arbitrary object through pyro using delegation
  approach and register it in the nameserver.
* `ns_unregister` unregister an object identifier from the nameserver.
* `ns_get_proxy` get a pyro proxy from a nameserver object identifier.
"""

__docformat__ = "restructuredtext en"

import logging
import tempfile

from Pyro import core, naming, errors, util, config

_LOGGER = logging.getLogger('pyro')
_MARKER = object()

config.PYRO_STORAGE = tempfile.gettempdir()

def ns_group_and_id(idstr, defaultnsgroup=_MARKER):
    try:
        nsgroup, nsid = idstr.rsplit('.', 1)
    except ValueError:
        if defaultnsgroup is _MARKER:
            nsgroup = config.PYRO_NS_DEFAULTGROUP
        else:
            nsgroup = defaultnsgroup
        nsid = idstr
    if nsgroup is not None and not nsgroup.startswith(':'):
        nsgroup = ':' + nsgroup
    return nsgroup, nsid

def host_and_port(hoststr):
    if not hoststr:
        return None, None
    try:
        hoststr, port = hoststr.split(':')
    except ValueError:
        port = None
    else:
        port = int(port)
    return hoststr, port

_DAEMONS = {}
_PYRO_OBJS = {}
def _get_daemon(daemonhost, start=True):
    if not daemonhost in _DAEMONS:
        if not start:
            raise Exception('no daemon for %s' % daemonhost)
        if not _DAEMONS:
            core.initServer(banner=0)
        host, port = host_and_port(daemonhost)
        daemon = core.Daemon(host=host, port=port)
        _DAEMONS[daemonhost] = daemon
    return _DAEMONS[daemonhost]


def locate_ns(nshost):
    """locate and return the pyro name server to the daemon"""
    core.initClient(banner=False)
    return naming.NameServerLocator().getNS(*host_and_port(nshost))


def register_object(object, nsid, defaultnsgroup=_MARKER,
                    daemonhost=None, nshost=None, use_pyrons=True):
    """expose the object as a pyro object and register it in the name-server

    if use_pyrons is False, then the object is exposed, but no
    attempt to register it to a pyro nameserver is made.

    return the pyro daemon object
    """
    nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup)
    daemon = _get_daemon(daemonhost)
    if use_pyrons:
        nsd = locate_ns(nshost)
        # make sure our namespace group exists
        try:
            nsd.createGroup(nsgroup)
        except errors.NamingError:
            pass
        daemon.useNameServer(nsd)
    # use Delegation approach
    impl = core.ObjBase()
    impl.delegateTo(object)
    qnsid = '%s.%s' % (nsgroup, nsid)
    uri = daemon.connect(impl, qnsid)
    _PYRO_OBJS[qnsid] = str(uri)
    _LOGGER.info('registered %s a pyro object using group %s and id %s',
                 object, nsgroup, nsid)
    return daemon

def get_object_uri(qnsid):
    return _PYRO_OBJS[qnsid]

def ns_unregister(nsid, defaultnsgroup=_MARKER, nshost=None):
    """unregister the object with the given nsid from the pyro name server"""
    nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup)
    try:
        nsd = locate_ns(nshost)
    except errors.PyroError as ex:
        # name server not responding
        _LOGGER.error('can\'t locate pyro name server: %s', ex)
    else:
        try:
            nsd.unregister('%s.%s' % (nsgroup, nsid))
            _LOGGER.info('%s unregistered from pyro name server', nsid)
        except errors.NamingError:
            _LOGGER.warning('%s not registered in pyro name server', nsid)


def ns_reregister(nsid, defaultnsgroup=_MARKER, nshost=None):
    """reregister a pyro object into the name server. You only have to specify
    the name-server id of the object (though you MUST have gone through
    `register_object` for the given object previously).

    This is especially useful for long running server while the name server may
    have been restarted, and its records lost.
    """
    nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup)
    qnsid = '%s.%s' % (nsgroup, nsid)
    nsd = locate_ns(nshost)
    try:
        nsd.unregister(qnsid)
    except errors.NamingError:
        # make sure our namespace group exists
        try:
            nsd.createGroup(nsgroup)
        except errors.NamingError:
            pass
    nsd.register(qnsid, _PYRO_OBJS[qnsid])

def ns_get_proxy(nsid, defaultnsgroup=_MARKER, nshost=None):
    """
    if nshost is None, the nameserver is found by a broadcast.
    """
    # resolve the Pyro object
    nsgroup, nsid = ns_group_and_id(nsid, defaultnsgroup)
    try:
        nsd = locate_ns(nshost)
        pyrouri = nsd.resolve('%s.%s' % (nsgroup, nsid))
    except errors.ProtocolError as ex:
        raise errors.PyroError(
            'Could not connect to the Pyro name server (host: %s)' % nshost)
    except errors.NamingError:
        raise errors.PyroError(
            'Could not get proxy for %s (not registered in Pyro), '
            'you may have to restart your server-side application' % nsid)
    return core.getProxyForURI(pyrouri)

def get_proxy(pyro_uri):
    """get a proxy for the passed pyro uri without using a nameserver
    """
    return core.getProxyForURI(pyro_uri)

def set_pyro_log_threshold(level):
    pyrologger = logging.getLogger('Pyro.%s' % str(id(util.Log)))
    # remove handlers so only the root handler is used
    pyrologger.handlers = []
    pyrologger.setLevel(level)
