# PyCC's Logging System
#
# Pretty simple stuff.

import sys

import util

MINUTIA = 3
LOW = MINUTIA
DETAILS = 2
MID = DETAILS
OUTLINE = 1
HIGH = OUTLINE
NOTHING = 0

class Log:

    def __init__ (self, out):
        self.out = out
        self.indents = []
        self.curindent = 0
        self.newline = 1
        self.level = NOTHING
        pass

    # Interface

    def set_level (self, lvl):
        self.level = lvl
        return

    def level_enabled (self, lvl):
        return self.level >= lvl

    def low_enabled (self):
        return self.level >= MINUTIA
    
    def mid_enabled (self):
        return self.level >= DETAILS

    def high_enabled (self):
        return self.level >= OUTLINE

    def indent (self, tag, *args):
        
        """ Causes all logs to be indented until undent is called w/ the
        return value.  For example:

        try:
          i = log.indent ('hi')
          ...
        finally: log.undent (i)

        Note: for backwards compatibility, the undent will also occur when
        the 'i' object is collected or deleted.  This method of unindenting
        is being phased out, however.  The try:finally: method is much
        preferred. """

        if self.level == NOTHING: return

        if args: tag = tag % args
        
        self._write ("%s {" % tag)
        self.curindent += 1
        self.indents += (tag,)
        return Log._Indenter (self, tag)

    def low_indent (self, tag, *args):

        """ Like indent, but returns None if the level is not minutia """

        if not self.low_enabled(): return
        return self.indent (tag % args)

    def undent (self, retval):

        """ Call w/ the return value from indent or low_indent; this is
        the transitionary step to move away from the destructor based
        unindenting scheme """

        if retval: retval.undent ()
        return

    def minutia (self, str, *args):
        
        """ Outputs a piece of information that is minutia.  For example,
        some piece of very low level code might use this routine.
        'low' is another name for this routine.

        The recommend way of using this is like so:
          log.minutia ('Index: %d String: %s', index, str)
        rather than:
          log.minutia ('Index: %d String: %s' % (index, str))

        This is that the expensive argument expansion doesn't happen unless
        if logging is enabled. """

        if self.level < MINUTIA: return
        if args: str = str % args
        self._write (str)
        return
    low = minutia

    def details (self, str, *args):
        
        """ Outputs a piece of information that is rather detailed.  A piece
        of mid-level code might use this routine.  'mid' is another name
        for this routine. """
        
        if self.level < DETAILS: return
        if str: str = str % args
        self._write (str)
        return
    mid = details

    def outline (self, str, *args):
        
        """ Outputs a rather high level piece of information.  'high' is
        another name for this routine. """
        
        if self.level < OUTLINE: return
        if str: str = str % args
        self._write (str)
        return
    high = outline

    # Internal stuff:

    class _Indenter:
        def __init__ (self, log, tag):
            self.log = log
            self.tag = tag
            return

        def undent (self):
            if self.log: self.log._undent (self.tag)
            self.log = None
            pass
        
        def __del__ (self):
            self.undent ()
            return
        
        pass

    def _undent (self, tag):
        self.curindent -= 1
        if self.indents[-1] != tag:
            raise util.PyntoException ("Mismatched indent")
        self.indents = self.indents[:-1]
        self._write ("} %s" % tag)
        pass

    def _write (self, text):
        self.out.write ("  "*self.curindent)
        self.out.write (str(text))
        self.out.write("\n")
        return

    pass

if __name__ == "__main__":
    def test():
        i = log.indent ("test", "yo")
        j = log.indent ("test", "yo")
        log.log ("hi")
        del j
        log.log ("hi2")
        return
    log.log ("hello")
    test ()
    
