# person.py
# Walker M. White (wmw2)
# October 15, 2015
"""Class to rerpresent a genealogical tree"""
import sys

# Allow us to go really deep
sys.setrecursionlimit(999999999)

# We will cover this NEXT lecture
class Person(object):
    """Instance represents a person in a genealogical tree.
    
    Attributes:
        fname: First Name [str]
        lname: Last Name [str]
        mom: Mother [Person, None if not known]
        dad: Father [Person, None if not known]"""
    
    def __init__(self,fname,lname,mom=None,dad=None):
        """Creates a new instance of person
        
        Parameter fname: The first name
        Precondition: fname is a string
        
        Parameter lname: The last name
        Precondition: lname is a string
        
        Parameter mom: The mother of this person (optional)
        Precondition: mom is a Person or None
        
        Parameter dad: The father of this person (optional)
        Precondition: dad is a Person or None"""
        self.fname = fname
        self.lname = lname
        self.mom = mom
        self.dad = dad
    
    def __str__(self):
        """Returns: a string representation of this person"""
        result = '(Person: '+self.name()
        
        if not self.mom is None:
            result += '; mom: '+self.mom.name()
            
        if not self.dad is None:
            result += '; dad: '+self.dad.name()
        
        return result+')'
    
    def __repr__(self):
        """Returns: an unambigious string representation of this person"""
        return str(self)
    
    def name(self):
        """Returns: the full name of this person"""
        return self.fname+' '+self.lname


# Recursive functions
def num_ancestors(p):
    """Returns: number of known ancestors of p
    
    Does not include p, so the answer might be 0.
    
    Parameter p: The initial family member
    Precondition: p is a Person (and not None)"""
    # Base case
    if p.mom == None and p.dad == None:
        return 0
    
    # Recursive step
    moms = 0
    if not p.mom == None:
        # Do not forget to include mom as well.
        moms = 1+num_ancestors(p.mom)

    dads = 0
    if not p.dad == None:
        # Do not forget to include dad as well.
        dads = 1+num_ancestors(p.dad)
    
    return moms+dads


def num_with_name(p,name):
    """Returns: number of people with name as a first name.
    
    This function does not just check ancestors; it checks
    p as well.
    
    Parameter p: The initial family member
    Precondition: p is a Person (and not None).
    
    Parameter name: The name to match
    Precondition: name is a string"""
    # Check we match
    match = 1 if p.fname == name else 0
    
    # Base case
    if p.mom == None and p.dad == None:
        # Conditional expression
        return match
        
    # Recursive step
    moms = 0
    if not p.mom == None:
        # No need to check mom; handled in recursive call.
        moms = num_with_name(p.mom,name)

    dads = 0
    if not p.dad == None:
        # No need to check dad; handled in recursive call.
        dads = num_with_name(p.dad,name)
    
    return moms+dads+match