from .shape import gds_shape
from .shape_info import shape_bottom_left, shape_size, shape_orientation
from .size_info import gds_size_info
from .coord import coord2
from .transforms.magnification import gds_magnification
from .transforms.stretch import shape_scale
from .transforms.translation import gds_translation, shape_translate

import numpy

__all__ = ["shapes_fit"]

def shape_fit (coordinates, bottom_left, top_right):
	ret_coords = gds_shape()
	#rescale
	size = shape_size(coordinates)
	box_size = shape_size([bottom_left, top_right])
	scale_factor = min([box_size[0]/size[0], box_size[1]/size[1]])
	ret_coords = shape_scale(coordinates, (scale_factor, scale_factor))
	#translate
	bl = shape_bottom_left(coordinates)
	translation = (bottom_left[0] - bl[0], bottom_left[1] - bl[1])
	ret_coords = shape_translate(ret_coords, translation)
	return ret_coords

# fit multiple shapes
def shapes_fit (shapes, bottom_left, top_right):
	ret_shapes = []
	#get the extent of all shapes
	new_shapes = [gds_shape(s) for s in shapes]
	
	SI = gds_size_info()
	for s in new_shapes:
		SI += s.size_info()
	bl = coord2(SI.left, SI.bottom)
	tr = coord2(SI.right, SI.top)
	new_size = gds_size_info(left = bottom_left[0], right = top_right[0], bottom = bottom_left[1], top = top_right[1])
	scale_factor = min([new_size.width/SI.width, new_size.height/SI.height])
	translation = (bottom_left[0] - scale_factor * new_size.left, bottom_left[1] - scale_factor * new_size.bottom)
	T = gds_magnification((0.0, 0.0), scale_factor) + gds_translation(translation)
	for s in new_shapes:
		ret_shapes.append(s.transform_copy(T))
	return ret_shapes


def shape_remove_identicals(shape):
	#removes two subsequent identical points
	S = gds_shape(shape)
	return S.remove_identicals()

def shape_delete_loops(coordinates):
	#coordinates = shape_remove_identicals(coordinates)
	## eliminate backloop
	#if len(coordinates) <= 3:
		#return coordinates

	#nc = []
	#nc.extend(coordinates)

	#i = 0
	#while i < len(nc) - 2:
		#c1 = nc[i]
		#c2 = nc[i+1]
		#k = i + 2
		#while k < len(nc)-1:
			#c3 = nc[k]
			#c4 = nc[k+1]
			#if lines_cross(c1, c2, c3, c4):
				#nc[i+1] = intersection(c1,c2,c3,c4)
				#del nc[i+2: k+1]
				#k = i+2
				#c2 = nc[i+1]
			#else:
				#k += 1 
		#i += 1
	#return nc
	if len(coordinates) <= 3:
		return coordinates

	nc = gds_shape(coordinates).remove_identicals().__points__
	# eliminate backloop

	dels = set()
	i = -1
	L = len(nc)
	while i < L - 2:
		i += 1
		if i in dels:
			continue
		c1 = nc[i]
		c2 = nc[i+1]
		k = i + 2
		while k < L-1:

			c3 = nc[k]
			c4 = nc[k+1]
			if lines_cross(c1, c2, c3, c4):
				nc[i+1] = intersection(c1,c2,c3,c4)
				dels.update(range(i+2, k+1))
				c2 = nc[i+1]
			k += 1 
	return numpy.delete(nc, dels, 0)


def shape_grow(coordinates, amount):
	coordinates = shape_remove_identicals(coordinates)
	clockwise = shape_orientation(coordinates)
	if clockwise:
		amount = - amount

	new_coords = []

	L = len(coordinates)
	if coordinates[0] == coordinates[-1]:
		L -= 1
	for i in range(L):

		x = coordinates[i][0]
		y = coordinates[i][1]
		angle1 = angle_rad(coordinates[i], coordinates[(i-1)%L])
		angle2 = angle_rad(coordinates[(i+1)%L], coordinates[i])
		angle = angle1 + 0.5* ( angle2 - angle1 + pi )%(pi) - 0.5*pi
		turn = (angle2 - angle1)%(2*pi)
		if (abs(turn - pi) < 1E-6) and (not coordinates[i]==coordinates[(i-1)%L]) and (not coordinates[i]==coordinates[(i+1)%L]):
			print >> sys.stderr, "Error:Growing a shape with a 180 degree bend  is not possible"
			raise SystemExit

		margin = 0.1
		if  (turn > pi/2 + margin) and (turn < 3 * pi/2 - margin) and not clockwise:
			angle_x = angle1 + angle2 + 3 * pi / 2.0
			Lx = abs(amount / cos(angle_x))
			c_new = (x - Lx * cos(angle2), y - Lx * sin(angle2))
			new_coords.append(c_new)
			angle_x = angle2 - angle1 - pi / 2.0
			Lx = abs(amount / cos(angle_x))
			c_new = (x + Lx * cos(angle1), y + Lx * sin(angle1))
			new_coords.append(c_new)
		else:
			w = amount / abs(cos(turn/2.0))
			c_new = (x + w*sin(angle), y - w* cos(angle))

			new_coords.append(c_new)

	if not L==len(coordinates):
		new_coords.append(new_coords[0])

			
	new_coords = shape_delete_loops(new_coords)
	return new_coords

