from pathos.helpers import cpu_count


class RecopiladorInformacion:
    def __init__(self):
        self.nombre_heuristica = None
        self.lista_parametros = None
        self.lista_nombres_parametros_dataframe = None
        self.fecha_hora = None
        self.funciones_utilizadas_pdf = None

    def transformar_archivo_json(self, ruta):
        import json

        diccionario = {'nombre_heuristica': self.nombre_heuristica, 'lista_parametros': self.lista_parametros,
                       'lista_nombres_parametros_dataframes': list(set(self.lista_nombres_parametros_dataframe)),
                       'fecha_hora': self.fecha_hora, 'funciones_utilizadas_pdf': self.funciones_utilizadas_pdf}
        ruta_archivo_json = "Ejecucion-" + str(self.nombre_heuristica) + "-" + str(self.fecha_hora) + ".txt"
        nueva_ruta_json = ruta / ruta_archivo_json
        with open(nueva_ruta_json, 'w') as outfile:
            json.dump(diccionario, outfile, indent=4)


#todo: Crear los métodos para verificar que el p.o.d. del usuario está bien planteado, y construir un p.o.d. genérico.


def cart_prod(dicts):
    import itertools
    return list(dict(zip(dicts, x)) for x in itertools.product(*dicts.values()))


def genera_lista_ejecuciones_heuristicas(dicts, repeticiones=1):
    import itertools
    lista_producto_cartesiano = cart_prod(dicts)
    return [x for item in lista_producto_cartesiano for x in itertools.repeat(item, repeticiones)]


def genera_carpeta_resultados(nombre, fecha_hora):
    import pathlib
    import os

    ruta = pathlib.Path('Resultados')

    try:
        os.mkdir(ruta)
    except:
        print("Ruta ", ruta ,"ya existente.")

    ruta = pathlib.Path('Resultados', nombre)

    try:
        os.mkdir(ruta)
    except:
        print("Ruta ", ruta ,"ya existente.")

    ruta = pathlib.Path('Resultados', nombre, fecha_hora)

    try:
        os.mkdir(ruta)
    except:
        print("Ruta ", ruta ,"ya existente.")

    return ruta


def genera_carpeta_datos(nombre, fecha_hora):
    import pathlib
    import os

    ruta = pathlib.Path('Datos')

    try:
        os.mkdir(ruta)
    except:
        print("Carpeta \"Datos\" ya existente.")

    ruta = pathlib.Path('Datos', nombre)

    try:
        os.mkdir(ruta)
    except:
        print("Carpeta \"", nombre,"\" ya existente.")

    ruta = pathlib.Path('Datos', nombre, fecha_hora)

    try:
        os.mkdir(ruta)
    except:
        print("Carpeta \"", fecha_hora,"\" ya existente.")

    return ruta


def genera_carpeta_ejecuciones(nombre, fecha_hora):
    import pathlib
    import os

    ruta = pathlib.Path('Ejecuciones')

    try:
        os.mkdir(ruta)
    except:
        print("Carpeta \"Ejecuciones\" ya existente.")

    ruta = pathlib.Path('Ejecuciones', nombre)

    try:
        os.mkdir(ruta)
    except:
        print("Carpeta \"", nombre,"\" ya existente.")

    return ruta


def crea_formato_tiempo(segundos_total):
    segundos_total = int(segundos_total)
    if segundos_total < 60:
        minutos, segundos = divmod(segundos_total, 60)
        if segundos_total < 10:
            cadena = "0"+str(segundos)+" seg"
        else:
            cadena = str(segundos)+" seg"
    elif segundos_total < 3600:
        minutos, segundos = divmod(segundos_total, 60)
        if minutos < 10:
            cadena = "0"+str(minutos)
        else:
            cadena = str(minutos)
        if segundos < 10:
            cadena = cadena+":0"+str(segundos)+" min"
        else:
            cadena = cadena+":"+str(segundos)+" min"
    elif segundos_total < 86400:
        minutos, segundos = divmod(segundos_total, 60)
        horas, minutos = divmod(minutos, 60)
        cadena = str(horas)+":"
        if minutos < 10:
            cadena = cadena+"0"+str(minutos)
        else:
            cadena = cadena+str(minutos)
        if segundos < 10:
            cadena = cadena+":0"+str(segundos)+" hrs"
        else:
            cadena = cadena+":"+str(segundos)+" hrs"
    return cadena


def inicia_exploracion_heuristica(heuristica, parametros_heuristica, nucleos_cpu=cpu_count(),
                                  modo_consola="parlante"):
    import pathos
    from .recolector_resultados import RecolectorResultados
    from tqdm import tqdm
    from datetime import datetime

    recopilador_informacion = RecopiladorInformacion()
    recopilador_informacion.nombre_heuristica = heuristica.nombre
    recopilador_informacion.lista_parametros = parametros_heuristica
    recopilador_informacion.funciones_utilizadas_pdf = heuristica.funciones_utilizadas_pdf

    heuristica.comprobar_parametros(parametros_heuristica[0])
    if modo_consola is not "silencioso":
        print("Preparando trabajo en paralelo...\n")
    pathos.multiprocessing.freeze_support()
    servidor = pathos.pools.ProcessPool(nucleos_cpu)
    if modo_consola is not "silencioso":
        print("Servidor con", servidor.ncpus, "procesadores listo.\n")
    resultados_heuristica = list(tqdm(servidor.imap(heuristica.iniciar_busqueda, parametros_heuristica),
                                      total=len(parametros_heuristica)))
    print("------------------------------------------------------------------------")
    if modo_consola is not "silencioso":
        print("Exploración heurística terminada.\n")
        print("Procesando resultados...\n")
    recolector_resultados = RecolectorResultados(resultados_heuristica)
    fecha_hora = datetime.now().strftime('%Y-%m-%d---%H-%M')
    recopilador_informacion.fecha_hora = fecha_hora
    recopilador_informacion.lista_nombres_parametros_dataframe = recolector_resultados.\
        obtener_nombre_parametros_dataframe()
    ruta_carpeta_ejecuciones = genera_carpeta_ejecuciones(heuristica.nombre, fecha_hora)
    recopilador_informacion.transformar_archivo_json(ruta_carpeta_ejecuciones)
    if modo_consola is not "silencioso":
        print("Resultados recolectados.\n")
    ruta_carpeta_resultados = genera_carpeta_resultados(heuristica.nombre, fecha_hora)
    ruta_carpeta_datos = genera_carpeta_datos(heuristica.nombre, fecha_hora)
    lista_rutas = [ruta_carpeta_ejecuciones, ruta_carpeta_resultados, ruta_carpeta_datos]
    if modo_consola is not "silencioso":
        print("\nRutas generadas: ")
        for ruta in lista_rutas:
            print(ruta)
    recolector_resultados.generar_datos_todos_resultados(ruta_carpeta_datos, heuristica.nombre, fecha_hora)
    recolector_resultados.generar_csv_resultados_procesados(ruta_carpeta_datos, heuristica.nombre, fecha_hora)
    heuristica.genera_pdf_final(recolector_resultados, ruta_carpeta_resultados, fecha_hora)
    if modo_consola is not "silencioso":
        print("Resultados guardados en", ruta_carpeta_resultados)
        print("Datos extra guardados en", ruta_carpeta_datos, "y", ruta_carpeta_ejecuciones, "\n")

