import math

class Point:
    def __init__(self, x,y):
        self.x = x
        self.y = y

    def magnitude(self):
        return math.sqrt(self.x*self.x + self.y*self.y)

    def _applyVectorFunc(self, other, f):
        return Point(f(self.x, other.x), f(self.y, other.y))
    def _applyScalarFunc(self, a, f):
        return self._applyVectorFunc(Point(a,a), f)

    def __add__(self, other):
        return self._applyVectorFunc(other, lambda a,b: a+b)
    def __sub__(self, other):
        return self._applyVectorFunc(other, lambda a,b: a-b)
    def __mul__(self, a):
        return self._applyScalarFunc(a, lambda b,c: b*c)
    def __div__(self, a):
        return self._applyScalarFunc(a, lambda b,c: b/c)

    def __repr__(self):
        return "Point({}, {})".format(self.x, self.y)

def dot_product(a,b):
    return a.x * b.x + a.y * b.y

def angle_between(b,c):
    return math.acos(dot_product(b,c) / (b.magnitude() * c.magnitude()))

def to_degrees(a):
    return a * 360 / (2*math.pi)

def find_collision_point(target_pos, target_vel, interceptor_pos, interceptor_speed):
    k = target_vel.magnitude() / interceptor_speed
    c = (interceptor_pos - target_pos).magnitude()

    b_hat = target_vel
    c_hat = interceptor_pos - target_pos
    
    CAB = angle_between(b_hat, c_hat)
    ABC = math.asin(math.sin(CAB) * k)
    ACB = (math.pi) - (CAB + ABC)
    
    j = c / math.sin(ACB)
    a = j * math.sin(CAB)
    b = j * math.sin(ABC)


    t = b / target_vel.magnitude()
    collision_pos = target_pos + (target_vel * t)

    print "Collision pos: {}".format(collision_pos)
    print "Time: {}".format(t)

    print "Angle A: {}".format(to_degrees(CAB))
    print "Angle B: {}".format(to_degrees(ABC))
    print "Angle C: {}".format(to_degrees(ACB))

    print "a: {}".format(a)
    print "b: {}".format(b)
    print "c: {}".format(c)

target_pos = Point(120,40)
target_vel = Point(5,2)
interceptor_pos = Point(80,80)
interceptor_speed = 10

find_collision_point(target_pos, target_vel, interceptor_pos, interceptor_speed)