"""Inheritance in python
"""


# This module defines several types of shapes (Rectangle, Circle)
# using inheritance from a base class called Shape.

# In inheritance:
# The more general class is called the base class or superclass.
# The more specific class is called the derived class or subclass.

# First we will need the Point class we have already defined:

import math
class Point (object) :
    """Point is a class that stores a two dimensional point"""
    def __init__(self, x=0, y=0) :
        self.x = x
        self.y = y
    def distance_to_origin(self) :
        """compute the distance of a point from the origin"""
        return math.sqrt(self.x*self.x + self.y *self.y)
    def distance(self, other) :
        """compute the distance between a point object and another
        point object"""

        return math.sqrt((self.x - other.x)**2 +
                         (self.y - other.y)**2)
    def duplicate(self) :
        return Point(self.x, self.y)
    def __repr__(self) :
        return "Point object with x = %d, y = %d" % (self.x, self.y)

class Shape (object) :
    def __init__(self, x=0, y=0) :
        """creates an instance of a Shape with a location given
        by x and y"""

        self.location = Point(x, y)
    def move(self, x, y) :
        """move a shape object to a location given by x and y"""
        self.location = Point(x, y)
    def distance_to_origin(self) :
        return self.location.distance_to_origin()
    def distance(other) :
        return self.location.distance(other.location)
    def __repr__(self) :
        return "A shape located at: " + str(self.location)


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

        self.width = width
        self.height = height
        Shape.__init__(self, x, y)
    def duplicate(self) :
        return Rectangle(self.width, self.height, self.x, self.y)
    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()

# When we define a method in the derived class it overrides the corresponding
# method from the base class.

# Note that you have to call the constructor of the base class explicitly:
# Shape.__init__(self, location)

import math
class Circle (Shape) :
    """A class that represents a circle"""
    def __init__(self, radius=1, x=0, y=0) :
        """radius - the radius of the circle"""
        Shape.__init__(self, x, y)
        self.radius = radius
    def duplicate(self) :
        return Circle(self.radius, self.x, self.y)
    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()

# Why use inheritance?
# - Code reuse - code from the base class does not need to be repeated.
#   Leads to easier maintenance of the code.
# - Adding functionality to the base class automatically reflects in the
#   Derived classes.