""" Demonstration of Inheritance """

from turtle import Turtle
from lectures.week2.point import Point


class Shape:
    """
    A shape that can draw itself, move, and
    report area and perimeter.

    === Attributes ===
    @type corners: list[Point]
       corners of this Shape
    @type perimeter: float
       length to traverse corners
    @type area: float
        area of this Shape
    """
    def __init__(self, corners):
        """
        Create a new Shape self defined by its corners

        @type self: Shape
        @type corners: list[Point]
        @rtype: None
        """
        # shallow copy of corners
        self.corners = corners[:]
        self._turtle = Turtle()
        self._set_perimeter()
        self._set_area()

    def __eq__(self, other):
        """ Return whether this Shape is equivalent
        to other

        @type self: Shape
        @type other: Shape | Any
        @rtype: bool
        """
        return (type(self) == type(other) and
                # self.corners == other.corners and
                self.perimeter == other.perimeter and
                self.area == other.area)

    def __str__(self):
        """ Return a string representation of this Shape

        @type self: Shape
        @rtype: str

        >>> print(Shape([Point(0, 0), Point(0, 1), Point(1, 0)]))
        Shape([(0, 0), (0, 1), (1, 0)])
        """

        # classes have a __name__
        return type(self).__name__ + \
               " a string that has all the points nicely formatted"

    def _set_perimeter(self):
        """
        Set Shape self's perimeter to the sum of the distances
        between corners.

        @type self: Shape
        @rtype: None
        """
        distance_list = []
        for i in range(len(self.corners)):
            distance_list.append(self.corners[i].distance(
                    self.corners[i - 1]))
        self._perimeter = sum(distance_list)

    def _get_perimeter(self):
        """
        Return the perimeter of this Shape

        @type self: Shape
        @rtype: float
        """
        return self._perimeter

    # perimeter is immutable --- no setter method in property
    perimeter = property(_get_perimeter)

    # area will be computed differently for most shapes
    def _set_area(self):
        """
        Set the area of Shape self to the shape of
        its sides.

        @type self: Shape
        @rtype: None
        """
        # impossible so we have the method defined, but it doesn't do
        # anything meaningful
        # the actual behaviour should be implemented in the subclass
        self._area = -1

    def _get_area(self):
        """
        Return the area of Shape self.

        @type self: Shape
        @rtype: float
        """
        return self._area

    # area is immutable --- no setter method in property
    area = property(_get_area)

    def move_to(self, x_offset, y_offset):
        """
        Move Shape self to a new position by adding
        Point offset_point to each corner.

        @type self: Shape
        @type x_offset: float | int
        @type y_offset: float | int
        @rtype: None
        """
        for c in self.corners:
            c.move(x_offset, y_offset)

    def draw(self):
        """
        Draw Shape self.

        @type self: Shape
        @rtype: None
        """
        self._turtle.penup()
        self._turtle.goto(self.corners[-1].x, self.corners[-1].y)
        self._turtle.pendown()
        for i in range(len(self.corners)):
            self._turtle.goto(self.corners[i].x, self.corners[i].y)
        self._turtle.penup()
        self._turtle.goto(0, 0)


if __name__ == "__main__":
    import doctest
    doctest.testmod()
    s = Shape([Point(1, 1), Point(1, 2), Point(2, 2), Point(2, 1)])
    print(s.area)
    print(s.perimeter)
    s.draw()
