#!/usr/bin/python3
# lastact: arturo@2024-03-14
# desc: Configura en los PPDs los parámetros indicados como parámetros

# Para recoger los parametros pasados en la llamada al script:
import argparse

# Importamos textwrap para poder hacer uso de un epilogo de ejemplos al final de la ayuda de varias lineas, tal como indica la doc de argparse:
# https://docs.python.org/es/3/library/argparse.html
import textwrap

# Importamos sys para poder pasar los parámetros desde la función de inicio a la función main:
import sys

# Para hacer llamadas al sistema:
import os

# Para hacer uso de expresiones regulares:
import re


# Obtener el nombre del script
nombre_script = os.path.basename(__file__)

# Definir el epílogo con ejemplos:
epilogo = f"""
Ejemplos de uso:
{nombre_script} '-i|--input' 'ruta_fichero_in.ppd' '-o|--output' 'ruta_fichero_out.ppd' '--konica_seguimiento_cuenta' ...
{nombre_script} '-i|--input' 'ruta_fichero_in.ppd' '-o|--output' 'ruta_fichero_out.ppd' '--konica_user_authentication' ...
{nombre_script} '-c|--custom' "{{'directiva1': 'valor1', 'directiva2': 'valor2', ...}}" ...
{nombre_script} -i Sharp-BP-70M55-ps.ppd -o Sharp-BP-70M55-ps-A4-usernumber-retencion.ppd -c "{{'DefaultColorSpace': 'Gray', 'DefaultPageSize': 'A4', 'DefaultPageRegion': 'A4', 'DefaultPaperDimension': 'A4', 'DefaultJCLRetentionSetting': 'Before', 'DefaultJCLDocumentFilingSetting': 'Main', 'DefaultJCLUserNumber': 'Custom.99999'}}"
{nombre_script} -i Sharp-MX-3050-3051-ps.ppd -o Sharp-MX-3050-3051-ps-out.ppd -c "DefaultJCLUserNumber: Custom.99999; DefaultPageSize: A4"
{nombre_script} -i Sharp-MX-3050-3051-ps.ppd -o Sharp-MX-3050-3051-ps-out.ppd -c "DefaultColorSpace: Gray
    DefaultPageSize: A4
    DefaultPageRegion: A4
    DefaultPaperDimension: A4
    DefaultJCLRetentionSetting: Before
    DefaultJCLDocumentFilingSetting: Main
    DefaultJCLUserNumber: Custom.99999"
"""

# Definimos las listas predefinidas de parámetros PPD:
dict_konica_user_authentication = {
    "DefaultKMAuthentication": "Private",
    "DefaultKMAuthServer": 1,
    "DefaultKMAuthUser": "Custom.Public",
    "DefaultKMAuthPass": "Custom.1234",
}
dict_konica_seguimiento_cuenta = {
    "DefaultKMSectionManagement": "True",
    "DefaultKMAccPass": "Custom.1234",
}
dict_sharp_usernumber_retencion = {
    # "DefaultColorSpace": "Gray",
    "DefaultPageSize": "A4",
    "DefaultPageRegion": "A4",
    "DefaultPaperDimension": "A4",
    "DefaultJCLRetentionSetting": "Before",
    "DefaultJCLDocumentFilingSetting": "Main",
    "DefaultJCLUserNumber": "Custom.99999",
}


def mostrar_ayuda():
    parser.print_help()


def cadena_to_diccionario(_cadena):
    _lista = {}
    if not ";" in _cadena and not "\n" in _cadena and ":" in _cadena:
        _clave, _valor = _cadena.split(":")
        _lista[_clave] = _valor.strip()
    if ";" in _cadena:
        _parejas = _cadena.split(";")
        for _pareja in _parejas:
            if ":" in _pareja:
                _clave, _valor = _pareja.split(":")
                _lista[_clave] = _valor.strip()
    if "\n" in _cadena:
        # print("#> El caracter separador son saltos de línea")
        _parejas = _cadena.split("\n")
        for _pareja in _parejas:
            if ":" in _pareja:
                _clave, _valor = _pareja.split(":")
                _lista[_clave] = _valor.strip()
    return _lista


def ppd_asignar_lista_parametros(contenido, _lista, _texto):
    if not isinstance(_lista, dict):
        # Empezamos comprobando si la lista de parámetros recibida esta en formato diccionario para evaluarla:
        regex = "{.*}"
        if re.search(regex, _lista):
            _lista = eval(_lista)
        else:
            _lista = cadena_to_diccionario(_lista)
    # _lista = eval(_lista)
    print(f"{_texto}: {_lista}")
    for key in sorted(_lista):
        print(key, _lista[key])
        regex = f"{key}: .*"
        sustitucion = f"{key}: {_lista[key]}"
        if re.search(regex, contenido):
            print(f"+> Se ha encontrado el patrón: '{regex}' => '{sustitucion}'")
            contenido = re.sub(regex, sustitucion, contenido)
        else:
            print(f"-> NO se ha encontrado el patrón: '{regex}' ('{sustitucion}')")
    return contenido


