class Channel(object):
    """
    A verbosity channel from an output, which behaves as a stream
    """
    
    def __init__(self, output, level):
        
        self.output = output
        self.level = level
        
        
    def write(self, message, eol = ""):
        
        self.output.log( msg = message, level = self.level, eol = eol )
        
        
    def writelines(self, sequence):
        
        for line in sequence:
            self.write( message = line )
            
            
    def flush(self):
        
        pass
            
            
    def __call__(self, msg):
        
        self.write( message = msg, eol = "\n" )
        

class SingleStream(object):
    """
    Handles output
    """
    
    INDENT = "    "
    
    DEBUG = 0
    VERBOSE = 1
    INFO = 2
    WARNING = 3
    
    LEVEL_FOR = {
        "DEBUG": DEBUG,
        "VERBOSE": VERBOSE,
        "INFO": INFO,
        "WARNING": WARNING,
        }
    
    def __init__(self, stream = None, level = INFO, gui = False):
        
        if stream is None:
            self._stream = self.__class__
        
        else:
            self._stream = stream
            
        self._level = level
        self._indent = 0
        
        self.warning = Channel( output = self, level = self.WARNING )
        self.info = Channel( output = self, level = self.INFO )
        self.verbose = Channel( output = self, level = self.VERBOSE )
        self.debug = Channel( output = self, level = self.DEBUG )
        
        if gui:
            import libtbx.callbacks
            self.notify = libtbx.call_back
            
        else:
            self.notify = lambda message, data: None
        
        
    def log(self, msg, level, eol = "\n"):
        
        if self._level <= level:
            indented = block_indent(
                text = str( msg ),
                indentation = self.INDENT,
                level = self._indent
                )
            
            for line in indented:
                self._stream.write( line )
            
            self._stream.write( eol )
        
        
    def indent(self):
        
        self._indent += 1
        
        
    def dedent(self):
        
        self._indent = max( 0, self._indent - 1 )
        
        
    def basedent(self):
        
        self._indent = 0
        
        
    @classmethod
    def Debug(cls, stream = None):
        
        return cls( stream = stream, level = cls.DEBUG )
    
    
    @classmethod
    def Verbose(cls, stream = None):
        
        return cls( stream = stream, level = cls.VERBOSE )
    
    
    @classmethod
    def Info(cls, stream = None):
        
        return cls( stream = stream, level = cls.INFO )
    
    
    @classmethod
    def Warning(cls, stream = None):
        
        return cls( stream = stream, level = cls.WARNING )
    
    
    @classmethod
    def ByName(cls, stream = None, name = LEVEL_FOR.keys()[0]):
        
        return cls( stream = stream, level = LEVEL_FOR[ name ] )
        
    
    # This simulates the empty stream
    @staticmethod
    def write(message):
        pass

    
def banner(text):
    
    width = max( len( text ) + 4, 79 )
    separator = "#" * width
    
    return "\n".join(
        [ separator, "# %s #" % text.center( width - 4 ), separator, "" ]
        )

def title(text):
        
    separator = "#" * ( len( text ) + 4 )
    return "\n".join( [ "", separator, "# %s #" % text, separator, "" ] )


def secondary_title(text):
    
    return "\n".join( [ "", text, "#" * len( text ), "" ] )
    

def subtitle(text):
    
    return "\n".join( [ "", text, "=" * len( text ), "" ] )
    
    
def underlined(text):
    
    return "\n".join( [ "", text, "-" * len( text ), "" ] )
    
    
def heading(text):
    
    return "\n".join( [ "", text, "" ] )


def subheading(text):
    
    return "\n".join( [ "", text, "" ] )
    
    
def section_close(text):
    
    return "\n".join( [ "", text, "" ] )


def blank():
    
    return ""


def block_indent(text, indentation, level):
    
    padding = indentation * level
    lines = text.split( "\n" )
    
    for line in lines[:-1]:
        yield "%s%s\n" % ( padding, line )
        
    yield "%s%s" % ( padding, lines[-1] )
