#!/usr/bin/env python2
"""This provides a cdCommands parser and a utility to parse and replace cdCommands values with a provided dict
cdCommands looks like so
top = "/afs/slac.stanford.edu/g/lcls/vol8/epics/iocTop/CAMAC/MAIN_TRUNK"
putenv("TOP=/afs/slac.stanford.edu/g/lcls/vol8/epics/iocTop/CAMAC/MAIN_TRUNK")
"""

import os
import sys
from plex import *
import random
import StringIO

# Here's where we define the lexicon for the parser. 
letter = Range("AZaz")
digit = Range("09")
hspace = Any(" \t")
spchars = Any(".-_:{}+/*$<>")
comma = Str(",")
equals = Str("=")
quote = Str('"')
name = Rep1(letter | digit | spchars)
nameinquotes = quote + name + quote
space = Any(" \t\n")
openParan = Str("(")
closeParan = Str(")")
comment = Bol + Str("#") + Rep(AnyBut("\n")) + Str("\n")

fileLexicon = Lexicon([
    (comment,  'comment'),
    (space, IGNORE),
    (Str("putenv("), Begin("putenv")),
    (Bol, Begin("variableassignment")),
    State('putenv', [
                    (name, 'name'),
                    (quote, IGNORE),
                    (space, IGNORE),
                    (equals, Begin("PutEnvValue"))
                    ]),
    State('PutEnvValue', [
                    (name, 'value'),
                    (quote, IGNORE),
                    (space, IGNORE),
                    (closeParan, Begin(''))
                    ]),
    State('variableassignment', [
                    (name, 'name'),
                    (quote, IGNORE),
                    (space, IGNORE),
                    (equals, Begin("variableassignmentValue"))
                    ]),
    State('variableassignmentValue', [
                    (name, 'value'),
                    (quote, IGNORE),
                    (space, IGNORE),
                    (Eol, Begin(''))
                    ]),                       
    (space, IGNORE),
    (quote, IGNORE)
])

def writeOutReplacedVal(out, name, value, commandtype):
    '''Write out a putenv or a n=v based on the commandtype'''
    if commandtype == 'putenv':
        out.write('putenv("' + name + '=' + value + '")' + "\n")
    elif commandtype == 'variableassignment':
        out.write(name + ' = "' + value + '"\n')
    else:
        raise Exception("Cannot determine if this is a putenv or a name=value")

def parseAndReplaceCDCommandsFile(cdCommandsPath, replaceMap):
    '''Parse the cdCommands file into a list of tuples that represents the name/value. 
    Replace the value of any name that is present in replaceMap with the value from the map.
    Finally update the specified file with the new set of values
    '''
    tempFilePath = os.path.join(os.path.dirname(cdCommandsPath), "_tmp_multifacility" + str(int(random.random()*1000000)))
    while os.path.exists(tempFilePath):
        stderr.write("Generating a new name for the temporary file\n")
        tempFilePath = os.path.join(os.path.dirname(cdCommandsPath), "_tmp_multifacility" + str(int(random.random()*1000000)))

    NVPairs = {}    
    with open(tempFilePath, 'w') as out:
        with open(cdCommandsPath, 'r') as f:
            scanner = Scanner(fileLexicon, f, cdCommandsPath)
            currentName = None
            currentCommandType = None
            while 1:
                token = scanner.read()
                # print token, scanner.state_name
                if token[0] is None:
                    break
                elif token[0] == "comment":
                    out.write(token[1])
                elif token[0] == 'name':
                    currentName = token[1]
                    currentCommandType =  scanner.state_name
                elif token[0] == 'value':
                    if not currentName:
                        sys.stderr.write("Obtained Value without a name" + token[1])
                        continue
                    mapName = currentName.upper()
                    if mapName in replaceMap:
                        NVPairs[currentName] = replaceMap[mapName]
                        writeOutReplacedVal(out, currentName, replaceMap[mapName], currentCommandType)
                    else:
                        NVPairs[currentName] = token[1]
                        writeOutReplacedVal(out, currentName, token[1], currentCommandType)
                    currentName = None
                    currentCommandType = None
                    if scanner.state_name == 'variableassignmentValue':
                        scanner.begin('')
                else:
                    sys.stderr.write("Unknown token" + token)
        os.rename(tempFilePath, cdCommandsPath)
        return NVPairs

# if __name__ == "__main__":
#     parseAndReplaceEnvPathsFile(sys.argv[1], {'TOP': 'ABC123'})
