# Parcial 2 2021/22 (c) 2022 Baltasar MIT License <jbgarcia@uvigo.es>


import json
from datetime import datetime


class RegistroTelefonico:
    """La clase RegistroTelefonico es capaz de albergar
       cuándo se produjeron las llamadas de los usuarios
       de una compañía telefónica, a través de un diccionario
       de claves datetime (hasta el segundo, no microsegundo) y
       valores de listas conteniendo varias
       cadenas de caracteres correspondientes a las diferentes
       llamadas comenzadas en ese momento.
       Las listas con los números de teléfono pueden ser
       accedidos como tuplas por el momento en el que se produjeron las llamadas,
       mediante el método ficticio get_for(d: datetime) -> tuple[str],
       o bien mediante un método ficticio get(i: int) -> tuple[str],
       de manera que get(0) devuelve la primera tupla de teléfonos
       ordenadas según el momento de la llamada.
       por nombre construido (r#i), o por índice.
       El constructor no necesita ningún parámetro.
       Los únicos métodos en la clase son:
       __init__(), add(d: datetime, ll: str), __getattr__(),
       __len__() (que devuelve el número de elementos),
       y __str__() (que devuelve el contenido del objeto como
       texto, en el formato: <formato_datetime_defecto>: 999999999, 999999999).
    """
    def __init__(self):
        self._modified = True
        self._cache = tuple()
        self._reg = {}

    @staticmethod
    def __datetime_cnv(d: datetime):
        """Convierte un datetime con microsegundos a otro sin él."""
        return datetime(d.year, d.month, d.day, d.hour, d.minute, d.second)

    def inserta(self, d: datetime, tlf: str):
        """Añade un teléfono a la lista para ese momento"""
        self._modified = True
        dm = RegistroTelefonico.__datetime_cnv(d)
        lls = self._reg.get(dm)

        if not lls:
            self._reg[dm] = [tlf]
        else:
            lls.append(tlf)

    def __crea_cache(self):
        if self._modified:
            self._cache = list(self._reg.items())
            self._cache.sort(key=lambda it: it[0])
            self._cache = tuple(self._cache)
            self._modified = False

    def __getattr__(self, item):
        if item == "get":
            self.__crea_cache()
            return lambda i: tuple(self._cache[i])
        elif item == "get_for":
            return lambda d: tuple(self._reg.get(d)) if self._reg.get(d) else tuple()

        raise AttributeError(item)

    def to_json(self):#, f):
        """
            Convertir los datos del objeto en JSON a un fichero.
            Formato:
                {
                    '2022-05-13 10:41:00': ["988387000", "988387002"],
                    '2022-05-13 10:41:35': ["988387001"]
                }
        """
        d_dump = {str(k): v for k, v in self._reg.items()}
        return json.dumps(d_dump)#, f)

    @staticmethod
    def from_json(str_json_data):# f):
        """
            Convertir los datos del fichero a JSON  y asignar el diccionario.
            Formato:
                {
                    '2022-05-13 10:41:00': ["988387000", "988387002"],
                    '2022-05-13 10:41:35': ["988387001"]
                }
        """
        d_dump = json.loads(str_json_data)# f)
        d_dump = {datetime.strptime(k, "%Y-%m-%d %H:%M:%S"): v for k, v in d_dump.items()}
        toret = RegistroTelefonico()
        toret._reg = d_dump
        return toret

    def filter(self, pred: callable):
        """Devolver aquellos elementos (completos) de la cache que cumplen pred."""
        return [tupla for tupla in self._cache if pred(tupla)]

    def __len__(self):
        return len(self._reg)

    def __str__(self):
        self.__crea_cache()

        return str.join("\n", [str(pair[0]) + ": "
                + ", ".join([tlf for tlf in pair[1]])
                for pair in self._cache])


if __name__ == "__main__":
    r = RegistroTelefonico()
    r.inserta(datetime(2022, 9, 13, 10, 41), "988387000")
    r.inserta(datetime(2022, 9, 13, 10, 41), "988387002")
    r.inserta(datetime(2022, 9, 13, 10, 41, 35), "988387001")
    print(r.get(0))
    print("Filtrado por segundo no 0: " + str(r.filter(lambda t: t[0].second != 0)))
    print("Filtrado primer tlf acabado en 02: " + str(r.filter(lambda t: t[1][0].endswith("01"))))

	# Modificado para que se pueda ejecutar en IDEOne,
	# Se pedía utilizar ficheros y json.dump()/json.load()
	# en lugar de json.dumps()/json.loads()
    json_data = r.to_json()
    print("Guardando: " + json_data)
    print("Recuperando:\n" + str(RegistroTelefonico.from_json(json_data)))
