# -*- coding: UTF-8 -*-
#    This file is part of arena.
#   
#    arena is free software: you can redistribute it and/or modify it
#    under the terms of the GNU General Public License as published by the
#    Free Software Foundation; either version 3 of the License or, at your
#    option, any later version.
#
#    arena is distributed in the hope that it will be useful, but
#    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABLITY
#    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
#    License for more details.
#
#    You should have received a copy of the GNU General Public License along
#    with arena.  If not, see <http://www.gnu.org/licenses/>. 

## @file
#  This file defines several classes that represent Markdown-style statements 
#  parsed from a source stream.

from Library.Parse.Semantic.SourceStatements import ASourceStatement
from Library.Parse.Lex.Languages import TokenType
from Library.Parse.SymbolTables import Scope
from Plugins.Content.Parse.Lex.Languages import MarkdownOpcode
from Plugins.Content.Parse.Symbols import ALinkIdentifier
from Plugins.Content.Parse.Semantic.MarkdownPreStatements import \
    mdxmlsStringRepresentation
from Local.Configuration import Site
from Library.String.Utilities import String
from Library.IO.StringStreams import AStringStream
from Library.IO.XML.XMLTags import AnXMLTag, AnXMLWrapperTag
import os.path

## Image file extensions
mdsImageFileExtensions = (".gif", ".jpg", ".jpeg", ".png", ".svg", ".tif", 
                          ".tiff")

## The default image alignment
mdisDefaultAlignment = "right"
## The default identifier for anchors after post preamble
mhrlMoreAnchorIdentifier = "$special/more"

## A generic Markdown-style statement
class AMarkdownStatement(ASourceStatement):
    ## Initializer
    def init(Self):
        result = ASourceStatement.init(Self)
                                
        return result
    
    ## Parse tokens from the source.
    #
    #  Descendant classes should override this method to act on one more or
    #  tokens.  The base implementation of this method simply outputs the
    #  token literal to the output stream and fetches the next token.
    def parse(Self):
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
        
        del Event
            
        Self._value = Self._Parser.Token().literal()
        Self._Parser.NextToken()     
    
    ## Search subclasses for the handler for the specified token.
    #
    #  This method takes advantage of the fact that Python links the 
    #  immediate subclasses of a class to their parent using an iterable object.
    #  The method iterates through those subclasses, calling
    #  AMarkdownStatement.handlerFor() on each one in an attempt to find a
    #  class that will handle the specified \p tokenCode.
    #
    #  If a class determines that it will handle the specified \p tokenCode, it
    #  creates an instance of itself and returns that instance instead of
    #  continuing the search.  That instance will be returned by this method,
    #  which otherwise returns \p None to indicate that no class was found to
    #  handle the specified \p tokenCode.
    @classmethod
    def subclassHandlerFor(Self, tokenCode, **params):
        Result = None
        
        # Query subclasses for one that will accept the token
        for Subclass in Self.__subclasses__():
            Result = Subclass.handlerFor(tokenCode, **params)
            if Result is not None:
                break
        
        return Result
    
    ## Determine whether the class will handle the specified token.
    #
    #  Together with AMarkdownStatement.subclassHandlerFor(), this method makes 
    #  adding new handlers for Markdown tokens as easy as deriving a class from 
    #  AMarkdownStatement or its descendants.  
    #
    #  The base implementation of this method searches the immediate subclasses 
    #  of AMarkdownStatement, calling AMarkdownStatement.handlerFor() on each 
    #  one.  THOSE classes, in turn, first determine whether or not they will 
    #  handle \p tokenCode.  If not, they search their immediate subclasses (by 
    #  calling AMarkdownStatement.subclassHandlerFor() on themselves) -- and so 
    #  forth.
    #
    #  The base implementation of this method returns the result of call to
    #  AMarkdownStatement.subclassHandlerFor() on itself.  The return value
    #  will either be an instance of the class that will handle the specified
    #  \p tokenCode; or \p None to indicate that no class was found to handle
    #  the specified token.
    #
    #  Descendant classes should override this method to add code that will
    #  determine whether or not the class will handle the specified token.
    #  Otherwise, the overriding method should return the result of a call to
    #  AMarkdownStatement.subclassHandlerFor() on its class.
    @classmethod
    def handlerFor(Self, tokenCode, **params):        
        return Self.subclassHandlerFor(tokenCode, **params)
    
    ## Parse a statement from the specified source    
    @classmethod
    def ParsedFrom(Self, ThisParser):
        Result = None
        
        if ThisParser is not None:
            token = ThisParser.Token().code()
            
            # Query subclasses for one that will accept the token
            Result = Self.handlerFor(token, Parser = ThisParser)

            if Result == None:
                # Handle the token ourselves
                Result = Self(Parser = ThisParser)
                
        return Result        
  
