import math
from constants import *

"""A set of helper-functions"""


def calculate_mean_extremes(s):
	"""given a list of boxes/overlaps calculate the mean of the total and the extremes of the total"""
	mean = s[0].mean
	curr_weight = s[0].weight
	extremes = s[0].extremes
	for o in s[1:]:
		mean = scalar(o.weight / (o.weight + curr_weight), o.mean)
		curr_weight += o.weight
		extremes = extremify(extremes, o.extremes)
	return (mean, extremes)

def scalar(a, (x,y)):
	"""scale a 2D-vector by a"""
	return (a*x, a*y)

def mid((x,y), (x2,y2)):
	"""mid point between two 2D-vectors"""
	return ((x+x2) / 2, (y + y2) / 2)
	
def add((x,y), (a,b)):
	"""add two 2D-vectors"""
	return (x+a, y+b)

def add_to_list(v, ls):
	return [add(v,l) for l in ls]
	
def neg((x,y)):
	"""get opposite of a 2D-vector"""
	return (-x, -y)
	
def extremify((e1, n1, w1, s1), (e2, n2, w2, s2)):
	"""get east, north, west and south extremes of two such extreme sets"""
	e = max([e1, e2], key=lambda item:item[0])
	n = max([n1, n2], key=lambda item:item[1])
	w = min([w1, w2], key=lambda item:item[0])
	s = min([s1, s2], key=lambda item:item[1])
	return (e, n, w, s)
	
def to_vec((angle, length)):
	"""translate a polar coordinate to 2D-vector"""
	return scalar(length, (math.cos(angle), math.sin(angle)))

def to_pol((x,y)):
	""""translate a 2D-vector to polar coordinates"""
	if x == 0:
		if y > 0:
			return (math.pi/2, y)
		elif y < 0:
			return (math.pi*3/2, -y)
		raise Exception("Error in to_pol:", x, y)
	return (math.atan2(y,x), length((x,y)))

def go_percent_clockwise(fl, (x,y)):
	"""go fl percent clockwise from current vector (x,y)
	   watch out, that fl is really a float!"""
	pol = to_pol((x,y))
	return to_vec((pol[0] + fl*2*math.pi, pol[1]))

def add_rad(alpha, v):
	pol = to_pol(v)
	pol = (pol[0] + alpha, pol[1])
	return to_vec(pol)
	
def get_extremes(l):
	"""get east, north, west and south extremes of 4 points
	   useful for later calculations like 'did the bird hit the ground?' """
	(max_x, max_y, min_x, min_y) = (l[0], l[0], l[0], l[0])
	for l_i in l[1:]:
		(max_x, max_y, min_x, min_y) = (tmax(max_x, l_i, 0), tmax(max_x, l_i, 1), tmin(max_x, l_i, 0), tmin(max_x, l_i, 1))
	return (max_x, max_y, min_x, min_y)

def tmax(old, new, i):
	if old[i] <= new[i]:
		return new
	return old

def tmin(old, new, i):
	if old[i] >= new[i]:
		return new
	return old
	
def length((x,y)):
	"""length of a 2D-vector"""
	return math.sqrt(x*x + y*y)

def norm((x,y)):
	"""normalize a 2D-vector"""
	l = length((x,y))
	return (x/l, y/l)

def norm_l(l, (x,y)):
	"""a vector in same direction, but length l"""
	return scalar(l, norm((x,y)))

def scale_to(v1, v2):
	"""a vector of length(v1) in direction v2"""
	return norm_l(length(v1), v2)
	
def weight((x,y,z)):
	"""the weight of a box"""
	return x*y*z/2

def dot_product((x,y),(x2,y2)):
	return x*x2 + y*y2
