import os
import time
from jinja2 import Environment, FileSystemLoader
import re

import filechecksum as fcs

# Pfad zur Eingabedatei und Ausgabedatei
input_file = "include/config.h"
output_sourcefile = "src/struct2json.cpp"
output_headerfile = "include/struct2json.h"
# Liste der zu suchenden Variablen/Structs
variable_names = ['LubeConfig', 'PersistenceData']

def get_types(file_content, variable_names):
    result = {}
    
    # Entferne Kommentare, um unerwünschte Störungen zu vermeiden
    file_content = re.sub(r'\/\*.*?\*\/', '', file_content, flags=re.DOTALL)
    file_content = re.sub(r'\/\/.*', '', file_content)
    
    for var_name in variable_names:
        # Erstelle ein reguläres Ausdrucksmuster, um den Typ der Variable zu extrahieren
        pattern = re.compile(r'\b(?:extern\s+)?(\w+)\s+' + re.escape(var_name) + r'\s*;')
        match = pattern.search(file_content)
        
        if match:
            # Extrahiere den Typ aus dem Treffer
            type_match = match.group(1)
            result[var_name] = type_match

    return result

def extract_struct_fields(file_content, variable_types):
    result = {}

    # Entferne Kommentare, um unerwünschte Störungen zu vermeiden
    file_content = re.sub(r'\/\*.*?\*\/', '', file_content, flags=re.DOTALL)
    file_content = re.sub(r'\/\/.*', '', file_content)

    for var_name, var_type in variable_types.items():
        # Erstelle ein reguläres Ausdrucksmuster, um das Strukturfeld zu extrahieren
        pattern = re.compile(r'typedef\s+struct\s*{([^}]*)}\s*' + re.escape(var_type) + r'\s*;')
        match = pattern.search(file_content)

        if match:
            # Extrahiere die Felder aus dem Treffer
            fields_match = re.findall(r'\b(\w+)\s+(\w+)\s*;', match.group(1))
            if fields_match:
                result[var_name] = {'type': var_type, 'fields': {field_name: field_type for field_type, field_name in fields_match}}

    return result

def struct2json():
    # Überprüfen, ob die Verzeichnisse existieren, andernfalls erstellen
    output_dir_source = os.path.dirname(output_sourcefile)
    if not os.path.exists(output_dir_source):
        os.makedirs(output_dir_source)
    output_dir_header = os.path.dirname(output_headerfile)
    if not os.path.exists(output_dir_header):
        os.makedirs(output_dir_header)

    # Unix-Zeitstempel hinzufügen
    timestamp = int(time.time())

    # Parse structs
    with open(input_file, 'r') as file:
        content = file.read()

    variable_types = get_types(content, variable_names)
    structs = extract_struct_fields(content, variable_types)
    checksum = fcs.calculate_checksum(structs)

    env = Environment(loader=FileSystemLoader('codegen/templates', encoding='utf-8'))
    # Lade das Jinja2-Template aus der Datei
    template_c = env.get_template('struct2json.cpp.j2')
    template_h = env.get_template('struct2json.h.j2')

    # Erstelle ein Context-Dictionary mit den erforderlichen Daten
    context = {
        'timestamp_unix': timestamp,
        'timestamp' : time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(timestamp)),
        'date' : time.strftime('%d.%m.%Y', time.localtime(timestamp)),
        'structs': structs,
        'checksum': checksum
    }

    # Überprüfe, ob die Checksummen übereinstimmen
    if fcs.read_and_compare_checksum(output_sourcefile, checksum):
        print("Keine Änderungen in der Source-Datei erforderlich.")
    else:
        # Rendere das Template mit den Werten und erhalte den Source-Text
        source_text = template_c.render(context)
        # Schreibe den generierten Source-Text in die Source-Datei
        with open(output_sourcefile, "w", encoding='utf-8') as f:
            f.write(source_text)
        print(f"Source-Datei wurde erstellt: {output_sourcefile}")

    # Überprüfe, ob die Checksummen übereinstimmen
    if fcs.read_and_compare_checksum(output_headerfile, checksum):
        print("Keine Änderungen in der Header-Datei erforderlich.")
    else:
        # Rendere das Template mit den Werten und erhalte den Header-Text
        header_text = template_h.render(context)
        # Schreibe den generierten Header-Text in die Header-Datei
        with open(output_headerfile, "w", encoding='utf-8') as f:
            f.write(header_text)
        print(f"Header-Datei wurde erstellt: {output_headerfile}")