# L-26 MCS 260 Fri 11 Mar 2016 : class Poly

"""
With object-oriented programming we hide the specific data structure
used to store an object and focus on the mathematical functionality.
We define a polynomial as a callable object.
"""

class Poly(object):
    """
    Defines a polynomial in one variable.
    """
    def __init__(self, c=0, p=0):
        """
        Defines a monomial with coefficient c and power p.
        """
        if c == 0:
            self.__terms = []
        else:
            self.__terms = [(c, p)]

    def __str__(self):
        "returns a polynomial as a string"
        prt = ''
        for mon in self.__terms:
            prt += '%+2.f*x^%d' % (mon[0], mon[1])
        if prt == '':
            return '0'
        else:
            return prt

    def addmon(self, cff, deg):
        """
        Adds a monomial with coefficient cff and degree deg.
        """
        if cff != 0:
            done = False
            for i in range(0, len(self.__terms)):
                mon = self.__terms[i]
                if mon[1] == deg:
                    newcff = cff + mon[0]
                    del(self.__terms[i])
                    if newcff != 0:
                        self.__terms.append((newcff, deg))
                    done = True
                    break
            if not done:
                self.__terms.append((cff, deg))

    def __add__(self, other):
        """
        Returns the sum of two polynomials.
        """
        result = Poly()
        for mon in self.__terms:
            result.addmon(mon[0], mon[1])
        for mon in other.__terms:
            result.addmon(mon[0], mon[1])
        return result

    def __call__(self, x):
        """
        Returns the value at x.
        """
        result = 0
        for (cff, deg) in self.__terms:
            result += cff*x**deg
        return result
