"""
    MoinMoin - Processor for abc format music syntax using abc2ps

    Copyright (c) 2004 by Nathan Whitehead <nwhitehe@cs.ucsc.edu>
    All rights reserved, see COPYING for details.
"""

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

# Set these according to local environment
config_cache_dir='/cse/grads/nwhitehe/.html/wiki/abcps'
config_cache_url=config.url_prefix+'abcps'
config_tmp_dir='/tmp'
config_external_abc2ps='/cse/grads/nwhitehe/bin/abcm2ps'
config_external_pstopnm='/usr/local/bin/pstopnm'
config_external_gs='/usr/local/gnu/bin/gs'
config_external_pnmcat='/usr/local/bin/pnmcat'
config_external_pnmcrop='/usr/local/bin/pnmcrop'
config_external_abc2midi='/cse/grads/nwhitehe/bin/abc2midi'

# Use png or gif?
config_use_gif=1
config_external_rasterize='/usr/local/bin/ppmtogif'
config_external_gzip='/usr/local/gnu/bin/gzip'
config_score_orientation='-tb' # or -lr for horizontal
# Serve and store scores gzipped to save space?
config_zip_scores=0

# Cut off hash to this many characters for user friendliness
hash_length = 6
# Show code in HTML page by default?
show_code = 1
# Generate PNG graphics of each page? (slow and memory intensive for server)
show_score = 1
# Show an embedded MIDI controller for playing the song?
show_midi = 1
# Syntax highlighting colors for ABC code
header_color = '#6000a0'
info_color = '#006000'
note_color = '#000000'
bar_color = '#ff0000'
continues_color = '#ff00ff'
comment_color = '#ff5050'
chord_color = '#808080'

def quote_apply(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(c, txt):
    """Make text appear the given ascii color"""
    return '<font color="' + c + '">' + txt + '</font>'

def colorize_line(txt):
    # If it is header, color it and we're done
    if len(txt) >= 2 and txt[1] == ':':
        return color_txt(header_color, txt[:2]) + color_txt(info_color, txt[2:])
    # If it is comment, color and we're done
    if len(txt) >= 1 and txt[0] == '%':
        return color_txt(comment_color, txt)
    # Color quotations (chords) first, otherwise
    # we will get more quotes from font tags later.
    def give_chord_color(txt):
        return color_txt(chord_color, txt)
    txt = quote_apply(give_chord_color, txt)
    txt = txt.replace('|', color_txt(bar_color, '|'))
    txt = txt.replace('\\', color_txt(continues_color, '\\'))
    return color_txt(note_color, txt)

def colorize(lines):
    """Do rudimentary syntax highlighting of ABC music in HTML"""
    # Do it line by line
    clines = map(colorize_line, lines)
    return string.join(clines, '\n')

def get_title(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(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(lines):
    global show_code
    global show_score
    if len(lines) > 0:
        stripline0 = string.strip(lines[0])
        if stripline0 == "#!AbcMusic":
            del lines[0]
            process_arguments(lines)
        if stripline0 == "#show-code-off":
            del lines[0]
            show_code = 0
            process_arguments(lines)
        if stripline0 == "#show-code-on":
            del lines[0]
            show_code = 1
            process_arguments(lines)
        if stripline0 == "#show-score-off":
            del lines[0]
            show_score = 0
            process_arguments(lines)
        if stripline0 == "#show-score-on":
            del lines[0]
            show_score = 1
            process_arguments(lines)
    return

def process(request, formatter, lines):
    global show_code
    # Preprocessing stage
    process_arguments(lines)
    title = get_title(lines)
    texstr = string.join(lines, '\n')
    texstr = string.strip(texstr)
    hash = sha.new(texstr).hexdigest()[:hash_length]
    name = cleanup(title) + '_' + hash

    filepath = "%s/%s" % (config_cache_dir, name)
    urlpath = "%s/%s" % (config_cache_url, name)

    if 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 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" : config_tmp_dir,
            "abc2ps": 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 config_zip_scores:
            cmd = "%(gzip)s %(file)s 2> /dev/null" % {
                "gzip" : 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 show_score:
        # delete any old stuff
        cmd = 'rm -f %s/%s*.ppm' % (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" : config_tmp_dir,
            "gs" : 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" : config_tmp_dir,
            "pnmcat" : config_external_pnmcat,
            "orientation" : config_score_orientation,
            "name" : name,
            "pnmcrop" : config_external_pnmcrop,
            "rasterize" : 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" : config_tmp_dir,
            "abc2midi": 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 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(abcurl, text="ABC source file"))
    request.write(formatter.linebreak(preformatted=0))
    request.write(formatter.url(psurl, text="PostScript score"))
    request.write(formatter.linebreak(preformatted=0))
    request.write(formatter.url(midiurl, text="MIDI rendition"))
    request.write(formatter.linebreak(preformatted=0))
    request.write(formatter.url(logurl, text="Compilation log"))
    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 show_score:
        request.write(formatter.table_row(1))
        request.write(formatter.table_cell(1))
        request.write(formatter.url(pngurl))
        request.write(formatter.table_cell(0))
        request.write(formatter.table_row(0))
        
    if show_code:
        request.write(formatter.table_row(1))
        request.write(formatter.table_cell(1))
        request.write(formatter.preformatted(1))
        request.write(formatter.rawHTML(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))
