"""
More object oriented programming.
http://openbookproject.net/thinkcs/python/english2e/ch15.html
see also http://www.freenetpages.co.uk/hp/alan.gauld/tutclass.htm
"""


class Rectangle :
    """A class that represents a rectangle"""
    def __init__(self, width=1, height=1) :
        """width - the width of the rectangle
        height - the height of the rectangle"""

        self.width = width
        self.height = height
    def duplicate(self) :
        return Rectangle(self.width, self.height)
    def area(self) :
        """returns the area of the rectangle"""
        return self.width * self.height
    def perimeter(self) :
        """returns the perimiter of the rectangle"""
        return 2 * self.width + 2 * self.height
    def scale(self, s) :
        """rescale the size of the rectangle by the given amount"""
        self.height *= s
        self.width *= s
    def __repr__(self) :
        return "Rectangle with width = %f height = %f" % (self.width, self.height)

rect1 = Rectangle(1, 2)
rect2 = Rectangle()


rect3 = rect1
# Let's modify rect3 now:
rect3.width = 3
print rect3
print rect1

# Modifying rect3 has changed rect1!  That is because they both
# point to the same Rectangle object.

# Let's define another type of shape:

import math
class Circle :
    """A class that represents a circle"""
    def __init__(self, radius=1) :
        """radius - the radius of the circle"""
        self.radius = radius
    def duplicate(self) :
        return Circle(self.radius)
    def area(self) :
        """returns the area of the rectangle"""
        return math.pi * self.radius * self.radius
    def perimeter(self) :
        """returns the perimiter of the rectangle"""
        return 2 * math.pi * self.radius
    def scale(self, s) :
        """rescale the size of the rectangle by the given amount"""
        self.radius *= s
    def __repr__(self) :
        return "Circle with radius = %f" % self.radius

circ1 = Circle(2)
circ2 = Circle()

# Note that both classes present essentially the same interface, i.e.
# the same set of methods.
# We can exploit this e.g. when using a list of shapes:

shape_list = [Circle(2), Circle(5), Rectangle(1,2), Circle(1), Rectangle(3,5)]
for shape in shape_list :
    print "The area is: ", shape.area()

# Naming convention:  Class names begin with a capital letter (Circle, Rectangle).