# -*- coding: iso-8859-1 -*-
"""Different help functions and classes

Help functions and classes
==========================

The `default` dictionary contains default values used in noop.

The `randomPyID` function is from TaSK (Tage Stabell-Kulø).  TaSK
called it `randomID`, but since I have modified it I gave it the new
name `randomPyID` (so it will not be confused with his original
`randomID` function).  It generates a new random identifier.  I've
added `pre` argument (to ensure that the generated identifier is a
valid Python identifier) and integrated it more in the noop
environment.

"""


# CVS/RCS information

_file     = r"$RCSfile: misc.py,v $"
_revision = r"$Revision: 1.9 $"
_date     = r"$Date: 2016/05/15 22:04:09 $"
_state    = r"$State: Exp $"
_author   = r"$Author: aa $"

_log      = r"""

$Log: misc.py,v $
Revision 1.9  2016/05/15 22:04:09  aa
Moved `idstr` here (from crypto).

Revision 1.8  2011-09-18 17:19:55  aa
Use annotations for argument types in the signature of functions.

Revision 1.7  2010-09-06 13:32:41  aa
Updated to Python 3.

Revision 1.6  2005/11/30 11:01:50  aa
Updated comments.

Revision 1.5  2004/10/22 19:30:32  aa
Renamed defaults to default.

Revision 1.4  2004/10/20 22:05:19  aa
Minor corrections (added missing import statements and similar).

Revision 1.3  2004/10/20 21:52:11  aa
Added signature to the randomPyID function.

Revision 1.2  2004/10/20 21:37:23  aa
Cleaned up the commets.

Revision 1.1  2004/06/22 18:40:21  aa
Added misc.py with the randomPyID function and updated comments.

"""


# Load some standard python libraries
import inspect
from random import Random
from types import *


# Load noop libraries (if available)
try:
    from noop.core.signature import signature, opt
except ImportError:
    def signature(*args, **kw): return lambda f: f
    class opt:
        def __init__(*args): pass

# Some default values
default = {}
default["lenPyID"] = 16	# The length of a random identifier


# Help function to get the name of class/object
def idstr(self=None):
    if self:
        return __name__ + "." + self.__class__.__name__ + "." + \
            inspect.currentframe().f_back.f_code.co_name
    else:
        return __name__ + "." + inspect.currentframe().f_back.f_code.co_name


# This is a TaSK function (slightly edited for noop usage)
@signature(exc=[TypeError])
def randomPyID(pre:opt(str) = "_", length:opt(int) = default["lenPyID"]) -> str:
    """Generate a random Python identifier
    
    Return a string representing a bitfield in hex notation (`length`
    long) preceeded by the `pre` string.  Maximum set to 256
    characters (1024 bits).  The default length is set to the default
    value 'lenPyID' (see `default` above).  This function does not
    check that the generated identifier is a valid Python identifier.
    Generates av `TypeError` if the given length is less than 1 and
    more than 256.

    """

    # Valid identifier length?
    if length < 1 or length > 256:
        raise TypeError(
              "randomPyID called with invalid number of characters (1-256)")
    
    # Create the random part of the identifier
    rnd = Random()
    tmpID = 0
    for i in range(0, length * 4):
        tmpID += rnd.randint(0,1) << i

    # Insert the preceeding string and remove the "0x"
    return pre + hex(tmpID)[2:]
