"""This module contains code from
Think Python by Allen B. Downey
http://thinkpython.com

Copyright 2012 Allen B. Downey
License: GNU GPLv3 http://www.gnu.org/licenses/gpl.html

"""

import math

from Wobbler import *


class Missed(Exception):
    """Exception raised when a turtle tries to tag someone too far away."""


class Tagger(Wobbler):
    """Represents a Turtle that plays tag."""

    def __init__(self, world, speed=1, clumsiness=60, color='red'):

        # call the __init__ method from Wobbler to initialize
        # world, speed, clumsiness, and color.
        Wobbler.__init__(self, world, speed, clumsiness, color)

        # then initialize the additional attributes that Taggers have
        self.it = 0
        self.sulking = 0

    def steer(self):
        """Steers the Wobbler in the general direction it should go.

        Postcondition: the Wobbler's heading may be changed, but
        its position may not.
        """
        # if sulking, decrement the sulking clock
        if self.sulking > 0:
            self.sulking -= 1
            if self.sulking == 0:
                self.color = 'red'
                self.speed = self.old_speed
            return

        # if out of bounds, turn toward the center
        if self.distance() > 200:
            self.turn_toward(0, 0)
            return

        # if not it, just wander
        if not self.it:
            return

        # if it, chase the closest player
        target = self.closest(self.world.animals)
        try:
            self.apply_tag(target)
        except Missed:
            self.chase(target)
        

    def turn_toward(self, x=0, y=0):
        """Turns to face the given point.

        x, y: point to turn toward
        """
        self.heading = self.away(x, y) + 180
        self.redraw()

    def away(self, x=0, y=0):
        """Computes the heading away from the given point.

        x, y: point to face away from
        """
        dx = self.x - x
        dy = self.y - y
        heading = math.atan2(dy, dx)
        return heading * 180 / math.pi

    def distance(self, x=0, y=0):
        """Computes the distance from this turtle to the given point.

        x, y: point to find distance to
        """
        dx = self.x - x
        dy = self.y - y
        return math.sqrt(dx**2 + dy**2)

    def distance_from(self, other):
        """Computes the distance between turtles.

        other: Turtle object
        """
        return self.distance(other.x, other.y)

    def youre_it(self):
        """Makes this turtle it."""
        self.it = 1
        self.old_speed = self.speed
        self.old_color = self.color
        self.speed = 0
        self.color = 'blue'
        self.sulking = 200
        self.redraw()

    def not_it(self):
        """Makes this turtle not it."""
        self.it = 0
        self.color = self.old_color
        self.redraw()

    def flee(self, other):
        """Faces away from the other turtle.

        other: Turtle object
        """
        self.heading = self.away(other.x, other.y)
        
    def chase(self, other):
        """Faces the other turtle.

        other: Turtle object
        """
        self.turn_toward(other.x, other.y)

    def closest(self, others):
        """Return closest animal in the list (other than self).

        others: list of Animals
        """
        t = [(self.distance_from(animal), animal)
              for animal in others if animal is not self]
        (distance, animal) = min(t)
        return animal

    def apply_tag(self, other):
        """Tried to tag the other turtle.

        If it is too far away, raises an exception.

        other: Turtle object
        """
        if self.distance_from(other) < 10:
            self.not_it()
            other.youre_it()
        else:
            raise Missed


if __name__ == '__main__':
    world = make_world(Tagger)
    world.animals[0].youre_it()
    world.mainloop()
