"""
Operator overloading
http://openbookproject.net/thinkcs/python/english2e/ch15.html#operator-overloading
"""


# We've seen that we can use the addition operator to "add" all kinds of things
# other than numbers, e.g. lists and strings.

# What does it mean to add Point objects?
# Recall that a point object has an x and y coordinates.
# Given two Point objects p1 and p2 we'd like their sum to be a point
# object whose x coordinate equals p1.x + p2.x and whose y coordinate
# equals p1.y + p2.y.
# We can do this by providing an __add__ methods as follows:

import math
class Point :
    """Point is a class that stores a two dimensional point"""
    def __init__(self, x=0, y=0) :
        self.x = x
        self.y = y
    def __add__(self, other) :
        """add two Point objects"""
        return Point(self.x + other.x, self.y + other.y)
    def __repr__(self) :
        return "Point object with x = %d, y = %d" % (self.x, self.y)


p1 = Point(3, 4)
p2 = Point(5, 7)
p3 = p1 + p2
print p3

# Note that under the hood this is translated to something like:
p3 = p1.__add__(p2)

# You can similarly overload the subtratction operator.

# Overloading the multiplication operator is more interesting.
# First, what does it mean to multiply two Point objects?  That is not obvious,
# and we could do it by defining the __mul__ method.  This method assumes that
# the other operand is also a Point object.
# What about multiplying a Point object by a number?  If the left operand is a
# primitive type you use __rmul__ :

import math
class Point :
    """Point is a class that stores a two dimensional point"""
    def __init__(self, x=0, y=0) :
        self.x = x
        self.y = y
    def __add__(self, other) :
        """add two Point objects"""
        return Point(self.x + other.x, self.y + other.y)
    def __mul__(self, other) :
        return Point(other * self.x,  other * self.y)
    def __rmul__(self, other) :
        """multiply a Point object by a number"""
        return Point(other * self.x,  other * self.y)
    def __repr__(self) :
        return "Point object with x = %d, y = %d" % (self.x, self.y)

p = Point(3, 4)
print p1 * 3
print 3 * p1

# By providing a __cmp__ function we can overload the comparison operator:

class Person (object) :
    """A class for storing information about a person"""
    def __init__(self, first_name, last_name) :
        self.first_name = first_name
        self.last_name = last_name
    def __cmp__(self, other) :
        print 'comparing'
        if self.last_name > other.last_name :
            return 1
        elif self.last_name < other.last_name :
            return 1
        if self.first_name > other.first_name :
            return 1
        elif self.first_name < other.first_name :
            return -1
        return 0
    def __repr__(self) :
        return "Person with Name = %s %s" % (self.first_name, self.last_name)

a = Person("Asa", "Ben-Hur")
b = Person("John", "Cleese")
a < b