# ALS Parcial 2b 2018/19 MIT License Baltasar <jbgarcia@uvigo.es>


"""
    1. La clase Contacto guarda los datos: nombre, apellidos, tlf (teléfono), y email, utilizando propiedades para acceder a la información. Los métodos de la clase serán: __init__(), __str_() (que devuelve los datos en formato <apellidos>, <nombre> (<tlf>): <email>), y __getattr__(). El acceso a nombre_completo (que devuelve el nombre en el formato <apellidos>, <nombre>) se hará mediante __getattr__(), no existiendo otra propiedad, atributo o método que lo haga.

    	c1 = Contacto(“Baltasar”, “Garcia”, 988368891, “jbgarcia@uvigo.es”)
	print(c1.nombre)					# Baltasar
	print(c1.nombre_completo)				# García, Baltasar


    2. Cree los métodos to_csv(f) y from_csv(f). El primero escribe la codificación CSV del objeto como un archivo, la segunda toma un archivo con contenido en formato CSV y crea un objeto con dicho contenido. Será necesario crear un lector r (csv.reader) sobre el archivo f y leer la fila CSV con next(r), mientras que para guardar datos se creará un escritor w (csv.writer) y se guardará la información con w.writerow(l). El orden de guardado de los atributos será el mismo que el utilizado para la construcción de los objetos Contacto.
       
	c1 = Contacto(“Baltasar”, “Garcia”, 988368891, “jbgarcia@uvigo.es”)

	with open(“datos.csv”, “wt”) as f:
		c1.to_csv(f)

	with open(“datos.csv”, “rt”) as f:
		print(str(Contacto.from_csv(f)))		# García, Baltasar (988368891): ...


    3. Escriba la función lista_contactos(lc, f), que recibe como parámetros una lista de registros y una función que define cómo combinar dos contactos. Deben utilizarse exclusivamente lambdas, y para esta función en particular, reducir la lista.

	listado = lista_contactos([c1, c2, c3], lambda c1, c2: str(c1) + “\n” + str(c2))
	print(listado)					# Baltasar…

"""


import csv

class Contacto:
    def __init__(self, nombre, apellidos, tlf, email):
        self._nombre = nombre
        self._apellidos = apellidos
        self._tlf = tlf
        self._email = email
        
    @property
    def nombre(self):
        return self._nombre
    
    @property
    def apellidos(self):
        return self._apellidos
    
    @property
    def tlf(self):
        return self._tlf
    
    @property
    def email(self):
        return self._email
    
    @staticmethod
    def from_csv(f):
        reader = csv.reader(f)
        data = next(reader)
        toret = Contacto(data[0], data[1], int(data[2]), data[3])
        return toret

    def to_csv(self, f):
        writer = csv.writer(f)
        writer.writerow([self.nombre, self.apellidos, self.tlf, self.email])
    
    def __getattr__(self, s):
        if s == "nombre_completo":
            return self.apellidos + ", " + self.nombre
        else:
        	raise AttributeError(s)
    
    def __str__(self):
        return str.format("{} ({}): {}", self.nombre_completo, self.tlf, self.email)
    

lista_contactos = lambda l, f:(
            "" if not l or l == []
            else f(l[0], lista_contactos(l[1:], f)))


import unittest
import io


class TestContacto(unittest.TestCase):
    def setUp(self):
        self.c1 = Contacto("Baltasar", "García", 988368891, "jbgarcia@uvigo.es")
        self.todos_contactos = [self.c1]
        self.todos_resultados = [
            "García, Baltasar (988368891): jbgarcia@uvigo.es",
        ]
        
    def testContactoStr(self):
        self.assertEqual(len(self.todos_resultados), len(self.todos_contactos))
        for i, resultado in enumerate(self.todos_resultados):
            resultado_contacto = TestContacto.prepara_resultado(str(self.todos_contactos[i]))
            resultado = TestContacto.prepara_resultado(resultado)
            self.assertEqual(resultado, resultado_contacto)
                    
    def testContactoNombreCompleto(self):
        for c in self.todos_contactos:
            nombre_completo = c.apellidos + ", " + c.nombre
            self.assertEqual( nombre_completo, c.nombre_completo)
        
    def testContactoCSV(self):
        for c in self.todos_contactos:
            with io.StringIO() as s:
                c.to_csv(s)
                self.assertEqual(",".join([c.nombre, c.apellidos, str(c.tlf), c.email]), s.getvalue().strip())
            
    def testLoadFromCSV(self):
        for i, c1 in enumerate(self.todos_contactos):
            with io.StringIO(",".join([c1.nombre, c1.apellidos, str(c1.tlf), c1.email])) as f:
                c2 = Contacto.from_csv(f)
                self.assertEqual(c1.nombre, c2.nombre)
                self.assertEqual(c1.apellidos, c2.apellidos)
                self.assertEqual(c1.tlf, c2.tlf)
                self.assertEqual(c1.email, c2.email)
            
    def testListaRegistros(self):
        resultado = lista_contactos(self.todos_contactos, lambda x, y: str(x) + "\n" + str(y)).strip()
        todos_resultados = "\n".join([str(c) for c in self.todos_contactos])
        self.assertEqual(todos_resultados, resultado)
        
    @staticmethod
    def prepara_resultado(s):
        return s.strip().replace('\'', '"').replace(' ', "")


if __name__ == "__main__":
    unittest.main()