## A link statement
class AMarkdownLinkStatement(AMarkdownStatement):
    ## Initializer
    def init(Self):
        result = AMarkdownStatement.init(Self)
        
        if result:
            # Establish public attributes
            # The XML tag represented by the statement
            Self._Tag = None
            
        return result
        
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:
            if tokenCode == MarkdownOpcode.dlOpenBracket:
                Result = Self(**params)
            
        return Result
              
    ## Parse an inline link from the source
    def parseInline(Self):
        # Inline link format is
        #     (URL) - OR -
        #     (URL "title text") - OR -
        #     (<URL>) - OR -
        #     (<URL> "title text")
        
        # Skip the opening paren
        Self._Parser.NextToken()
        
        # Store the URL
        Self._Tag["href"] = ""
        while Self._Parser.Token().code() not in (TokenType.space,
            TokenType.endOfLine, MarkdownOpcode.dlCloseParen):                        
                if Self._Parser.Token().code() == TokenType.endOfStream:
                    break
                    
                Self._Tag["href"] += Self._Parser.Token().literal()
                Self._Parser.NextToken()
        
        if Self._Parser.Token().code() == TokenType.space:
            Self._Output.write(Self._Parser.Token().literal())        
            Self._Parser.NextToken()
        
            # Check for title text
            if Self._Parser.Token().code() == TokenType.string:
                Self._Tag["title"] = Self._Parser.Token().value()
                Self._Parser.NextToken()
        
        # Skip the closing paren
        Self._Parser.NextToken()
    
    ## Parse a reference-style link from the source
    def parseReference(Self):
        # Reference-style link format is
        #     [reference] - OR -
        #     []
        
        # Skip the opening bracket
        Self._Parser.NextToken()
        
        # Get the reference - if explicitly named...
        refName = ""
        while Self._Parser.Token().code() not in (MarkdownOpcode.dlCloseBracket,
            TokenType.endOfLine, TokenType.endOfStream):
                refName += Self._Parser.Token().literal()
                Self._Parser.NextToken()
        
        if refName == "":
            refName = Self._Tag.text
            
        Link = None
        
        try:
            Link = Self._Parser.Symbols()[Scope.globals][refName]
            
        except:
            pass
          
        Self._Parser.NextToken()
        
        if Link is not None:
            Self._Tag["href"] = Link.url
            Self._Tag["title"] = Link.title
            
            # Include any other attributes
            if len(Link.attributes) > 0:
                Self._Tag.attributes().update(Link.attributes)
              
    ## Process an a link that refers to an attachment
    def parseAttachmentReference(Self):
        if Self._Tag["href"] is None:
            return
            
        # Check the protocol specified by the link
        if ":" in Self._Tag["href"]:
            protocol = Self._Tag["href"][0:Self._Tag["href"].find(":")]
            
            protocol = protocol.lower()
            
            if protocol == "attach":
                # This is an attachment link -- see if the attachment exists
                attachmentName = Self._Tag["href"][len(protocol) + 1:]
                Attachment = Self._Parser.Attachment(attachmentName)
                
                if Attachment is not None:
                    Self._Tag["href"] = Attachment["clientPath"]  
                    
                    # Display the attachment icon
                    #if Attachment.icon() is not None:
                    #    AttachmentIcon = AnXMLTag("img")
                    #    AttachmentIcon["alt"] = "Attachment icon"
                    #    AttachmentIcon["src"] = Attachment.icon()
                    #    AttachmentIcon["class"] = "line_icon"
                    
                    #    Self._Tag.text = \
                    #        AttachmentIcon.toString() + Self._Tag.text
                    #    del AttachmentIcon
                    
                    if String.isEmpty(Self._Tag["title"]):
                        Self._Tag["title"] = Attachment["description"]          
                    
                else:
                    Self._Tag["href"] = \
                        Self._Parser.newAttachmentLink(attachmentName)
              
    ## Parse the link statement from the source
    def parse(Self):
        # Link format is:
        #     [Link display text](URL) - OR -
        #     [Link display text](URL "title text") - OR -
        #     [Link display text][reference]
        
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
      
        Self._Parser.NextToken()
        
        # Construct an XML tag for output
        Self._Tag = AnXMLWrapperTag("a")
        Self._Tag.text = ""
        
        # Parse the link display text
        while Self._Parser.Token().code() not in \
          Self._Language.Rule("link/ending"):
              Self._Tag.text += Self._Parser.Token().literal()
              Self._Parser.NextToken()
         
        Self._Parser.NextToken()
        # Check for an inline or reference-style link
        if Self._Parser.Token().code() == MarkdownOpcode.dlOpenParen:
            Self.parseInline()
            
        elif Self._Parser.Token().code() == MarkdownOpcode.dlOpenBracket:
            Self.parseReference()
            
        # Check for an attachment in the link
        Self.parseAttachmentReference()
            
        # Output the link
        Self._value = Self._Tag.toString()
 
