import sys, re

from .tokens import *

def placeholder(txt):
    return '<<<%s>>>' % (txt,)

class BaseFormat(object):
    text_based = True

SPACES_PAT = re.compile(r'[\n ]+')

class Format(BaseFormat):
    """The base format implements a lossy plaintext display format that serves as reasonable default behavior.

    Formats are stateful, so currently you construct a new one each time
    you parse something.  I'm not sure I like those semantics, though."""

    def __init__(self):
        self.start_of_list = False
        self.start_of_table = False
        self.link_text = None
        self.eat_nl = True

    def text(self, text):
        """Escape special characters in text, intended to be plain text,
        as necessary."""
        if self.eat_nl:
            text = text.lstrip('\n')
            self.eat_nl = False
        text = SPACES_PAT.sub(' ', text)
        # TODO(xavid): I'm not sure I like this hack.
        if self.link_text is not None:
            self.link_text += text
        yield text
    
    def tag(self, t, arg=None):
        if t == BOLD:
            return u'*'
        elif t == ITALIC:
            return u'/'
        elif t == MONOSPACE:
            return u''
        elif t == SUPERSCRIPT:
            return u'^'
        elif t == SUBSCRIPT:
            return u','
        elif t == UNDERLINE:
            return u'_'
        elif t == STRIKE:
            return u'-'
        elif t == CODEBLOCK:
            return u''
        else:
            # Default to doing nothing, it's pretty safe.
            return u''
    LIST_MAP = {ORDERED_ITEM: '#', UNORDERED_ITEM: '*'}
    def start(self, t, arg=None):
        if t in (ORDERED, UNORDERED, BLOCKQUOTE):
            if arg == 1:
                self.start_of_list = True
            yield ''
        elif t in self.LIST_MAP:
            if self.start_of_list:
                start = u''
            else:
                start = u'\n'
            self.start_of_list = False
            yield start + u' ' * arg + self.LIST_MAP[t] + u' '
        elif t == BLOCKQUOTE_LINE:
            if self.start_of_list:
                start = u''
            else:
                start = u'\n'
            self.start_of_list = False
            yield start + u'>' * arg + u' '
        elif t == PARAGRAPH:
            yield ''
        elif t == LINK:
            self.link_text = ''
            yield ''
        elif t == IMAGE:
            yield '['
        elif t == HEADING:
            yield '%s ' % (u'=' * arg)
        elif t == TABLE:
            self.start_of_table = True
            yield u''
        elif t == TABLE_CELL:
            yield u'\t'
        elif t == TABLE_HEADING:
            yield u'\t* '
        elif t == TABLE_ROW:
            if self.start_of_table:
                self.start_of_table = False
                yield u''
            else:
                yield u'\n'
                self.eat_nl = True
        else:
            yield self.tag(t, arg)

    def end(self, t, arg=None):
        if t in (ORDERED, UNORDERED):
            yield ''
        elif t in (ORDERED_ITEM, UNORDERED_ITEM, BLOCKQUOTE_LINE):
            yield ''
        elif t == PARAGRAPH:
            yield ''
        elif t == LINK:
            implicit = arg['url'] == self.link_text and '://' in arg['url']
            self.link_text = None
            if implicit:
                yield u''
            else:
                yield u'@<%s>' % arg['url']
        elif t == IMAGE:
            yield u']'
        elif t == HEADING:
            yield ' %s' % (u'=' * arg)
        elif t == TABLE:
            yield u''
        elif t == TABLE_CELL:
            yield u''
        elif t == TABLE_HEADING:
            yield u' *'
        elif t == TABLE_ROW:
            yield u''
        else:
            yield self.tag(t, arg)

    def entity(self, t, arg=None):
        if t == HRULE:
            yield u'\n%s\n' % (u'-' * 70)
            self.eat_nl = True
        elif t == LINEBREAK:
            yield u'\n'
            self.eat_nl = True
        elif t == ENV_BREAK:
            yield u'\n\n'
            self.eat_nl = True
        elif t == ERROR:
            yield u'!! %s !!' % arg
        elif t == NOINDENT:
            yield u''
        elif t == REF:
            yield placeholder(arg)
        else:
            assert False, t
