import argparse
import yaml
from yaml.loader import SafeLoader
import re
import os

def parseLayoutFile():
    layoutFile = open(args.layout,"r")
    data = layoutFile.read()
    layoutFile.close()
    regex= r'(?<=\")([\s\S]*?)(?=\")'
    data = re.findall(regex, data)
    if(len(data) != 5):
        raise Exception('layout file has a different structure from expected')
    return [data[0], data[2], data[4]]
 

def parseEventFile():
    eventFile = open(args.event, "r")
    data = yaml.load(eventFile, Loader=SafeLoader)
    eventFile.close()
    return data

def alignMultiLine(characterCounter, multilineString):
    index = 0
    strings = multilineString.split('\n')
    for string in strings:
        if(index !=0):
            string = string.lstrip()
            string = "\n"+"".join(" " for i in range(characterCounter)) + string
            strings[index] = string
        index+=1
    return "\n".join(strings)

def replaceSymbols(text, oldSymbols, newSymbols):
    counter = 0
    for oldSymbol in oldSymbols:
        if(len(newSymbols[counter]) - len(oldSymbols[counter]) > 0):
            text = str(text).replace(oldSymbol, " "+newSymbols[counter]+" ")
        else:
            text = str(text).replace(oldSymbol, newSymbols[counter])
        counter+=1
    return text

def getTitleLength(header):
    idx1 = header.find("<over_score>")+14
    idx2 = header.find("<under_score>")
    return idx2 - idx1

# def getContext(context):
#     if(len(context) == 3):
#         return "starlingx-openstack-empty"
#     elif(len(context) == 2):
#         if("starlingx" in context):
#             if("openstack" in context):
#                 return "starlingx-openstack"
#             else:
#                 return "starlingx-empty"
#         else:
#             return "openstack-empty"
#     else:
#         return context[0]

# RS - 11-16-22 - generalize getContext to all runtime scenarios
def getContext(context):
    return '-'.join(map(str, context))