## An image
class AMarkdownImageStatement(AMarkdownLinkStatement): 
    ## Initializer
    def init(Self):
        result = AMarkdownStatement.init(Self)
        
        if result:
            # Establish private attributes
            # The XML tag represented by the statement
            Self._Tag = None            
            Self._align = mdisDefaultAlignment
            
        return result
                 
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode == MarkdownOpcode.dlBeginImage:
                Result = Self(**params)
            
        return Result
        
    ## Parse an inline image reference from the source
    def parseInline(Self):
        # Inline image reference format is
        #     (URL) - OR -
        #     (URL "title text")
        
        # Skip the opening paren
        Self._Parser.NextToken()
        
        # Store the URL
        Self._Tag["src"] = ""
        while Self._Parser.Token().code() not in (TokenType.space,
            TokenType.endOfLine, MarkdownOpcode.dlCloseParen):
                if Self._Parser.Token().code() == TokenType.endOfStream:
                    break
                    
                Self._Tag["src"] += Self._Parser.Token().literal()
                Self._Parser.NextToken()
        
        if Self._Parser.Token().code() == TokenType.space:   
            Self._Output.write(Self._Parser.Token().literal())     
            Self._Parser.NextToken()
        
            # Check for title text
            if Self._Parser.Token().code() == TokenType.string:
                Self._Tag["title"] = Self._Parser.Token().value()
                Self._Parser.NextToken()
        
        # Skip the closing paren
        Self._Parser.NextToken()
    
    ## Parse a reference-style image reference from the source
    def parseReference(Self):
        # Reference-style image reference format is
        #     [reference] - OR -
        #     []
        
        # Skip the opening bracket
        Self._Parser.NextToken()
        
        # Get the reference - if explicitly named...
        if Self._Parser.Token().code() != MarkdownOpcode.dlCloseBracket:
            refName = Self._Parser.Token().literal()
            Self._Parser.NextToken()
        
        # ...if implicitly named, use the value of the link text    
        else:
            refName = Self._Tag["alt"]
            
        Link = Self._Parser.Symbols()[Scope.globals][refName]
          
        Self._Parser.NextToken()
        
        if Link is not None:
            Self._Tag["src"] = Link.url
            Self._Tag["title"] = Link.title
            
            # Include any other attributes
            if len(Link.attributes) > 0:
                Self._Tag.attributes().update(Link.attributes)            
                     
    ## Process an image that refers to an attachment
    def parseAttachmentReference(Self):
        # Check the protocol specified by the image source
        if ":" in Self._Tag["src"]:
            protocol = Self._Tag["src"][0:Self._Tag["src"].find(":")]
            
            protocol = protocol.lower()
            
            if protocol == "attach":
                # This is an attachment link -- see if the attachment exists
                attachmentName = Self._Tag["src"][len(protocol) + 1:]
                Attachment = Self._Parser.Attachment(attachmentName)
                
                if Attachment is not None:
                    Self._Tag["src"] = Attachment["clientPath"] 
                    
                    if String.isEmpty(Self._Tag["title"]):
                        Self._Tag["title"] = Attachment["description"]          
                    
                else:
                    # Construct an anchor tag to allow the image to be uploaded
                    NewAttachmentLink = AnXMLWrapperTag("a")
                    NewAttachmentLink["href"] = \
                        Self._Parser.newAttachmentLink(attachmentName)        
                    NewAttachmentLink["title"] = "Upload this image"
                    NewAttachmentLink.text = Self._Tag.toString()
                    Self._Tag = NewAttachmentLink
                     
    ## Parse the image statement from the source
    def parse(Self):
        # Image format is:
        #     ![Image alt. text](URL) - OR -
        #     ![Image alt. text](URL "title text") - OR -
        #     ![Image alt. text][reference]
        # The image is aligned to the LEFT of the paragraph if it is located
        # at the beginning of the paragraph.  It is CENTERED if it is the only
        # thing on the line.  It is otherwise right-aligned.

        Self._Parser.NextToken()
        
        # Construct a tag for output
        Self._Tag = AnXMLTag("img")
        Self._Tag["alt"] = ""
        Self._Tag["align"] = mdisDefaultAlignment
        
        # Check the previous token -- are we at the beginning of a paragraph?
        if Self._Parser.PreviousToken().code() == TokenType.endOfLine:
            Self._Tag["align"] = "left"

        while Self._Parser.Token().code() not in \
          Self._Language.Rule("link/ending"):
              Self._Tag["alt"] += Self._Parser.Token().literal()
              Self._Parser.NextToken()
            
        Self._Parser.NextToken()
        # Check for an inline or reference-style link
        if Self._Parser.Token().code() == MarkdownOpcode.dlOpenParen:
            Self.parseInline()
            
        elif Self._Parser.Token().code() == MarkdownOpcode.dlOpenBracket:
            Self.parseReference()
            
        # Check for an attachment in the link
        Self.parseAttachmentReference()
        
        # Check the next token: are we at the end of the line?
        Tok = Self._Parser.PeekToken()
        if Tok.code() == TokenType.endOfLine:
            # We are the at the end of a line; were we the only thing on line?
            # If so, we will already be left-aligned by the code above
            if Self._Tag["align"] != mdisDefaultAlignment:
                # And now the image is center-aligned
                Paragraph = AnXMLWrapperTag("p")
                Paragraph["style"] = "text-align:center;"
                del Self._Tag["align"]                
                Paragraph.text = Self._Tag.toString()
                del Self._Tag
                Self._Tag = Paragraph
                
        del Tok
        
        # Output the image reference
        Self._value = Self._Tag.toString()    
 
