"""

Functions used to help generate code and worker functions
called by code generated by the builtin STML tags.

"""
import logging
import sys
maxint=sys.maxint
from types import ModuleType

from skunk.config import Configuration
from skunk.stml.valformat import ValFormatRegistry

def safe_import(codeout, mod, as_name=None, hidden_ns='__h'):
    """
    imports (in the generated code) the stated module into the given
    hidden namespaceand returns a string that can be used to refer to
    it, of the form "%s.%s" % (hidden_ns, as_name), where as_name
    defaults to mod.__name__ (or, if mod is a string, mod itself).
    as_name must either be the normal name of a module, package-delimited
    if it belongs to a package, or a

    Adapted from a similar function in skunkweb's DT.DTCompilerUtil.
    """
    if isinstance(mod, ModuleType):
        modname=mod.__name__
    else:
        modname=mod

    modlist=modname.split('.', 1)
    if as_name:
        assign_name=as_name
    else:
        assign_name=modlist[0]
        
    if hidden_ns:
        assign_name='%s.%s' % (hidden_ns, assign_name)
        if as_name:
            as_name='%s.%s' % (hidden_ns, as_name)

    codeout.writeln("%s=__import__('%s')" % (assign_name, modname))
    if as_name and modlist[1:]:
        codeout.writeln("%s=%s.%s" % (as_name, assign_name, modlist[1]))
    return as_name


def import_into(thing, mod, as_name=None):
    """
    imports a module and makes it an attribute of some thing.
    
    >>> class thing:
            pass
    >>> o=thing()
    >>> import logging
    >>> import_into(o, logging)
    >>> o.logging.__name__
    'logging'
    >>> import_into(o, 'logging', 'foo')
    >>> o.foo.__name__
    'logging'
    >>> import_into(o, 'skunk.stml')
    >>> o.skunk.stml.__name__
    'skunk.stml'
    >>> import_into(o, 'skunk.stml', 'boo')
    >>> o.boo.__name__
    'skunk.stml'
    """

    if isinstance(mod, ModuleType):
        modname=mod.__name__
    else:
        modname=mod
    top=__import__(modname)
    if not as_name:
        setattr(thing, top.__name__, top)
    else:
        setattr(thing, as_name, sys.modules[modname])

    
def write_val(value, outStream, formatter=None):
    """
    worker function for the <:val:> tag.
    """
    if value is None:
        # special case: None isn't written.
        # perhaps this should be determined
        # by the formatter, but for the current
        # repertoire, that seems like overkill
        return
    if formatter is None:
        formatter=str
    else:
        formatter=get_formatter(formatter)
    outStream.write(formatter(value))


def get_formatter(formatter):
    """
    looks up a formatter.
    """
    if not callable(formatter):
        formatter=ValFormatRegistry[formatter]
    return formatter

tempnum=0

def get_temp_name(prefix='temp'):
    """
    Generates temporary variable names; copied from DT.DTCompilerUtil

    Despite the suspect global, I deem that this will work OK under
    concurrency, because what matters is that temporary variables be
    different within a thread; it doesn't matter whether different
    threads use the same variable names.  The only concurrency problem
    would arise under massive concurrency, because of integer rollover
    -- and that issue can be neglected.
    """
    
    global tempnum
    newname='%s%d' % (prefix, tempnum)
    if tempnum < maxint:
        tempnum+=1
    else:
        tempnul=0
    return newname

__all__=['write_val',
         'get_formatter',
         'get_temp_name',
         'safe_import',
         'import_into']