def seriesFilter(key, serie):
    if(float(serie)%100 > 1):
        return (float(key)//10) == (float(serie)//10)
    else:
        return (float(key)//100) == (float(serie)//100)

def seriesFile(layout, events, types, fileExtension, oldSymbols, newSymbols, products, sort ):
    series = args.series.split(",")
    for serie in series:
        matchingKeys = [key for key in events.keys() if seriesFilter(key, serie) and events[key]["Type"] in types and events[key]["Context"] in products ]
        if(sort):
            matchingKeys.sort()
        if(len(matchingKeys) > 0):
            serieFile = open(args.outputPath+str(serie)+"-series-"+'-'.join(types).lower()+"-messages"+fileExtension, "w")
            header = layout[0]
            header = header.replace("<series_number>",serie).replace("<series-number>",serie)
            score = "".join(args.titleSymbol for i in range(getTitleLength(header)))
            header = header.replace("<over_score>", score)
            header = header.replace("<Context>", getContext(products))
            header = header.replace("<under_score>", score)
            serieFile.write(header)
            for matchingKey in matchingKeys:
                body = layout[1]
                body = body.replace("<alarm_id>", format(matchingKey, '.3f'))
                fields = re.findall('(?<=\<)(.*?)(?=\>)', body)
                for field in fields:
                    if(field in events[matchingKey]):
                        if(type(events[matchingKey][field]) == type(events)):
                            value = []
                            for subkey in events[matchingKey][field]:
                                value.append(events[matchingKey][field][subkey])
                            events[matchingKey][field] = "\n".join(value)
                        else:
                            events[matchingKey][field] = (re.sub(r'\n\s*\n','\n',str(events[matchingKey][field]),re.MULTILINE))
                        if(oldSymbols != None and newSymbols != None):
                            events[matchingKey][field]= replaceSymbols(events[matchingKey][field], oldSymbols,newSymbols)
                        if('\n' in events[matchingKey][field]):
                            index = body.index('<'+field+'>')
                            characterCounter= 0
                            while(body[index] != '\n'):
                                index-=1
                                characterCounter+=1
                            body = body.replace('<'+field+'>',alignMultiLine(characterCounter-1, events[matchingKey][field]))
                        else:
                            body = body.replace('<'+field+'>',events[matchingKey][field])
                    else:
                        body = body.replace('<'+field+'>','N/A')
                serieFile.write(body)
            footer = layout[2]
            serieFile.write(footer)
            serieFile.close

def recordsFile(layout, events, fileExtension, oldSymbols, newSymbols, sort):
    records = args.records.split(",")
    if(len(records) > 0):
        matchingKeys = [float(record) for record in records for key in events.keys() if float(key) == float(record)]
        if(sort):
            matchingKeys.sort()
        if(len(matchingKeys) > 0):
            serieFile = open(args.outputPath+args.fileName+fileExtension, "w")
            header = layout[0]
            score = "".join(args.titleSymbol for i in range(getTitleLength(header)))
            header = header.replace("<over_score>", score)
            header = header.replace("<under_score>", score)
            serieFile.write(header)
            for matchingKey in matchingKeys:
                body = layout[1]
                body = body.replace("<alarm_id>", format(matchingKey, '.3f'))
                fields = re.findall('(?<=\<)(.*?)(?=\>)', body)
                for field in fields:
                    if(field in events[matchingKey]):
                        if(type(events[matchingKey][field]) == type(events)):
                            value = []
                            for subkey in events[matchingKey][field]:
                                value.append(events[matchingKey][field][subkey])
                            events[matchingKey][field] = "\n".join(value)
                        else:
                             events[matchingKey][field] = (re.sub(r'\n\s*\n','\n',str(events[matchingKey][field]),re.MULTILINE))
                        if(oldSymbols != None and newSymbols != None):
                            events[matchingKey][field]= replaceSymbols(events[matchingKey][field], oldSymbols,newSymbols)
                        if('\n' in events[matchingKey][field]):
                            index = body.index('<'+field+'>')
                            characterCounter= 0
                            while(body[index] != '\n'):
                                index-=1
                                characterCounter+=1
                            body = body.replace('<'+field+'>',alignMultiLine(characterCounter-1, events[matchingKey][field]))
                        else:
                            body = body.replace('<'+field+'>',events[matchingKey][field])
                    else:
                        body = body.replace('<'+field+'>','N/A')
                serieFile.write(body)
            footer = layout[2]
            serieFile.write(footer)
            serieFile.close    


parser = argparse.ArgumentParser()
invalidArguments = False 
parser.add_argument("-l", "--layout", required=True, help = "path for the layout file")
parser.add_argument("-e", "--event", required=True, help = "path for the events.yaml file")
parser.add_argument("-s", "--series", help = "list of the desired series")
parser.add_argument("-ts", "--titleSymbol", required=True, help = "Symbol used between the title")
parser.add_argument("-replace", "--replace", required=False, help = "replaces a symbol with another")
parser.add_argument("-type", "--type", help = "type can be Alarm or Log, it also can be both")
parser.add_argument("-outputPath", "--outputPath", required=True, help="Path where the output will be saved")
parser.add_argument("-records", "--records", help="list of the desired records")
parser.add_argument("-fileName", "--fileName", help="file name for the output file")
parser.add_argument("-product", "--product", help="product type for filtering")
parser.add_argument("-sort", "--sort", help="argument that defines if the output will be sorted")


args = parser.parse_args()
oldSymbol = None
newSymbol = None
types = []

if(args.series == None and args.records == None):
    invalidArguments = True
    print("Expected either series or records as an argument")
if(args.series != None and args.product == None):
    invalidArguments = True
    print("Expected product as an argument")
if(args.series != None and args.type == None):
    invalidArguments=True
    print("Expected type as an argument")
if(args.replace != None):
    replaceItems =args.replace.split(",")
    oldSymbols = []
    newSymbols = []
    for replaceItem in replaceItems:
        replace = replaceItem.lstrip().split(" ")
        if(len(replace) == 2):
            oldSymbols.append(replace[0])
            newSymbols.append(replace[1])
if(args.type != None):
    types = args.type.split(",")
    counter = 0
    for recordtype in types:
        types[counter] = recordtype.lstrip().rstrip().capitalize()
        if(types[counter] != "Alarm" and types[counter]!= "Log"):
            invalidArguments = True
            print("Invalid type argument")
        counter +=1
if(args.records != None):
    if(args.fileName == None):
        invalidArguments = True
        print("Expected fileName as an argument")
if(args.product != None):
    products = args.product.split(",")
    counter = 0
    for product in products:
        products[counter] = product.lstrip().rstrip().lower()
        if(products[counter] != "openstack" and products[counter] != "starlingx"):
            if(products[counter] == "empty"):
                products[counter] = None
            else:
                print("Invalid product argument") 
                invalidArguments= True
        counter +=1
if(args.sort != None):
    if(args.sort.upper() == 'TRUE'):
        sort = True
    else:
        sort = False
else:
    sort = False



if(invalidArguments == False):
    fileName, fileExtension = os.path.splitext(args.layout)
    layout = parseLayoutFile()
    events = parseEventFile()
    if(args.records != None):
        recordsFile(layout,events,fileExtension, oldSymbols, newSymbols,sort)
    else:
        seriesFile(layout, events, types, fileExtension, oldSymbols, newSymbols, products,sort)