# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
#
# Copyright (c) 2008 - 2012 by Wilbert Berendsen
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
# See http://www.gnu.org/licenses/ for more information.

"""
generate all scheme words in the _scheme_data.py file
"""
from __future__ import unicode_literals

import _scheme_data
import urllib
import os
import re


VERSION = 2.17
GUILE_URL = "https://www.gnu.org/software/guile/docs/docs-1.8/guile-ref/Procedure-Index.html#Procedure-Index"
LY_FUNCTION_URL = "http://lilypond.org/doc/v2.17/Documentation/internals/scheme-functions"
SMC_PATH = os.path.join(os.environ['HOME'], 'lilypond/usr/share/lilypond/current/scm')

GUILE_IGNONED_TYPE = (
    'Apply Traps',
    'Common Trap Options',
    'Continuations',
    'Debug on Error',
    'Display Backtrace',
    'Encryption',
    'Entry Traps',
    'Exit Traps',
    'Garbage Collection Functions',
    'getopt-long Reference',
    'Internationalization',
    'Location Traps',
    'Network Databases',
    'Network Socket Address',
    'Network Sockets and Communication',
    'Procedure Traps',
    'Signals',
    'Threads',
    'Trap Utilities',
    'Source Traps',
    'Step Traps',
    'SRFI-37',
    'Stepping and Continuing',
    'System asyncs',
    'System Identification',
    'User asyncs',
    'User Information',
    'User level options interfaces',
)

GUILE_OTHER_WORDS = ['else', 'set!']

def writeList(file_, name, lst):
    file_.write("{} = [\n".format(name))
    for word in sorted(set(lst)):
        file_.write("    '{0}',\n".format(word))
    file_.write("]\n\n")

def replace(word):
    word = word.replace('&lt;', '<')
    word = word.replace('&gt;', '>')
    return word

guilePage = urllib.urlopen(GUILE_URL).read()
guilePat = re.compile(r"<code>([a-z\d\+\?\!\*&;/=:-]+)</code></a>: <a href=\".+\">(.+)</a>")

lyFunctionPage = urllib.urlopen(LY_FUNCTION_URL).read()
lyFunctionPat = re.compile(r'<u>Function:</u> <b>(ly:.+)</b>')


defineFunc = re.compile(r'\((?:define\*?|define-safe)-public\s+\(([-><a-zA-Z:\?]+)[\s\)]')
defineMacro = re.compile(r'\(defmacro\*?-public\s+([-><a-zA-Z:\?]+)[\s\)]')
defineVar = re.compile(r'\((?:define\*?|define-safe)-public\s+([-><a-zA-Z:\?]+)[\s\)]')
startWithLy = re.compile(r"(ly:[-><a-zA-Z:\?]+)[\s\)]")


schemeDataPath = os.path.join(os.path.split(_scheme_data.__file__)[0], '_scheme_data.py')
with open(schemeDataPath, "w") as f:
    f.write("#! python\n#generated by makeshemedata.py\n\nversion={}\n\n".format(VERSION))
    
    guileWords = []
    for m in guilePat.finditer(guilePage):
        if m.group(2) not in GUILE_IGNONED_TYPE:
            proc = m.group(1)
            if not proc.startswith('gds-'):
                guileWords.append(replace(proc))
    guileWords += GUILE_OTHER_WORDS
    
    
    lyFunctions = []
    lyVars = []
    lyCons = []
    for word in lyFunctionPat.finditer(lyFunctionPage):
        lyFunctions.append(replace(word.group(1)))
        
    for filename in os.listdir(SMC_PATH):
        path = os.path.join(SMC_PATH, filename)
        with open(path) as inp:
            text = inp.read()
            for m in defineFunc.finditer(text):
                lyFunctions.append(m.group(1))
            
            for m in defineMacro.finditer(text):
                lyFunctions.append(m.group(1))
                
            for m in startWithLy.finditer(text):
                lyFunctions.append(m.group(1))
            
            for m in defineVar.finditer(text):
                word = m.group(1)
                if word.isupper():
                    lyCons.append(word)
                else:
                    lyVars.append(word)
                    
    for word in lyFunctions:
        if word in lyVars:
            lyVars.remove(word)
    
    lyVars.remove('parser')
    
    writeList(f, 'scheme_keywords', guileWords) 
    writeList(f, 'scheme_functions', lyFunctions)
    writeList(f, 'scheme_variables', lyVars)
    writeList(f, 'scheme_constants', lyCons)
    