#!/usr/bin/env python
"""A simple EPICS macLib implementation. We support the minimum syntax needed for expanding fileNames/paths etc
"""
from __future__ import print_function

import re

# Form regex patterns for the six possible forms
# pMacro:      macro name within parentheses
# pMacroWQDef: macro name within parentheses preceded by default value in quotes
# pQDefVal:    default value within quotes within parentheses
# pMacroWDef:  macro name within parentheses preceded by default value
# pDefVal:     default value within parentheses
# bMacro:      macro name within braces
# bMacroWQDef: macro name within braces preceded by default value in quotes
# bQDefVal:    default value within quotes within braces
# bMacroWDef:  macro name within braces preceded by default value
# bDefVal:     default value within braces
macroPatterns = [
    r'\$\((?P<pMacro>[^()=\s]+)\)',                                  # $(macroname)
    r'\$\((?P<pMacroWQDef>[^()=\s]+)="(?P<pQDefVal>[^"()=\s]*)"\)',  # $(macroname="default-value")
    r'\$\((?P<pMacroWDef>[^()=\s]+)=(?P<pDefVal>[^()=\s]*)\)',       # $(macroname=default-value)
    r'\${(?P<bMacro>[^{}=\s]+)}',                                    # ${macroname}
    r'\${(?P<bMacroWQDef>[^{}=\s]+)="(?P<bQDefVal>[^"{}=\s]*)"}',    # ${macroname="default-value"}
    r'\${(?P<bMacroWDef>[^{}=\s]+)=(?P<bDefVal>[^{}=\s]*)}',         # ${macroname=default-value}
]
combinedPattern = '(?:{})'.format('|'.join(macroPatterns))
macroPattern = re.compile(combinedPattern)

def processMacroMatch(match):
    '''Returns the macro and default value depending on which form was matched'''
    if match.group('pMacro'):
        return match.group('pMacro'), None

    if match.group('pMacroWQDef'):
        return match.group('pMacroWQDef'), match.group('pQDefVal')

    if match.group('pMacroWDef'):
        return match.group('pMacroWDef'), match.group('pDefVal')

    if match.group('bMacro'):
        return match.group('bMacro'), None

    if match.group('bMacroWQDef'):
        return match.group('bMacroWQDef'), match.group('bQDefVal')

    if match.group('bMacroWDef'):
        return match.group('bMacroWDef'), match.group('bDefVal')

def substMacro(val, env):
    ''' Expands a macro using EPICS maclib syntax. The four forms we support are
    $(macroname)
    $(macroname=default-value)
    ${macroname}
    ${macroname=default-value}
    '''
    ret = ''
    cursor = 0
    for match in macroPattern.finditer(val):
        # Get span of macro expression
        start, end = match.span()

        # Grab everything before macro expression
        ret += val[cursor:start]

        # Perform macro substitution
        macro, defaultValue = processMacroMatch(match)
        if macro in env:
            ret += env[macro]
        elif defaultValue is not None:
            ret += defaultValue
        else:
            ret += match.group(0)

        # Move cursor just after macro expression
        cursor = end

    # Grab remainder of string
    ret += val[cursor:]
    return ret



if __name__ == "__main__":
     print(substMacro("${TOP}", {'TOP': 'ABC123'}))
     print(substMacro("$(TOP)", {'TOP': 'ABC123'}))
     print(substMacro("${TOP=DEF546}", {'TOP': 'ABC123'}))
     print(substMacro("${TOP1=DEF546}", {'TOP': 'ABC123'}))
     print(substMacro("$(TOP=DEF546)", {'TOP': 'ABC123'}))
     print(substMacro("$(TOP1=DEF546)", {'TOP': 'ABC123'}))

     print(substMacro("${TOP}/123/${BOTTOM}", {'TOP': 'ABC123', 'BOTTOM': 'DEF456'}))
     print(substMacro("${TOP}/123/${BOTTOM1}", {'TOP': 'ABC123', 'BOTTOM': 'DEF456'}))
     print(substMacro("${TOP}/123/${BOTTOM1=GHI789}", {'TOP': 'ABC123', 'BOTTOM': 'DEF456'}))
     