#!env python

""" Transcoding moniwiki text to markdown text """

import unittest
import re
import sys
import os
from optparse import OptionParser

def mbstrlen(text, encoding='utf-8'):
    """stlren for a string include multibyte characters."""
    return len(text) + (len(unicode(text, encoding)) - len(text)) / 2

def trans(monitext):
    """Return a markdown text transcoded from the given moniwiki text."""
    result = ''
    last_line = 'empty'

    while monitext:
        # newline character or empty line(s)
        matched = re.match(r'\n+', monitext, re.M)

        if matched:
            result += matched.group()
            if len(matched.group()) > 1:
                last_line = 'empty'
            elif last_line == 'title':
                result += '\n'
                last_line = 'empty'
            monitext = monitext[matched.end():]
            continue

        # code block
        matched = re.match(r'{{{.*?\n((\n|.)*?)\n}}}', monitext, re.M)

        if matched:
            body = matched.groups()[0]
            result += '\n\t' + '\n\t'.join(body.split('\n'))
            monitext = monitext[matched.end():]
            last_line = 'code'
            continue

        # header
        matched = re.match(r'^(=+) (.+) (=+)', monitext)

        if matched:
            title = matched.groups()[1]
            level = len(matched.groups()[0])

            if last_line != 'empty':
                result += '\n'

            if level < 4:
                underscore = {2 : '=', 3 : '-'}[level] * mbstrlen(title)
                result += title + os.linesep + underscore
            else:
                result += ('#' * level) + " " + title
            monitext = monitext[matched.end():]

            last_line = 'title'

            continue

        # link
        matched = re.match(r'(.*)\[([^\s]+[ \t]+)?(.+)\]', monitext)

        if matched:
            pre = matched.groups()[0]
            url = matched.groups()[1]
            if url:
                url = url.strip()
            name = matched.groups()[2]

            if url:
                replaced = "%s[%s](%s)" % (pre, name, url)
            else:
                replaced = "%s[%s](%s)" % (pre, name, name)

            monitext = monitext[:matched.start()] + replaced\
                    + monitext[matched.end():]

        # important
        monitext = re.sub(r'\'\'\'(.*?)\'\'\'', r'**\1**', monitext)

        # italic
        monitext = re.sub(r'\'\'(.*?)\'\'', r'_\1_', monitext)

        # list
        matched = re.match(r'^(\s*)\* (.*)', monitext)

        if matched:
            depth = len(matched.groups()[0])
            body = matched.groups()[1]
            result += (depth - 1) * '\t' + '* ' + body
            monitext = monitext[matched.end():]

        last_line = 'others'

        try:
            # Go to the next line
            index = monitext.index('\n')
            result += monitext[:index]
            monitext = monitext[index:]
        except ValueError:
            result += monitext
            break

    return result

def main():
    """Transcode or test."""

    parser = OptionParser()
    parser.add_option("", "--test", action="store_true", dest="test",
                      default=False, help="Run unittest")
    options, args = parser.parse_args()

    if options.test:
        sys.argv.remove('--test')
        unittest.main()
    else:
        if len(args) > 0:
            text = open(args[0]).read()
        else:
            text = sys.stdin.read()

        sys.stdout.write(trans(text))

class TestClass(unittest.TestCase):
    """Tests runned by --test option."""

    def test_title(self):
        """Test transcoding for headers."""
        self.assertEquals("Title\n=====", trans("== Title =="))
        self.assertEquals("Title\n-----", trans("=== Title ==="))
        self.assertEquals("#### Title", trans("==== Title ===="))
        self.assertEquals("##### Title", trans("===== Title ====="))

    def test_list(self):
        """Test transcoding for list."""
        self.assertEquals("* item", trans(" * item"))
        self.assertEquals("\t* item", trans("  * item"))
        self.assertEquals("\t\t* item", trans("   * item"))

    def test_code(self):
        """Test transcoding for code block."""
        self.assertEquals("\n\tline1\n\tline2",
                          trans("{{{\nline1\nline2\n}}}"))

    def test_link(self):
        """Test transcoding for link."""
        self.assertEquals("[name](name)", trans("[name]"))
        self.assertEquals("[name](http://domain/path/to/resource)",
                          trans("[http://domain/path/to/resource name]"))

    def test_link_in_list(self):
        """Test transcoding for link in list."""
        self.assertEquals("* [name](name)\n* name2\n* name3",
                          trans(" * [name]\n * name2\n * name3"))

    def test_empty_line_before_and_after_title(self):
        """Test transcoding for link in list."""
        self.assertEquals("blahblah\n\n#### title\n\nblahblah",
                          trans("blahblah\n==== title ====\nblahblah"))

        self.assertEquals("blahblah\n\n#### title\n\nblahblah",
                          trans("blahblah\n\n==== title ====\n\nblahblah"))

if __name__ == '__main__':
    main()