## A class that handles strong formatting
class AMarkdownStrongBlock(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode in params["Parser"].Language().Rule("block/strong"):
                Result = Self(**params)
            
        return Result
    
    ## Parse the statement
    def parse(Self):      
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                
        # The same token must be used to end the block
        endOfBlock = Self._Parser.Token().code()
        
        # Construct an XML tag to handle output of the block
        StrongBlock = AnXMLWrapperTag("strong")
        # Construct an output stream to store the text of the block
        BlockText = AStringStream()
        
        # Redirect parser output to our output stream
        PreviousOutput = Self.OutputTo(BlockText)
        
        # Parse tokens until the end of the block
        Self._Parser.parseUntil(endOfBlock)
        
        # Retrieve the text of the block
        StrongBlock.text = BlockText.toString()
        
        # Free the temporary output stream
        del BlockText
        # Restore the previous output
        Self.OutputTo(PreviousOutput)
        
        # Write the strong block
        StrongBlock.printTo(Self._Output)
        # Skip past the end of the block
        Self._Parser.NextToken()

## A class that handles an unordered list
class AMarkdownUnorderedListBlock(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode in params["Parser"].Language().Rule("list/unordered"):
                Result = Self(**params)
            
        return Result
    
    ## Initializer
    def init(Self):
        result = AMarkdownStatement.init(Self)
        
        if result:
            # Establish private attributes
            # The HTML tag used to specify the list
            Self._ListTag = None
            # The HTML tag used to specify the list item
            Self._ListItemTag = None
            # The stream used to capture list output
            Self._ListText = None
            # The stream used to capture list item output
            Self._ListItemText = None
            
        return result
    
    ## Print the list item
    def printListItem(Self, PreviousOutput):
        # Restore the previous output
        Self.OutputTo(PreviousOutput)
        Self._ListItemTag.text = Self._ListItemText.toString()
                    
        # Write the list item to the stream
        Self._ListItemTag.printTo(Self._Output)
                    
        # Write a line break after the list item
        BreakTag = AnXMLTag("br")
        BreakTag.printTo(Self._Output)
        del BreakTag
    
    ## Parse the statement
    def parse(Self):
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                
        # To be a list, the token must occur at the beginning of a line
        if (Self._Parser.PreviousToken() is not None) and \
            (Self._Parser.PreviousToken().code() != TokenType.endOfLine):
                # Output the token literal
                Self._Output.write(Self._Parser.Token().literal())
                Self._Parser.NextToken()
                return
        
        # Redirect output to capture the text of the ordered list
        Self._ListText = AStringStream()
        OriginalOutput = Self.OutputTo(Self._ListText)    
            
        # Construct a list item
        Self._ListItemTag = AnXMLWrapperTag("li")
        # Redirect output to capture the text of the list item
        Self._ListItemText = AStringStream()
        PreviousOutput = Self.OutputTo(Self._ListItemText)
                    
        # Skip any space between the list marker and the list item
        Tok = Self._Parser.PeekToken()
        if Tok.code() in (TokenType.space, MarkdownOpcode.dlTab):
            Self._Parser.NextToken()
              
        # The list item ends with two consecutive line breaks
        while True:
            # parseUntil() always skips the current token
            Self._Parser.parseUntil(TokenType.endOfLine)
                   
            if Self._Parser.Token().code() == TokenType.endOfStream:  
                Self.printListItem(PreviousOutput)            
                break
                        
            # Write the end of line
            Self._Output.write(Self._Parser.Token().literal())
            
            # Check for two consecutive line breaks
            Tok = Self._Parser.PeekToken()
            if Tok.code() == TokenType.endOfLine:                        
                # Write the end of line
                Self._Parser.NextToken()
                Self._Output.write(Self._Parser.Token().literal())
                
                # Two or more line breaks might mean the end of the list item
                # IF the new line is not indented
                Tok = Self._Parser.PeekToken()
                if Tok.code() != MarkdownOpcode.dlTab:
                    Self.printListItem(PreviousOutput) 
                    break                               
                                            
            # Otherwise, if the new line contains a list marker, it
            # marks a new list item; if it does not then it marks the end
            # of the list
            if Tok.code() in Self._Language.Rule("list/unordered"):
                Self.printListItem(PreviousOutput)
                                    
                Self._Parser.NextToken()

                Tok = None                            
                # Construct a list item
                Self._ListItemTag = AnXMLWrapperTag("li")
                # Redirect output to capture the text of the list item
                Self._ListItemText = AStringStream()
                PreviousOutput = Self.OutputTo(Self._ListItemText)
                                        
                # Skip any space between the list marker and the list item
                Tok = Self._Parser.PeekToken()
                if Tok.code() in (TokenType.space, MarkdownOpcode.dlTab):
                    Self._Parser.NextToken()
                    
            elif Tok.code() == MarkdownOpcode.dlTab:
                # Skip the excess tab at the beginning of the line
                Self._Parser.NextToken()                      
        
        # Construct an unordered list item
        Self._ListTag = AnXMLWrapperTag("ul")
        # Get the text of the unordered list
        Self._ListTag.text = Self._ListText.toString()
        
        # Restore the original output
        Self.OutputTo(OriginalOutput)
        # Write the unordered list
        Self._ListTag.printTo(Self._Output)

## A class that handles an ordered list
class AMarkdownOrderedListBlock(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode == TokenType.number:
                Result = Self(**params)
            
        return Result
                 
    ## Initializer
    def init(Self):
        result = AMarkdownStatement.init(Self)
        
        if result:
            # Establish private attributes
            # The HTML tag used to specify the list
            Self._ListTag = None
            # The HTML tag used to specify the list item
            Self._ListItemTag = None
            # The stream used to capture list output
            Self._ListText = None
            # The stream used to capture list item output
            Self._ListItemText = None
            
        return result                 
                 
    ## Print the list item
    def printListItem(Self, PreviousOutput):
        # Restore the previous output
        Self.OutputTo(PreviousOutput)
        Self._ListItemTag.text = Self._ListItemText.toString()
                    
        # Write the list item to the stream
        Self._ListItemTag.printTo(Self._Output)
                    
        # Write a line break after the list item
        BreakTag = AnXMLTag("br")
        BreakTag.printTo(Self._Output)
        del BreakTag
                         
    ## Parse the statement
    def parse(Self):
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                
        # Get the starting value for the list
        startValue = Self._Parser.Token().value()        
        
        # To be an ordered list, the number must occur at the beginning of a line
        if (Self._Parser.PreviousToken() is not None) and \
            (Self._Parser.PreviousToken().code() != TokenType.endOfLine):
                # Output the token literal
                Self._Output.write(Self._Parser.Token().literal())
                Self._Parser.NextToken()
                return
        
        # AND be followed by a period
        Self._Parser.NextToken()
        if Self._Parser.Token().code() != MarkdownOpcode.dlPeriod:
            # Output the token iteral
            Self._Output.write(Self._Parser.PreviousToken().literal())
            return
            
        # AND be followed by a space
        Tok = Self._Parser.PeekToken()
        if Tok.code() not in (TokenType.space, MarkdownOpcode.dlTab):
            # Output the token literal
            Self._Output.write(str(startValue))
            return
           
        # Construct a stream to contain the output of the ordered list
        Self._ListText = AStringStream()
        # Redirect output
        OriginalOutput = Self.OutputTo(Self._ListText)
        
        # Construct an XML object to represent the list item
        Self._ListItemTag = AnXMLWrapperTag("li")
        # Construct a stream to hold the output of the ordered list item
        Self._ListItemText = AStringStream()
        # Redirect output
        PreviousOutput = Self.OutputTo(Self._ListItemText)
                    
        # Skip the period
        Self._Parser.NextToken()
        
        # Skip any space between the period and the list item
        Tok = Self._Parser.PeekToken()
        if Tok.code() in (TokenType.space, MarkdownOpcode.dlTab):
            Self._Parser.NextToken()
              
        # The list item ends with two consecutive line breaks
        while True:
            # parseUntil() always skips the current token
            Self._Parser.parseUntil(TokenType.endOfLine)
                   
            if Self._Parser.Token().code() == TokenType.endOfStream:
                Self.printListItem(PreviousOutput)
                break
                        
            # Write the end of line
            Self._Output.write(Self._Parser.Token().literal())
            
            # Check for two consecutive line breaks
            Tok = Self._Parser.PeekToken()
            if Tok.code() == TokenType.endOfLine:                        
                # Write the end of line
                Self._Parser.NextToken()
                Self._Output.write(Self._Parser.Token().literal())
                
                # Two or more line breaks might mean the end of the list item
                # IF the new line is not indented
                Tok = Self._Parser.PeekToken()
                if Tok.code() != MarkdownOpcode.dlTab:
                    Self.printListItem(PreviousOutput)
                    break
                                            
            # Otherwise, if the new line contains a number and period, it
            # marks a new list item; if it does not then it marks the end
            # of the list
            if Tok.code() == TokenType.number:
                Self.printListItem(PreviousOutput)
                
                Self._Parser.NextToken()
                Tok = Self._Parser.PeekToken()
                                
                if Tok.code() != MarkdownOpcode.dlPeriod:
                    Tok = None
                    break
                        
                Self._Parser.NextToken()
                Tok = Self._Parser.PeekToken()
                if Tok.code() not in (MarkdownOpcode.dlTab, 
                  TokenType.space):
                      Tok = None
                      break
                    
                Tok = None    
                # Construct an XML object to represent the list item
                Self._ListItemTag = AnXMLWrapperTag("li")
                # Construct a stream to hold the output of the ordered list item
                Self._ListItemText = AStringStream()
                # Redirect output
                PreviousOutput = Self.OutputTo(Self._ListItemText)
                    
                # Skip the period
                Self._Parser.NextToken()
                    
                # Skip any space between period and the start of the
                # list item
                Tok = Self._Parser.PeekToken()
                if Tok.code() in (TokenType.space, MarkdownOpcode.dlTab):
                    Self._Parser.NextToken()
                    
            elif Tok.code() == MarkdownOpcode.dlTab:                    
                # Skip the excess tab at the beginning of the line
                Self._Parser.NextToken()
                        
        # Construct an XML tag to represent the ordered list
        Self._ListTag = AnXMLWrapperTag("ol")
        # Get the text of the ordered list
        Self._ListTag.text = Self._ListText.toString()

        # Set the start value of the list
        Self._ListTag["start"] = startValue
        
        # Print the ordered list
        Self.OutputTo(OriginalOutput)
        Self._ListTag.printTo(Self._Output)
                    
## A class that handles unordered list or emphasis formatting
class AMarkdownAsteriskBlock(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:
            if tokenCode == MarkdownOpcode.dlAsterisk:
               Result = Self(**params)
            
        return Result
            
    ## Parse the statement
    def parse(Self):
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                
        # To be a list marker, the asterisk must occur at the beginning of a 
        # line
        if Self._Parser.PreviousToken().code() == TokenType.endOfLine:
            Statement = AMarkdownUnorderedListBlock(Self._Parser)
            Statement.parse()
            del Statement
            
            return
            
        # If emphasis block, the same token must be used to end the block
        endOfBlock = Self._Parser.Token().code()
        
        # Peek at the next token
        Tok = Self._Parser.PeekToken()
        # Is it not a space?
        if Tok.code() not in (TokenType.space, MarkdownOpcode.dlTab):
            # Not a space -- must be an emphasis block
            EmSpan = AnXMLWrapperTag("em")
            EmText = AStringStream()
            PreviousOutput = Self.OutputTo(EmText)
        
            # Parse tokens until the end of the block
            Self._Parser.parseUntil(endOfBlock)
            
            EmSpan.text = EmText.toString()
            del EmText
            
            Self.OutputTo(PreviousOutput)
            
            EmSpan.printTo(Self._Output)
            del EmSpan

            Self._Parser.NextToken()
            
        else:
            Self._Output.write(Self._Parser.Token().literal())
            
        del Tok

## A class that handles emphasis formatting
class AMarkdownEmphasisBlock(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode == MarkdownOpcode.dlUnderscore:
                Result = Self(**params)
            
        return Result
            
    ## Parse the statement
    def parse(Self):
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                
        # The same token must be used to end the block
        endOfBlock = Self._Parser.Token().code()
        
        EmSpan = AnXMLWrapperTag("em")
        EmText = AStringStream()
        PreviousOutput = Self.OutputTo(EmText)
        
        # Parse tokens until the end of the block
        Self._Parser.parseUntil(endOfBlock)
            
        EmSpan.text = EmText.toString()
        del EmText
            
        Self.OutputTo(PreviousOutput)
            
        EmSpan.printTo(Self._Output)
        del EmSpan
        
        Self._Parser.NextToken()

## A class that handles header lines
class AMarkdownHeaderLine(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode in params["Parser"].Language().Rule("line/header"):
                Result = Self(**params)
            
        return Result
            
    ## Parse the statement
    def parse(Self):
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                
        # Determine the header level
        level = len(Self._Parser.Token().literal())
        # Begin the header block
        HeaderBlock = AnXMLWrapperTag("h" + str(level))
        HeaderBlockText = AStringStream()
        PreviousOutput = Self.OutputTo(HeaderBlockText)
        
        # Parse tokens until the end of the line or until another hash
        # character is encountered
        Self._Parser.parseUntil(TokenType.endOfLine, 
          *Self._Language.Rule("line/header"))
        
        # Ignore hashes at the end of the line
        if Self._Parser.Token().code() in Self._Language.Rule("line/header"):
            Self._Parser.parseUntil(TokenType.endOfLine)
            
        # End the header block
        HeaderBlock.text = HeaderBlockText.toString()
        del HeaderBlockText
        Self.OutputTo(PreviousOutput)
        
        # Construct an anchor for the header line
        HeaderAnchor = AnXMLWrapperTag("a")
        HeaderAnchor["id"] = HeaderBlock.text.replace(" ", "")
        HeaderAnchor.printTo(Self._Output)
        del HeaderAnchor
        
        HeaderBlock.printTo(Self._Output)
        del HeaderBlock
     
## A class that handles emphasis formatting
class AMarkdownCodeSpan(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode == MarkdownOpcode.dlBacktick:
                Result = Self(**params)
        
        return Result
            
    ## Parse the statement
    def parse(Self):
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                
        # Check for two backticks in a row
        Tok = Self._Parser.PeekToken()
        
        if Tok.code() != MarkdownOpcode.dlBacktick:
            CodeSpan = AnXMLWrapperTag("code")
            CodeSpanText = AStringStream()
            PreviousOutput = Self.OutputTo(CodeSpanText)
            
            # Output tokens verbatim until the end of the block
            Self._Parser.NextToken()
            while Self._Parser.Token().code() != MarkdownOpcode.dlBacktick:
                if Self._Parser.Token().code() == TokenType.endOfStream:
                    break
                    
                Self._Output.write(Self._Parser.Token().literal())
                    
                Self._Parser.NextToken()
                
            CodeSpan.text = CodeSpanText.toString()
            del CodeSpanText
            Self.OutputTo(PreviousOutput)
            CodeSpan.printTo(Self._Output)
            del CodeSpan
            
            Self._Parser.NextToken()
            
        else:
            Self._Parser.NextToken()
            # Output a single backtick character
            Self._Output.write(Self._Parser.Token().literal())
            Self._Parser.NextToken() 
            
        del Tok
        
### A class that handles horizontal rules
class AMarkdownHorizRuleLine(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode in params["Parser"].Language().Rule("delimiter/hrule"):
                Result = Self(**params)
            
        return Result
        
    ## Parse the statmenet
    def parse(Self):
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                
        # Horizontal rules must be the only thing on the line
        Tok = Self._Parser.PeekToken()
        if (Tok.code() != TokenType.endOfLine) or \
          (Self._Parser.PreviousToken().code() != TokenType.endOfLine):
              Self._Output.write(Self._Parser.Token().literal())
              Self._Parser.NextToken()
              
              return
              
        # Check for a special horizontal rule
        if Self._Parser.Token().code() in Self._Language.Rule("delimiter/more"):
            if Self._Parser.Content().hasPreamble() == False:
                Self._Parser.recordPreamble()
                
                # Insert an anchor after the preamble, for easy linking
                AnchorTag = AnXMLWrapperTag("a")
                AnchorTag["id"] = mhrlMoreAnchorIdentifier
                AnchorTag.text = ""
                AnchorTag.printTo(Self._Output)
                del AnchorTag
                
                Self._Parser.NextToken()                
                return
                
        RuleTag = AnXMLTag("hr")
        RuleTag.printTo(Self._Output)
        del RuleTag
              
        del Tok
              
        Self._Parser.NextToken()
            
## A class that handles tabs
class AMarkdownTabBlock(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode == MarkdownOpcode.dlTab:
                Result = Self(**params)
            
        return Result
            
    # Parse the statement
    def parse(Self):
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                
        # Cache the previous token
        previousToken = Self._Parser.PreviousToken().code()
        # Set up whitespace equivalent to a tab length
        whitespace = " " * Self._Language.tabSize()
            
        # Were we just at the end of a line or do we have more than one 
        # consecutive tab?
        if (previousToken == TokenType.endOfLine) or \
          (previousToken == MarkdownOpcode.dlTab):
            # We are in a code block
            CodeBlock = AnXMLWrapperTag("code")
            CodeBlockText = AStringStream()
            PreviousOutput = Self.OutputTo(CodeBlockText)
            
            # Print literals until the end of the line                
            while Self._Parser.Token().code() != TokenType.endOfStream:
                if Self._Parser.Token().code() == TokenType.endOfStream:
                    break
                        
                if Self._Parser.Token().code() != MarkdownOpcode.dlTab:
                    Self._Output.write(Self._Parser.Token().literal())
                    
                else:
                    Self._Output.write(whitespace)
                    
                Self._Parser.NextToken()
                    
                if Self._Parser.Token().code() == TokenType.endOfLine:
                    # Check whether the previous token was the end of line
                    if Self._Parser.PreviousToken().code() == TokenType.endOfLine:
                        # Check whether the next line is indented
                        Tok = Self._Parser.PeekToken()
                        if Tok.code() in (TokenType.space, MarkdownOpcode.dlTab):
                            continue
                        
                        CodeBlock.text = CodeBlockText.toString()
                        del CodeBlockText
                        Self.OutputTo(PreviousOutput)
                        PreBlock = AnXMLWrapperTag("pre")
                        PreBlock["class"] = "quote"
                        PreBlock.text = CodeBlock.toString()
                        del CodeBlock
                        PreBlock.printTo(Self._Output)
                        del PreBlock
                        
                        break
                            
        else:
            # Output the token
            Self._Output.write(whitespace)
            Self._Parser.NextToken()

## A class that handles whitespace
class AMarkdownSpaceBlock(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode == TokenType.space:
                Result = Self(**params)
            
        return Result
            
    ## Parse the statement
    def parse(Self):
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                
        # Cache the previous token
        previousToken = Self._Parser.PreviousToken().code()
        # Cache the amount of whitespace
        whitespace = Self._Parser.Token().literal()
        
        # Get the next token
        Self._Parser.NextToken()
        
        # Are we at the end of a line?
        if Self._Parser.Token().code() == TokenType.endOfLine:
            # Was the token before the whitespace an EOL as well?
            if previousToken == TokenType.endOfLine:
                # A blank line; insert a paragraph mark
                Paragraph = AnXMLWrapperTag("p")
                Paragraph.printTo(Self._Output)
                del Paragraph
                
            # Otherwise, do we have more than one space before the end of line?
            elif len(whitespace) > 1:
                # Insert a line break
                Break = AnXMLTag("br")
                Break.printTo(Self._Output)
                del Break
                
        # Otherwise, simply output the whitespace verbatim
        else:
            Self._Output.write(whitespace)

## A class that handles line breaks
class AMarkdownLineEnding(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode == TokenType.endOfLine:
                Result = Self(**params)
            
        return Result
            
    ## Parse the statement
    def parse(Self):
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                
        # Check to see if this is a postfix header line
        level = Self._Parser.postfixHeaderLevel()
        
        if level != 0:
            HeaderBlock = AnXMLWrapperTag("h" + str(level))
            HeaderBlockText = AStringStream()
            PreviousOutput = Self.OutputTo(HeaderBlockText)
            
            # Parse to the end of the line
            Self._Parser.parseUntil(TokenType.endOfLine)
            
            HeaderBlock.text = HeaderBlockText.toString()
            del HeaderBlockText
            Self.OutputTo(PreviousOutput)
            
            # Construct an anchor for the header line
            HeaderAnchor = AnXMLWrapperTag("a")
            HeaderAnchor["id"] = HeaderBlock.text.replace(" ", "")
            HeaderAnchor.printTo(Self._Output)
            del HeaderAnchor
            
            HeaderBlock.printTo(Self._Output)
            del HeaderBlock
            
        elif Self._Parser.PreviousToken() is not None:
            # Was there more than one line break in a row?
            if Self._Parser.PreviousToken().code() == TokenType.endOfLine:
                # Insert a paragraph break
                Paragraph = AnXMLWrapperTag("p")
                Paragraph.printTo(Self._Output)
                del Paragraph
                
        # Write the token code verbatim
        Self._Output.write(Self._Parser.Token().literal())
        Self._Parser.NextToken()             
        
## A class that handles identifiers
class AMarkdownIdentifier(AMarkdownStatement):
    ## Determine if the class will handle the specified token
    @classmethod
    def handlerFor(Self, tokenCode, **params):
        # Check with subclasses first
        Result = Self.subclassHandlerFor(tokenCode, **params)
        
        if Result is None:        
            if tokenCode == TokenType.identifier:
                Result = Self(**params)
        
        return Result
            
    ## Parse the statement
    def parse(Self):  
        Event = Self.generate("parse")
        if Event.handled():
            del Event
            return
            
        del Event
                 
        # Write the token code verbatim
        Self._Output.write(Self._Parser.Token().literal())
        Self._Parser.NextToken()        