def main(argv):
    if os.path.isfile(args.input):
        dir_base = os.path.dirname(os.path.abspath(args.input))
        destino = dir_base + "/" + os.path.basename(args.output)
        print(f"El archivo PPD a manipular es: {args.input}, ubicado en: {dir_base}")
        print(f"Destino: {destino}")
        # print(os.path.abspath(args.input))
    else:
        # Si el archivo no existe, imprimir un mensaje de error
        print("El archivo PPD indicado no existe")
        os._exit(1)

    try:
        fhand = open(args.input)
        contenido = fhand.read()
    except:
        mensaje = "=> El archivo indicado como parámetro no existe: " + args.input
        print(mensaje)
        os._exit(2)

    # Comprobamos que parámetros se han pasado para generar el archivo de salida:
    if args.konica_user_authentication:
        texto = f"#> Modificaremos las siguientes directivas relativas a la autenticación en konica"
        contenido = ppd_asignar_lista_parametros(
            contenido, dict_konica_user_authentication, texto
        )

    if args.konica_seguimiento_cuenta:
        texto = f"#> Modificaremos las siguientes directivas relativas a la account track o seguimiento de cuenta de konica"
        contenido = ppd_asignar_lista_parametros(
            contenido, dict_konica_seguimiento_cuenta, texto
        )

    if args.sharp_usernumber_retencion:
        texto = f"#> Modificaremos las siguientes directivas al Usernumber y retención en sharp"
        contenido = ppd_asignar_lista_parametros(
            contenido, dict_sharp_usernumber_retencion, texto
        )

    if args.custom_params:
        lista = args.custom_params
        texto = f"#> Personalizaremos las siguientes directivas indicadas manualmente"
        contenido = ppd_asignar_lista_parametros(
            # contenido, eval(lista), texto
            contenido,
            lista,
            texto,
        )  # Mediante eval() transformamos una cadena de texto en un diccionario

    # Guardamos el resultado en el fichero de salida:
    try:
        fout = open(destino, "w")
        fout.write(contenido)
    except:
        mensaje = "=> ¡¡Error!! No hay permiso de escritura sobre el archivo ..."
        print(mensaje)
        os._exit(3)
    print(f"=> PPD resultante: {destino}")


# Creamos un objeto argparse para la ayuda y tratamiento de los parámetros:
parser = argparse.ArgumentParser(
    description="""Configura los parámetros PPD de los ficheros PPDs pasados como parámetro.
    Puede indicarse un tipo de modificación ya preconfigurada, o pasarse de diferentes formas la lista de parámetros, tal como se puede ver en los ejemplos""",
    formatter_class=argparse.RawDescriptionHelpFormatter,
    epilog=textwrap.dedent(epilogo),
)
parser.add_argument(
    "-i",
    "--input",
    help="Indica la ruta del archivo PPD a tomar como patrón y modificar",
    required=True,
)
parser.add_argument(
    "-o",
    "--output",
    help="Indica el nombre del archivo PPD resultante de salida",
    required=True,
)
parser.add_argument(
    "--konica_seguimiento_cuenta",
    action="store_true",  # Permite definir un argumento sin valor que le acompañe
    dest="konica_seguimiento_cuenta",  #  Permite comprobar mediante args.[dest] si el parámetro o argumento ha sido indicado
    help=f"Account Track: Modifica las directivas de Konica relativas al Account track o seguimiento de cuenta #> {dict_konica_seguimiento_cuenta}",
)
parser.add_argument(
    "--konica_user_authentication",
    action="store_true",
    dest="konica_user_authentication",
    help=f"User Authentication: Modifica las directivas relativas a la autenticación en konica #> {dict_konica_user_authentication}",
)
parser.add_argument(
    "--sharp_usernumber_retencion",
    action="store_true",
    dest="sharp_usernumber_retencion",
    help=f"User Number y Retención: Modifica las directivas relativas a la autenticación y retención en sharp #> {dict_sharp_usernumber_retencion}",
)
parser.add_argument(
    "-c",
    "--custom",
    dest="custom_params",
    help="Permite indicar una lista de parámetros a modificar #> {'directiva1': 'valor1', 'directiva2': 'valor2', ...}",
    required=False,
)
args = parser.parse_args()

if __name__ == "__main__":
    main(sys.argv[1:])
