"""
    MoinMoin Processor for abc format music syntax using abcm2ps, abc2midi

    Copyright (c) 2004 by Nathan Whitehead <nwhitehe *at* cs.ucsc.edu>
    All rights reserved, see COPYING for details. (GPL)
"""
Dependencies = ["time"]

import string, sys, os, re, sha
from MoinMoin import config
    

class Parser:
    """ a noop parser """

    def __init__(self, raw, request, **kw):
        
        self.raw = raw
        self.request = request

        # save call arguments for later use in format
        
        # Set these according to local environment
        self.config_cache_dir='/home/nico/public_html/lakisawiki-666/abcps'
        
        self.config_cache_url=self.request.cfg.url_prefix+'/abcps'
        
        self.config_tmp_dir='/tmp'
        
        self.config_external_abc2ps='/usr/bin/abcm2ps'
        self.config_external_pstopnm='/usr/bin/pstopnm'
        self.config_external_gs='/usr/bin/gs'
        self.config_external_pnmcat='/usr/bin/pnmcat'
        self.config_external_pnmcrop='/usr/bin/pnmcrop'
        self.config_external_abc2midi='/usr/bin/abc2midi'
        
        # Use png or gif?
        self.config_use_gif=0
        self.config_external_rasterize='/usr/bin/ppmtogif'
        self.config_external_gzip='/bin/gzip'
        self.config_score_orientation='-tb' # or -lr for horizontal
        # Serve and store scores gzipped to save space?
        self.config_zip_scores=0
        # Cut off hash to this many characters for user friendliness
        self.hash_length = 6
        # Show code in HTML page by default?
        self.show_code = 1
        # Generate PNG graphics of each page? (slow and memory intensive for server)
        self.show_score = 1
        # Show an embedded MIDI controller for playing the song?
        self.show_midi = 1
        # Syntax highlighting colors for ABC code
        self.header_color = '#6000a0'
        self.info_color = '#006000'
        self.note_color = '#000000'
        self.bar_color = '#ff0000'
        self.continues_color = '#ff00ff'
        self.comment_color = '#ff5050'
        self.chord_color = '#808080'

        
    def format(self, formatter):
        # this has the function of the old processor method
        # just use self.raw and self.request
        self.process(self.request, formatter, self.raw.split("\n"))
        #self.process(self.request, formatter, self.raw)
        #self.request.write(self.raw)
    
    
    def quote_apply(self, f, txt):
        """Apply a given function on text to all quotations in a string"""
        # This is harder than it sounds because replacement text may have quotes
        qi = txt.find('"')
        while not qi == -1:
            qi2 = txt.find('"', qi + 1)
            if not qi2 == -1:
                newtext = f(txt[qi:qi2 + 1])
                txt = txt[:qi] + newtext + txt[qi2 + 1:]
                lenincr = len(newtext) - (qi2 - qi)
                qi = txt.find('"', qi2 + lenincr)
            else:
                qi = -1
        return txt
    
    def color_txt(self, c, txt):
        """Make text appear the given ascii color"""
        return '<font color="' + c + '">' + txt + '</font>'
    
    def colorize_line(self, txt):
        # If it is header, color it and we're done
        if len(txt) >= 2 and txt[1] == ':':
            return self.color_txt(self.header_color, txt[:2]) + self.color_txt(self.info_color, txt[2:])
        # If it is comment, color and we're done
        if len(txt) >= 1 and txt[0] == '%':
            return self.color_txt(self.comment_color, txt)
        # Color quotations (chords) first, otherwise
        # we will get more quotes from font tags later.
        def give_chord_color(txt):
            return self.color_txt(self.chord_color, txt)
        txt = self.quote_apply(give_chord_color, txt)
        txt = txt.replace('|', self.color_txt(self.bar_color, '|'))
        txt = txt.replace('\\', self.color_txt(self.continues_color, '\\'))
        return self.color_txt(self.note_color, txt)
    
    def colorize(self, lines):
        """Do rudimentary syntax highlighting of ABC music in HTML"""
        # Do it line by line
        clines = map(self.colorize_line, lines)
        return string.join(clines, '\n')
    
    def get_title(self, lines):
        """Return the title string, if it exists"""
        for l in lines:
            if len(l) >= 2 and l[0] == 'T' and l[1] == ':':
                return l[2:]
        return "(Untitled)"
    
    def cleanup(self, txt):
        """Scrub a title so it may be used in a filename"""
        # Old way, txt.replace(' ', '_').replace('(', '').replace(')', '')
        res = ""
        for x in txt:
            if x.isalnum():
                res = res + x
            if x == ' ':
                res = res + '_'
        return res
    
    def process_arguments(self, lines):
        global show_code
        global show_score
        if len(lines) > 0:
            stripline0 = string.strip(lines[0])
            if stripline0 == "#!AbcMusic":
                del lines[0]
                self.process_arguments(lines)
            if stripline0 == "#show-code-off":
                del lines[0]
                show_code = 0
                self.process_arguments(lines)
            if stripline0 == "#show-code-on":
                del lines[0]
                show_code = 1
                self.process_arguments(lines)
            if stripline0 == "#show-score-off":
                del lines[0]
                show_score = 0
                self.process_arguments(lines)
            if stripline0 == "#show-score-on":
                del lines[0]
                show_score = 1
                self.process_arguments(lines)
        return
    
    def process(self, request, formatter, lines):
        
        
        global show_code
        # Preprocessing stage
        self.process_arguments(lines)
        title = self.get_title(lines)
        texstr = string.join(lines, '\n')
        texstr = string.strip(texstr)
        hash = sha.new(texstr).hexdigest()[:self.hash_length]
        name = self.cleanup(title) + '_' + hash
    
        filepath = "%s/%s" % (self.config_cache_dir, name)
        urlpath = "%s/%s" % (self.config_cache_url, name)
    
        if self.config_use_gif:
            suffix = ".gif"
        else:
            suffix = ".png"
        abcpath = filepath + ".abc"
        pspath = filepath + ".ps"
        psgzpath = filepath + ".ps.gz"
        pngpath = filepath + suffix
        logpath = filepath + ".log"
        midipath = filepath + ".mid"
        abcurl = urlpath + ".abc"
        if self.config_zip_scores:
            psurl = urlpath + ".ps.gz"
        else:
            psurl = urlpath + ".ps"
        pngurl = urlpath + suffix
        logurl = urlpath + ".log"
        midiurl = urlpath + ".mid"
    
        # Delete logfile
        os.system("rm -f %s" % logpath)
    
        # Generate PS
        if not os.path.exists(pspath):
            data = open(abcpath, "w")
            data.write('%s' % texstr)
            data.close()
            
            options = "-e 1"
            cmd = "cd %(workingdir)s ; %(abc2ps)s %(options)s -O %(outfile)s %(infile)s >> %(logfile)s 2>&1" % {
                "workingdir" : self.config_tmp_dir,
                "abc2ps": self.config_external_abc2ps,
                "options": options,
                "outfile" : pspath,
                "infile": abcpath,
                "logfile": logpath
                }
            os.system(cmd)
            os.system("chmod 644 " + pspath)
            os.system("chmod 644 " + abcpath)
            if self.config_zip_scores:
                cmd = "%(gzip)s %(file)s 2> /dev/null" % {
                    "gzip" : self.config_external_gzip,
                    "file" : pspath
                    }
                os.system(cmd)
                os.system("chmod 644 " + psgzpath)
            os.system("chmod 644 " + logpath)
    
        # Generate PNG
        if (not os.path.exists(pngpath)) and self.show_score:
            # delete any old stuff
            cmd = 'rm -f %s/%s*.ppm' % (self.config_tmp_dir, name)
            os.system(cmd)
    
            # Use ghostscript to convert ps to pnm files
            options = "-dNOPAUSE -q -dBATCH -sPAPERSIZE=letter -sDEVICE=ppmraw -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -r120x120 -sOutputFile=%s%%003d.ppm" % name
            cmd = 'cd %(workingdir)s ; %(gs)s %(options)s %(infile)s > /dev/null 2>&1' % {
                "workingdir" : self.config_tmp_dir,
                "gs" : self.config_external_gs,
                "options" : options,
                "infile" : pspath
                }
            os.system(cmd)
            
            # Concatenate pnm files into one file
            cmd = 'cd %(workingdir)s ; %(pnmcat)s %(orientation)s %(name)s*.ppm 2> /dev/null | %(pnmcrop)s 2> /dev/null | %(rasterize)s > %(outfile)s 2> /dev/null' % {
                "workingdir" : self.config_tmp_dir,
                "pnmcat" : self.config_external_pnmcat,
                "orientation" : self.config_score_orientation,
                "name" : name,
                "pnmcrop" : self.config_external_pnmcrop,
                "rasterize" : self.config_external_rasterize,
                "outfile" : pngpath
                }
            os.system(cmd)
            os.system("chmod 644 " + pngpath)
    
        # Generate MIDI file
        if not os.path.exists(midipath):
            data = open(abcpath, "w")
            data.write('%s' % texstr)
            data.close()
            
            options = ""
            cmd = "cd %(workingdir)s ; %(abc2midi)s %(infile)s %(options)s -o %(outfile)s >> %(logfile)s 2>&1" % {
                "workingdir" : self.config_tmp_dir,
                "abc2midi": self.config_external_abc2midi,
                "options": options,
                "outfile" : midipath,
                "infile": abcpath,
                "logfile": logpath
                }
            os.system(cmd)
            os.system("chmod 644 " + midipath)
            os.system("chmod 644 " + abcpath)
            os.system("chmod 644 " + logpath)
    
        # Clean up junk (unzipped score if using zipped scores)
        if self.config_zip_scores:
            os.system("rm -f " + pspath)
    
        # Generate page
        #    if show_code or show_score:
        request.write(formatter.paragraph(1))
        request.write(formatter.table(1))
        
        request.write(formatter.table_row(1))
        request.write(formatter.table_cell(1))
        request.write(formatter.paragraph(1))
        request.write(formatter.strong(1))
        request.write(formatter.emphasis(1))
        request.write(formatter.text(title))
        request.write(formatter.emphasis(0))
        request.write(formatter.strong(0))
        request.write(formatter.linebreak(preformatted=0))
        request.write(formatter.url(1, abcurl))
        request.write("ABC source file")
        request.write(formatter.url(0))
        request.write(formatter.linebreak(preformatted=0))
        request.write(formatter.url(1, psurl))
        request.write("PostScript score")
        request.write(formatter.url(0))
        request.write(formatter.linebreak(preformatted=0))
        request.write(formatter.url(1, midiurl))
        request.write("MIDI rendition")
        request.write(formatter.url(0))
        request.write(formatter.linebreak(preformatted=0))
        request.write(formatter.url(1, logurl))
        request.write("Compilation log")
        request.write(formatter.url(0))
        request.write(formatter.paragraph(0))
        request.write(formatter.table_cell(0))
        request.write(formatter.table_row(0))
        
        if 0:#show_midi:
            request.write(formatter.table_row(1))
            request.write(formatter.table_cell(1))
            request.write(formatter.preformatted(1))
            request.write(formatter.rawHTML("<embed src=%s width=120 height=40 align=center>" % midiurl))
            request.write(formatter.preformatted(0))
            request.write(formatter.table_cell(0))
            request.write(formatter.table_row(0))
    
        if self.show_score:
            request.write(formatter.table_row(1))
            request.write(formatter.table_cell(1))
            request.write(formatter.rawHTML("<img src=%s>"%pngurl))
            request.write(formatter.table_cell(0))
            request.write(formatter.table_row(0))
            
        if self.show_code:
            request.write(formatter.table_row(1))
            request.write(formatter.table_cell(1))
            request.write(formatter.preformatted(1))
            request.write(formatter.rawHTML(self.colorize(lines)))
            request.write(formatter.preformatted(0))
            request.write(formatter.table_cell(0))
            request.write(formatter.table_row(0))
    
        request.write(formatter.table(0))
        request.write(formatter.paragraph(0))
    
        # Old way with just one link
        #request.write(formatter.url(psurl, text=title))