def findPayment(loan, r, m):
    """Assumes: loan and r are floats, m an int. 
    Returns the monthly payment for a mortgage of size
    loan at a montly rate of r for m months"""
    return loan*((r*(1+r)**m)/((1+r)**m - 1))
    
class Mortgage(object):
    """Abstract class for building different kinds of mortgages"""
    def __init__(self, loan, annRate, mohths):
        """create a new mortgage"""
        self.loan = loan
        self.rate = annRate/12
        self.months = months
        self.paid = [0.0]
        self.owed = [loan]
        self.payment = findPayment(loan, self.rate, months)
        self.legend = None #description of mortgage
        
    def makePayment(self):
        """make a payment"""
        self.paid.append(self.payment)
        reduction = self.payment - self.owed[-1]*self.rate
        self.owed.append(self.owed[-1] -reduction)
        
    def getTotalPaid(self):
        """Return the total amount paid so far"""
        return sum(self.paid)
        
    def __str__(self):
        return self.legend
        
        


# fixed-rate mortgage
class Fixed(Mortgage):
    def __init__(self, loan, r, months):
        Mortgage.__init__(self, loan, r, months)
        self.legend = 'Fixed, ' + str(r*100) + '%'

# fixed-rate mortgage with up-front points
class FixedWithPts(Fixed):
    def __init__(self, loan, r, months, pts):
        Fixed.__init__(self, loan, r, months)
        self.pts = pts
        self.paid = [loan*pts/100]
        self.legend += ', ' + str(pts) + ' points'
        
# mortgages that changes interet rate after 48 months
class TwoRate(Mortgage):
    def __init__(self, loan, r, months, teaserRate, teaserMonths):
        Mortgage.__init__(self, loan, teaserRate, months)
        self.teaserMonths = teaserMonths
        self.nextRate = r/12
        self.legend = str(teaser.Rate*100\
            + '% for ' + str(self.teaserMonths)\
            + ' months, then ' + str(r*100) + '%'
            
    def makePayment(self):
        if len(self.paid) == self.teaserMonths +1:
            self.rate = self.nextRate
            self.payment = findPayment(self.owed[-1], self.rate, self.months - \
                                       self.teaserMonths)
        Mortgage.makePayment(self)
        
        
#helper function to try out alternatives
def compareMortgages(amt, years, fixedRate, pts, ptsRate,
                    varRate1, varRate2, varMonths):
    # creat alternative mortgages
    totMonths = years*12
    fixed1 = Fixed(amt, fixedRate, totMonths)
    fixed2 = FixedWithPts(amt, ptsRate, totMonths, pts)
    twoRate = TwoRate(amt, varRate2, totMonths, varRate1,
                      varmonths)
    morts = [fixed1, fixed2, towRate]
    
    #run experiment!
    for m in range(totMonths):
        for mort in morts:
            mort.makePayment()
            
    # report results
    for m in morts:
        print m
        print 'Total payments = $' + str(int(m.getTotalPaid()))
        
# amount borrowed: $200,000
# term: 30 years
#  option1: rate = 7%
#  option2: 3.25 points upfront, rate = 5 %
#  option3: 48 months of rate = 5%, then rate = 9.5%
"""
compareMortgages(amt=200000, years=30,
                 fixedRate=0.07,
                 pts=3.25, ptsRate=0.25,
                 varRate1=0.045,varRate2=0.095, varMonths=48)
                 """
                 
        