#!/usr/bin/env python
# sakana2moin.py
# by dan sandler <dan.sandler /at/ gmail DOTCOM>
# converts sakana wikipages into moin wikipage files
# usage: sakana2moin.py <srcdir> <destdir>
# version: 0.1

import sys, os, re, time

from MoinMoin import wikiutil

class Translator:
    indentstring = '    '
    indentlength = len(indentstring)
    def __init__(self,OUT):
        self._out = OUT
        self._inlist = 0
        self._indent = ""
        self._newline = 1
        self._preformatted = 0
    def indent(self):
        self._indent = self._indent + Translator.indentstring
    def outdent(self):
        self._indent = self._indent[Translator.indentlength:]
    def output(self, s):
        if self._newline:
            self._out.write(self._indent)
            self._newline = 0
        if re.search('\n', s):
            self._newline = 1
        self._out.write(s)
    def translate(self, IN):
        self._in = IN
        while 1:
            line = self._in.readline()
            if line == '': break
            if self._preformatted:
                line = re.sub(r'\n+$', '', line)
            else:
                line = line.strip()

            # full-line macros
            m = re.search(r'{list}', line)
            if m:
                self._inlist += 1
                self.indent() ; continue

            m = re.search(r'{/list}', line)
            if m:
                self._inlist -= 1
                self.outdent() ; continue

            # full-line macros with possible internal text

            postfix = '\n'
            m = re.search(r'^@\s*(.*)$', line)
            if m:
                line = m.group(1)
                postfix = ' =\n'
                self.output("= ")

            m = re.search(r'^-\s*(.*)$', line)
            if m:
                line = m.group(1)
                if self._inlist:
                    self.output("* ")
                else:
                    # I feel like sakana's - operator is more like a H3 than a
                    # H2 ... is that just me?
                    postfix = " ===\n"
                    self.output("=== ")

            # inline formatters

            chunked = re.split(r'({[^}]*})', line)
            for chunk in chunked:
                if len(chunk) > 0 \
                and chunk[0] == '{' and chunk[-1] == '}':
                    tag = chunk[1:-1]

                    if tag in ('code','text'):
                        self.output("{{{\n")
                        self._preformatted += 1
                        continue

                    if tag in ('/code','/text'):
                        self.output("}}}\n")
                        self._preformatted -= 1
                        continue

                    m = re.search(r'^(part|quote)(.*)$', tag)
                    if m:
                        if m.group(1) == "quote" and m.group(2).startswith("|"):
                            pagename = m.group(2)[1:]
                            if pagename.startswith("(user)"):
                                pagename = pagename[len("(user)"):]
                            self.output("""''Quote from ["%s"]:''"""
                                % pagename)
                        self.indent()
                        self.output("\n") #start the indent
                        continue

                    if tag in ('/part','/quote'):
                        self.outdent()
                        continue

                    if tag == 'b' or tag == 'strong' \
                    or tag == '/b' or tag == '/strong':
                        self.output("'''")
                        continue
                    
                    if tag == 'i' or tag == 'em' \
                    or tag == '/i' or tag == '/em':
                        self.output("''")
                        continue
                    
                    if tag == 'tt' or tag == '/tt':
                        self.output("`")
                        if tag == 'tt':
                            self._preformatted += 1
                        else: self._preformatted -= 1
                        continue
                    
                    if tag == 'hr':
                        self.output("----")
                        continue
                    
                    if tag == 'br':
                        self.output("[[BR]]")
                        continue

                    m = re.search(r'^verb\|(.*)$', tag)
                    if m:
                        self.output("[[HTML(%s)]]" % m.group(1))
                        continue

                    m = re.search(r'^(eroom|change|bug)\|(.*)$', tag)
                    if m:
                        if m.group(1) == "eroom":
                            func = "ERoom"
                        elif m.group(1) == "change":
                            func = "Change"
                        elif m.group(1) == "bug":
                            func="Bug"

                        m2 = re.search(r'^(.*)\|(.*)', m.group(2))
                        if m2:
                            page = m2.group(1)
                            name = ',' + m2.group(2)
                        else:
                            page = m.group(2)
                            name = ''
                        self.output("[[%s(%s%s)]]" % (func, page, name))
                        continue

                    m = re.search(r'^page\|(.*)$', tag)
                    if m:
                        m2 = re.search(r'^(.*)\|(.*)', m.group(1))
                        if m2:
                            page = m2.group(1)
                            name = m2.group(2)
                        else:
                            page = m.group(1)
                            name = ''
                        self.output("[:%s:%s]" % (page, name))
                        continue

                    m = re.search(r'^link\|(.*)$', tag)
                    if m:
                        m2 = re.search(r'^(.*)\|(.*)', m.group(1))
                        if m2:
                            page = m2.group(1)
                            name = ' ' + m2.group(2)
                        else:
                            page = m.group(1)
                            name = ''
                        self.output("[%s%s]" % (page, name))
                        continue

                    self.output('`[Unknown macro: %s]`' % chunk)

                else:
                    # blocks of text
                    # must substitute [OtherPage]
                    pagelink_chunks = re.split(r'(\[[^\]]*\])', chunk)
                    for subchunk in pagelink_chunks:
                        if len(subchunk) > 2 \
                        and subchunk[0] == '[' and subchunk[-1] == ']':
                            # OK, special pages!
                            page = subchunk[1:-1]
                            m = re.match(r'\(user\)(.*)$', page)
                            if m: page = m.group(1) #users are regular pages
                            self.output('["%s"]'% page)
                        else:
                            # finally, text with no tags or ANYTHING.
                            self.output(re.sub(r'\\', '', subchunk))

            self.output(postfix)

