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

#  Copyright © 2012-2015  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
sys.path.insert(0, '.')
import re
from textwrap import fill, wrap

from pybiklib import config

try:
    _
except NameError:
    import builtins
    builtins.__dict__['_'] = lambda s: s

footnote_first_idx = 1

def underline(title, underline_char='='):
    return '{}\n{}'.format(title, underline_char*len(title))

def clean_links(text):
    global footnote_first_idx
    footnote_cur_idx = 0
    footnotes = []
    def add_footnote(match):
        nonlocal footnote_cur_idx
        if match.group(2) != '|':
            return match.group(0)
        elif match.group(1) != '':
            footnote = match.group(1)
            if footnote in footnotes:
                footnote_cur_idx = footnotes.index(footnote) + footnote_first_idx
            else:
                footnote_cur_idx = len(footnotes) + footnote_first_idx
                footnotes.append(footnote)
            return ''
        else:
            return ' [{}]'.format(footnote_cur_idx)
    text = re.sub(r'<(.*?)(\|?)>', add_footnote, text)
    footnotes = ['[{}] <{}>'.format(i+footnote_first_idx, footnote) for i, footnote in enumerate(footnotes)]
    footnote_first_idx += len(footnotes)
    return text, footnotes
    
def wrap_deb(text):
    for line in text.splitlines():
        if line:
            if line.startswith(('* ', ' ')):
                yield from wrap(line, width=78, initial_indent=' ', subsequent_indent='   ')
            else:
                yield from wrap(line, width=78)
        else:
            yield '.'
            
            
class TemplateStr (str):
    __slots__ = ()
    linefmt = None
    delimiters = None
    footnotes = []
    mark = ''
    
    @classmethod
    def reset(cls):
        cls.linefmt = None
        cls.delimiters = None
        cls.footnotes.clear()
        cls.mark = ''
        
    def __format__(self, fmt):
        if fmt == 'line':
            text = self
            fmt = self.linefmt
            self.__class__.linefmt = None
        elif self == '#':
            self.__class__.linefmt = fmt
            return ''
        elif self == '#delimiters':
            delims = fmt.split()
            if delims:
                if len(delims) != 2:
                    raise IndexError('wrong count of delimiters: '+fmt)
                self.__class__.delimiters = re.escape(delims[0]) + r'(.*?)' + re.escape(delims[1]), r'{\1}'
            else:
                self.__class__.delimiters = None
            return ''
        elif self == '#footnotes':
            if not self.footnotes:
                return ''
            text = '\n' + '\n'.join(self.footnotes) + '\n'
            self.__class__.footnotes.clear()
            return text
        elif self == '#mark':
            self.__class__.mark = fmt
            return ''
        else:
            text = getattr(config, self)
            if callable(text):
                text = text()
        if not fmt:
            return text
        for s in fmt.split('.'):
            if s == 'wrap':
                text = '\n\n'.join(fill(t, width=78) for t in text.split('\n\n'))
            elif s == 'wrap_deb':
                text = '\n '.join(wrap_deb(text))
            elif s == 'links':
                text, footnotes = clean_links(text)
                self.__class__.footnotes += footnotes
            elif s == 'join':
                if isinstance(text, (tuple, list)):
                    text = '\n'.join(text)
                else:
                    text = text.replace('\n\n', '  ').replace('\n', ' ')
            else:
                raise ValueError('unknown format: ' + fmt)
        return text
        
        
class TemplateKeyDict (dict):
    __slots__ = ()
    def __getitem__(self, key):
        if key and key[0] in ["'", '"']:
            import ast
            return TemplateStr(ast.literal_eval(key))
        return TemplateStr(key)
        
        
def get_template_filename(templatename):
    if templatename == os.path.basename(templatename):
        templatename = os.path.join(config.appdata_dir, 'templates', templatename)
    templatename += '.in'
    return templatename
    
def create_doc(templatename, filename=None, *, skip=None):
    global footnote_first_idx
    footnote_first_idx = 1
    if not filename:
        filename = templatename
    templatename = get_template_filename(templatename)
    with open(templatename, 'rt', encoding='utf-8') as f:
        template = f.readlines()
    text = ''
    prev_linelen = None
    skipstate = 0
    TemplateStr.reset()
    for lineno, line in enumerate(template):
        line = line.rstrip()
        if skip == line:
            skipstate = 1
            continue
        elif skipstate == 3:
            skipstate = 0
        elif skipstate:
            skipstate = 1 if line else skipstate+1
            continue
        if prev_linelen is not None and 3 <= len(line) == line.count(line[0]):
            line = line[0] * prev_linelen
        else:
            if TemplateStr.delimiters is not None:
                line = line.replace('{','{{').replace('}','}}')
                pattern, replace = TemplateStr.delimiters
                line = re.sub(pattern, replace, line)
            try:
                line = line.format_map(TemplateKeyDict())
                line = format(TemplateStr(line), 'line')
            except Exception as e:
                print('{}:{}: {}'.format(templatename, lineno+1, e))
                print('   ', line, end='')
                raise
            prev_linelen = len(line)
        if skip == TemplateStr.mark:
            continue
        text += line + '\n'
    with open(filename, 'wt', encoding='utf-8') as f:
        f.write(text)
    
    
def main():
    skip = None
    args = sys.argv[1:]
    if not args:
        print('usage: {} [--skip=PARAGRAPH] template[=filename]'.format(os.path.basename(sys.argv[0])))
        sys.exit(1)
    for arg in args:
        if arg.startswith('--skip='):
            skip = arg.split('=', 1)[1]
        elif not arg.startswith('--'):
            fileinfo = arg.split('=', 1)
            create_doc(*fileinfo, skip=skip)
        else:
            print('Unknown Option:', arg)
            sys.exit(1)
            
    
if __name__ == '__main__':
    try:
        _
    except NameError:
        __builtins__._ = lambda text: text
    main()
    

