"""Global module that all modules developing with CherryPy should import."""

__version__ = '2.3.0'

import datetime
import sys
import types

from _cperror import *
import config

import _cptree
tree = _cptree.Tree()

# Legacy code may clobber this.
root = None

lowercase_api = False

import _cpserver
server = _cpserver.Server()

codecoverage = False

try:
    from threading import local
except ImportError:
    from cherrypy._cpthreadinglocal import local

# Create a threadlocal object to hold the request and response
# objects. In this way, we can easily dump those objects when
# we stop/start a new HTTP conversation, yet still refer to
# them as module-level globals in a thread-safe way.
serving = local()

class _ThreadLocalProxy:
    
    def __init__(self, attrname):
        self.__dict__["__attrname__"] = attrname
    
    def __getattr__(self, name):
        try:
            childobject = getattr(serving, self.__attrname__)
        except AttributeError:
            raise AttributeError("cherrypy.%s has no properties outside of "
                                 "an HTTP request." % self.__attrname__)
        return getattr(childobject, name)
    
    def __setattr__(self, name, value):
        try:
            childobject = getattr(serving, self.__attrname__)
        except AttributeError:
            raise AttributeError("cherrypy.%s has no properties outside of "
                                 "an HTTP request." % self.__attrname__)
        setattr(childobject, name, value)
    
    def __delattr__(self, name):
        try:
            childobject = getattr(serving, self.__attrname__)
        except AttributeError:
            raise AttributeError("cherrypy.%s has no properties outside of "
                                 "an HTTP request." % self.__attrname__)
        delattr(childobject, name)

# Create request and response object (the same objects will be used
#   throughout the entire life of the webserver, but will redirect
#   to the "serving" object)
request = _ThreadLocalProxy('request')
response = _ThreadLocalProxy('response')

# Create thread_data object as a thread-specific all-purpose storage
thread_data = local()
threadData = thread_data # Backward compatibility

# Create variables needed for session (see lib/sessionfilter.py for more info)
from filters import sessionfilter
session = sessionfilter.SessionWrapper()
_session_data_holder = {} # Needed for RAM sessions only
_session_lock_dict = {} # Needed for RAM sessions only
_session_last_clean_up_time = datetime.datetime.now()

def expose(func=None, alias=None):
    """Expose the function, optionally providing an alias or set of aliases."""
    
    def expose_(func):
        func.exposed = True
        if alias is not None:
            if isinstance(alias, basestring):
                parents[alias.replace(".", "_")] = func
            else:
                for a in alias:
                    parents[a.replace(".", "_")] = func
        return func
    
    parents = sys._getframe(1).f_locals
    if isinstance(func, (types.FunctionType, types.MethodType)):
        # expose is being called directly, before the method has been bound
        return expose_(func)
    else:
        # expose is being called as a decorator
        if alias is None:
            alias = func
        return expose_

def log(msg='', context='', severity=0, traceback=False):
    """Syntactic sugar for writing to the (error) log."""
    # Load _cputil lazily to avoid circular references, and
    # to allow profiler and coverage tools to work on it.
    import _cputil
    logfunc = _cputil.get_special_attribute('_cp_log_message', '_cpLogMessage')
    
    if traceback:
        msg += _cputil.formatExc()
    
    logfunc(msg, context, severity)
