# -*- coding: utf-8 -*-
import estructura
from lista import *

#fecha: dia(int) mes(int) año(int)
estructura.crear("fecha","dia mes ano")
#personaje: nombre(str) nace(fecha) muere(fecha)
estructura.crear("personaje", "nombre nace muere")
p1 = personaje("b",fecha(17,1,1876),fecha(28,4,1934)) #”b” nace el 17 de enero de 1876 y muere el 28 de abril de 1934
p2 = personaje("c",fecha(7,5,1853),fecha(11,9,1935))
p3 = personaje("a",fecha(28,4,1921),fecha(20,1,2000))

L1 = lista(p1, lista(p2, lista(p3, None)))

# Pregunta 1

# naceOMuereEnFecha: lista(personaje), fecha -> lista(personaje)
# Retorna una lista con todos los personajes de L que nacieron o murieron el mismo día y mes que la fecha f
# Ejemplo: naceOMuereEnFecha(L, f) entrega lista(p1, lista(p3, None))
def naceOMuereEnFecha(L, f):
    if L == None:
        return None
    else:
        dia = f.dia
        mes = f.mes
        naceActual = cabeza(L).nace
        muereActual = cabeza(L).muere
        if (naceActual.dia == dia and naceActual.mes == mes) or \
            (muereActual.dia == dia and muereActual.mes == mes):
            return lista(cabeza(L), \
                         naceOMuereEnFecha(cola(L), f))
        else:
            return naceOMuereEnFecha(cola(L), f)

assert naceOMuereEnFecha(L1, fecha(28, 4, 2016)) == lista(p1, lista(p3, None))


# Pregunta 2

# Todo lo que viene no es parte de la pregunta, es sólo el código para
# crear un ABB a partir de una lista. Lo hice para crear el abb correspondiente
# a la lista de la P1, pero creo que igual les puede servir como ejercicio
#######################################################################
estructura.crear("nodo", "valor izq der")

def insertarPersonaje(valor, arbol):
    if arbol == None:
        return nodo(valor, None, None)
    else:
        nombreActual = arbol.valor.nombre
        if nombreActual > valor.nombre:
            return nodo(arbol.valor, \
                        insertarPersonaje(valor, arbol.izq),
                        arbol.der)
        else:
            return nodo(arbol.valor, \
                        arbol.izq, \
                        insertarPersonaje(valor, arbol.der))

def listaAArbol(L, arbol):
    if L == None:
        return arbol
    else:
        actual = cabeza(L)
        arbol = insertarPersonaje(actual, arbol)
        return listaAArbol(cola(L), arbol)

########################################################################
# Fin sección que no es parte de la pregunta

abb = listaAArbol(L1, None)

# mayorOIgualFecha: fecha, fecha -> boolean
# Retorna True en caso de que f sea mayor o igual a limite (considerando sólo
# el día y mes), False en caso contrario
# Ejemplo: mayorOIgualFecha(fecha(22, 4, 2016), fecha(21, 4, 1912)) entrega
# True
def mayorOIgualFecha(f, limite):
    if f.mes > limite.mes:
        return True
    elif f.mes == limite.mes:
        return f.dia >= limite.dia
    else:
        return False

assert mayorOIgualFecha(fecha(22, 4, 2016), fecha(21, 4, 1912))

# menorOIgualFecha: fecha, fecha -> boolean
# Retorna True en caso de que f sea menor o igual a limite (considerando sólo
# el día y mes), False en caso contrario
# Ejemplo: menorOIgualFecha(fecha(22, 4, 2016), fecha(21, 4, 1912)) entrega
# False
def menorOIgualFecha(f, limite):
    if f.mes < limite.mes:
        return True
    elif f.mes == limite.mes:
        return f.dia <= limite.dia
    else:
        return False
assert not menorOIgualFecha(fecha(22, 4, 2016), fecha(21, 4, 1912))

# nPersonajesQueNacieronEnRango: nodo, fecha, fecha -> int
# Retorna la cantidad de personajes en abb que nacieron entre los días y meses
# definidos en f1 y f2, ambos inclusive
# Ejemplo: nPersonajesQueNacieronEnRango(abb, fecha(21, 04, 2016), fecha(20,05, 2016)) entrega 2
def nPersonajesQueNacieronEnRango(abb, f1, f2):
    if abb == None:
        return 0
    else:
        naceActual = abb.valor.nace
        if mayorOIgualFecha(naceActual, f1) and \
                menorOIgualFecha(naceActual, f2):
            return 1 + nPersonajesQueNacieronEnRango(abb.izq, f1, f2) + \
                        nPersonajesQueNacieronEnRango(abb.der, f1, f2)
        else:
            return nPersonajesQueNacieronEnRango(abb.izq, f1, f2) + \
                    nPersonajesQueNacieronEnRango(abb.der, f1, f2)

assert nPersonajesQueNacieronEnRango(abb, fecha(21, 04, 2016), fecha(20,05, 2016)) == 2