def dehexify(s):
    name=""
    for i in range(0,len(s),2):
        name += ("%c" % int(s[i:i+2], 16))
    return name

def hexify(name):
    s=''
    for c in name:
        s += ("%x" % ord(c))
    return s

class Snip:
    def __init__(self, srcdir, name):
        self.srcdir = srcdir
        self.name = name
        filepath = os.path.join(srcdir, hexify(name))
        self.info = eval(open(filepath+':meta').read())
        if not self.name == self.info["name"]:
            raise "names not consistent: '%s', '%s'" \
                % (self.name, self.info['name'])
        self.datafile = filepath+':data'

    def appendToMoinStream(self, outfile):
        t = Translator(outfile)
        text = open(self.datafile)
        t.translate(text)

        # now, append any notes
        
        try:
            emitted_hdr = 0
            for note in self.info["notes"]:
                noteSnip = Snip(self.srcdir, note)
                print "    note: %s <%s>" % (self.name, self.datafile)
                if not emitted_hdr:
                    outfile.write("== Comments ==\n")
                    emitted_hdr = 1
                else:
                    outfile.write("----\n")
                noteSnip.appendToMoinStream(outfile)
                outfile.write("""''  -- ["%s"] at %s''\n""" % (
                    noteSnip.info["created_by"][len("(user)"):],
                    time.strftime("%X %x",
                        time.localtime(noteSnip.info['created_at']))
                    ))
        except KeyError: pass

    def toMoin(self, destdir):
        moin_name = self.name
        if moin_name.startswith("(user)"):
            moin_name = moin_name[len("(user)"):]

        # MoinMoin has its own bizarre ideas about how to encode file names
        moin_name = wikiutil.quoteFilename(moin_name)

        print "page: %s <%s>" % (self.name, self.datafile)

        self.appendToMoinStream(open(os.path.join(destdir, moin_name),'w'))

if __name__ == '__main__':
    if len(sys.argv) < 3:
        print "usage: sakana2moin.py <srcdir> <destdir>"
        sys.exit(1)

    srcdir = sys.argv[1]
    destdir = sys.argv[2]

    srcfiles = os.listdir(srcdir)
    for fn in srcfiles:
        if fn.endswith(":data"):
            try:
                #fp = open(os.path.join(srcdir,fn[:-5]+':meta'))
                #text = fp.read()
                #exec("info = " + text) # eww! thanks, swetland
                #pagename = info["name"]
    
                fn = fn[:-5]
                pagename = dehexify(fn)

                if pagename.startswith("(note)"):
                    # it will be processed with its parent page
                    continue
                elif pagename.startswith("(meta)") \
                or pagename.startswith("(topic)"):
                    print "warning: skipping '%s' (can't handle meta/topic snips)" % pagename
                    continue

                Snip(srcdir, pagename).toMoin(destdir)

            finally:
                pass

# vim: ft=python ts=4 sts=4 sw=4 expandtab:
