import os
import sys
import runpy
import traceback
from pathlib import Path
import ctypes
from tkinter import messagebox

# Mutex
mutex = None

def setup_environment():
    """Setup environment paths for the application."""
    # Checks if the app is a .exe or .py file
    if getattr(sys, "frozen", False):
        baseDir = Path(sys.executable).parent
    else:
        baseDir = Path(__file__).parent

    # The path to the resources dir
    validatorDir = baseDir.joinpath("resources")
    # If the baseDir doesn't exists creates a new path pointing to the current working dir.
    if not validatorDir.exists():
        validatorDir = Path.cwd().joinpath("resources")
    # Checks if the validatorDir exists and gathers the DLLs
    if validatorDir.exists():
        # Add the validatorDir to the system path
        if str(validatorDir) not in sys.path:
            sys.path.insert(0, str(validatorDir))
        # Adds the DLLs to environment
        dllPath = validatorDir / "dlls"
        if dllPath.exists():
            os.environ["PATH"] = str(dllPath) + os.pathsep + os.environ.get("PATH", "")
        gdalData = validatorDir / "gdal_data"
        if gdalData.exists():
            os.environ["GDAL_DATA"] = str(gdalData)
        proj_data = validatorDir / "proj_data"
        if proj_data.exists():
            os.environ["PROJ_LIB"] = str(proj_data)
        try:
            if dllPath.exists():
                os.add_dll_directory(str(dllPath))
        except (AttributeError, OSError):
            pass
        return validatorDir
    # If it doesn't exists it returns None
    return None

def already_running():
    """Prevents multiple instances of the app."""
    global mutex
    # Creates a mutex so the validator can't be run multiple times.
    mutexName = "Global\\ValidatorMutex"
    mutex = ctypes.windll.kernel32.CreateMutexW(None, False, mutexName)
    # If the app is running it doesn't do anything
    return ctypes.windll.kernel32.GetLastError() == 183

def main():
    # Start the validator
    try:
        # Environment setup
        validatorDir = setup_environment()
        # Checks if the env setup returned None
        if not validatorDir:
            return 1
        # Changes the dir to the resources folder
        os.chdir(str(validatorDir))
        # The accepted entry scripts
        possibleScripts = ["main.py", "validator.py", "app.py", "gui.py", "run.py"]
        # Checks if any of the files matches the scripts names
        foundScript = None
        for script in possibleScripts:
            scriptPath = validatorDir / script
            if scriptPath.exists():
                foundScript = scriptPath
                break
        
        # If the script is found it runs the app.
        if foundScript:
            runpy.run_path(str(foundScript), run_name="__main__")
        # If it isn't found it shows an error
        else:
            messagebox.showerror(
                title="Eroare",
                message="Eroare interna a validatorului."
            )
        return 0

    except Exception:
        traceback.print_exc()
        # If an error occurs shows the user that one happend.
        messagebox.showerror(
            title="Eroare",
            message="Eroare interna a validatorului."
        )
        return 1

if __name__ == "__main__":
    # Checks if it is running
    if already_running():
        sys.exit(0)
    # Runs the app.
    sys.exit(main())