#!/usr/bin/env python
# update-snippets.py

# USAGE:  update-snippets.py REFERENCE-DIR TARGET-DIR FILES
#
# update ly snippets in TARGET-DIR/FILES with snippets from REFERENCE-DIR/FILES
#
# More precisely, each existing FILE in TARGET-DIR is matched to the FILE in
# REFERENCE-DIR (it the latter does not exist, a warning is given).
#
# Shell wildcards expansion is performed on FILES.
# This script currently supports Texinfo format.
# Ly snippets preceded with a line containing '@c KEEP LY' in TARGET-DIR/FILES
# will not be updated.
# An error occurs if REFERENCE-DIR/FILE and TARGET-DIR/FILE do not have the
# same snippets count.

import sys
import os
import glob
import re

print "update-snippets.py"

comment_re = re.compile (r'(?<!@)(@c(?:omment)? .*?\n|^@ignore\n.*?\n@end ignore\n)', re.M | re.S)
snippet_re = re.compile (r'^(@lilypond(?:file)?(?:\[.*?\])?\s*\{.+?\}|@lilypond(?:\[.*?\])?(?:.|\n)+?@end lilypond)', re.M)


def snippet_split (l):
    r = []
    for s in [s for s in l if s]:
        if s.startswith ('@c ') or s.startswith ('@ignore\n') or s.startswith ('@comment '):
            r.append(s)
        else:
            r += [t for t in snippet_re.split (s) if t]
    return r

def count_snippet (l):
    k = 0
    for s in l:
        if s.startswith ('@lilypond'):
            k += 1
    return k

def find_next_snippet (l, k):
    while not l[k].startswith ('@lilypond'):
        k += 1
    return k

exit_code = 0

def update_exit_code (code):
    global exit_code
    exit_code = max (code, exit_code)

ref_dir, target_dir = sys.argv [1:3]
file_patterns = sys.argv[3:]

total_snippet_count = 0
changed_snippets_count = 0

for pattern in file_patterns:
    files = glob.glob (os.path.join (target_dir, pattern))
    for file in files:
        ref_file = os.path.join (ref_dir, os.path.basename (file))
        if not os.path.isfile (ref_file):
            sys.stderr.write ("Warning: %s: no such file.\nReference file for %s not found.\n" % (ref_file, file))
            continue
        f = open (file, 'r')
        target_source = comment_re.split (f.read ())
        f.close ()
        if reduce (lambda x, y: x or y, ['-- SKELETON FILE --' in s for s in target_source]):
            sys.stderr.write ("Skipping skeleton file %s\n" % file)
            continue
        g = open (ref_file, 'r')
        ref_source = comment_re.split (g.read ())
        target_source = snippet_split (target_source)
        ref_source = snippet_split (ref_source)
        if '' in target_source or '' in ref_source:
            raise "AAAAARGH: unuseful empty string"
        snippet_count = count_snippet (target_source)
        if not snippet_count == count_snippet (ref_source):
            update_exit_code (1)
            sys.stderr.write ("Error: %s and %s have different snippet counts.\n\
Update translation by at least adding a @lilypond block where necessary, then rerun this script.\n" % (ref_file, file))
            continue
        total_snippet_count += snippet_count
        c = 0
        k = -1
        for j in range (len (target_source)):
            if target_source[j].startswith ('@lilypond'):
                k = find_next_snippet (ref_source, k+1)
                if j > 0 and (not target_source[j-1].startswith ('@c KEEP LY')) and target_source[j] != ref_source[k]:
                    target_source[j] = ref_source[k]
                    c += 1
                    changed_snippets_count += 1
        f = open (file, 'w')
        f.write (''.join (target_source))
        sys.stderr.write ('%s: %d/%d snippets updated\n' % (file, c, snippet_count))

sys.stderr.write ('\nTotal: %d snippets, %d updated snippets.\n' % (total_snippet_count, changed_snippets_count))
sys.exit (exit_code)
