#!/usr/bin/python3
#-*- coding:utf-8 -*-

#    Pybik -- A 3 dimensional magic cube game.
#    Copyright © 2009, 2011-2013  B. Clausius <barcc@gmx.de>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.


import sys, os, re

class Py2pyxParseError (Exception): pass


def main(argv):
    if not (1 < len(argv) <= 4):
        print('usage:', os.path.basename(__file__), 'python-file [pyx-filename [pxd-filename]]',
            file=sys.stderr)
        return 1
        
    arg_src = argv[1]
    arg_dst = argv[2] if len(argv) > 2 else None
    arg_pxd = argv[3] if len(argv) > 3 else None
    if not os.path.exists(arg_src):
        print('error:', arg_src, 'does not exist', file=sys.stderr)
        return 1
    create_pyx(arg_src, arg_dst, arg_pxd)
    return 0
    
def create_pyx(src_path, dst_path, pxd_path):
    errors = 0
    openr = lambda path: open(path, 'rt', encoding='utf-8')
    openw = lambda path: open(path, 'wt', encoding='utf-8') if path else sys.stdout
    edit_lines = None
    
    copy = lambda lineno, match: (match.string, None, None)
    add = lambda lineno, match: (match.expand(r'\1\4 \2\n'), None, None)
    def remove(unused_lineno, match):
        count = match.group(4)
        count = 1 if count == '' else int(count)
        return match.expand(r'\1#px \2\4\n'), None, [count, r'\1#px \2\4\n', None]
    replace = lambda lineno, match: (match.expand(r'\1\4 \2\n'), None, [1, r'\1#px \2\4\n', None])
    comment = lambda lineno, match: (match.expand(r'\1\2\4\n'), None, None)
    def repl_pxd(lineno, match):
        return (match.expand(r'\1\4 \2\n'),
                match.expand(r'\1\4').rstrip(':') + '    #line {}\n'.format(lineno),
                [1, r'\1#px \2\4\n', None])
    def move_pxd(unused_lineno, match):
        count = match.group(4)
        count = 1 if count == '' else int(count)
        return match.expand(r'\1#px \2\4\n'), None, [count, r'\1#px \2\4\n', r'\1\4\n']
    fdict = {None:copy, '+':add, '-':remove, '/':replace, ' ':comment,
             #'d ':pxd, 'd+':add_pxd,
             'd/':repl_pxd, 'd=':move_pxd}
    
    with openr(src_path) as srcf, openw(dst_path) as dstf, openw(pxd_path) as pxdf:
        pxdf.write('#file: {}\n\n'.format(src_path))
        for lineno, line in enumerate(srcf):
            try:
                match = re.match(r'^( *)(#px(d.|.)|)(.*?)\n$', line)
                if edit_lines is not None and edit_lines[0] > 0:
                    cnt_edit_lines, edit_re_pyxline, edit_re_pxdline = edit_lines
                    pyxline = edit_re_pyxline and match.expand(edit_re_pyxline)
                    pxdline = edit_re_pxdline and (match.expand(edit_re_pxdline).rstrip() + '    #line {}\n'.format(lineno))
                    edit_lines[0] -= 1
                    continue
                pyxline, pxdline, edit_lines = fdict[match.group(3)](lineno, match)
            except Exception as e:
                print('%s:%d:'%(src_path, lineno), e, file=sys.stderr)
                print('  Invalid line:', line, file=sys.stderr, end='')
                pyxline = line
                pxdline = None
                errors += 1
            finally:
                dstf.write(pyxline)
                if pxdline is not None:
                    pxdf.write(pxdline)
    if errors:
        raise Py2pyxParseError('create_pyx failed with %s errors' % errors)
        
    
if __name__ == '__main__':
    sys.exit(main(sys.argv))
    

