import sys
import pygame
import math

import globals

# -----------------------------------------------------------------------
# Object class
#   used to store an object that needs collision to be applied to it

class CollObject:
	
	def __init__(self, position, rad):
		self.pos = position
		self.r = rad
		self.vec = 0.0, 0.0

# -----------------------------------------------------------------------
# Line class
#   used to precalc some vaules for runtime use (speeds up math)

class Line:
		
	def __init__(self, p1x, p1y, p2x, p2y):
		self.x1 = p1x
		self.y1 = p1y
		self.x2 = p2x
		self.y2 = p2y
		
		self.a = self.y2 - self.y1
		self.b = self.x1 - self.x2
		self.c = self.x2 * self.y1 - self.x1 * self.y2
		
		self.c1 = (self.x1 + self.a) * self.y1 - self.x1 * (self.y1 + self.b)
		self.c2 = (self.x2 + self.a) * self.y2 - self.x2 * (self.y2 + self.b)
		
		temp = 0.0
		temp = self.a * self.a + self.b * self.b
		length = 0.0
		length = math.sqrt(temp)
		
		self.a /= length
		self.b /= length
		self.c /= length
		self.c1 /= length
		self.c2 /= length        
	

# -----------------------------------------------------------------------
# Collider class
#       usage: declare a collider object then apply 

class Collider:
	
	def __init__(self):
		# array of vector lines to collide with
		self.vectors = []
		self.linecount = 0
		self.diff = [0, 0]
	
	# ----------------------------------------------
	def AddLines(self, lines):
		for l in lines:
			newline = Line(l[0], l[1], l[2], l[3])
			self.linecount += 1
			self.vectors.append(newline)

	# ----------------------------------------------
	def AddLinesWithOffset(self, lines, pos):
		for l in lines:
			newline = Line(l[0]+pos[0], l[1]+pos[1], l[2]+pos[0], l[3]+pos[1])
			self.linecount += 1
			self.vectors.append(newline)

	# ----------------------------------------------
	def AddSwappedLines(self, lines):
		for l in lines:
			newline = Line(l[2], l[3], l[0], l[1])
			self.linecount += 1
			self.vectors.append(newline)
	
	# ----------------------------------------------
	def SphereClip(self, point1, point2):
		diff = [point2[0] - point1[0], point2[1] - point1[1]]
		if(diff[0] * diff[0] + diff[1] * diff[1] < point1[2] * point1[2]):
			return 1
		if(diff[0] * diff[0] + diff[1] * diff[1] < point2[2] * point2[2]):
			return 2
		return 0
	
	# ----------------------------------------------
	def SphereSphereClip(self, sphere1, sphere2):
		self.diff = sphere2[0] - sphere1[0], sphere2[1] - sphere1[1]
		rad = sphere1[2]
		if(sphere2[2] > sphere1[2]) : rad = sphere2[2]
			
		if(self.diff[0] * self.diff[0] + self.diff[1] * self.diff[1] < rad * rad):
			return 1
		return 0    
	
	# ----------------------------------------------
	# Clip a vector against a plane
	def ClipVectorPlane(self, obj, dist, brdist, a, b ):
		ratio = 0.0
		dot = 0.0
		sz = obj.r * 4
		if(dist - brdist == 0):
			# ratio = (obj.r - brdist)/(obj.r)
			dist += 0.01
			
		ratio = (obj.r - brdist)/(dist - brdist)
			
		dot = ratio * (obj.vec[0] * a + obj.vec[1] * b)
		
		# these if statements clip the velocity of the ball to a reasonable value
		tempx = obj.vec[0] - (a * dot)
		if(tempx > sz): tempx = sz
		if(tempx < -sz): tempx = -sz
		tempy = obj.vec[1] - (b * dot)
		if(tempy > sz): tempy = sz
		if(tempy < -sz): tempy = -sz
		obj.vec = [tempx, tempy]
		
	
	# ----------------------------------------------
	# iterate the lines and clip the obj against them
	def ClipVectorLines(self, obj, start, length ):
		
		if(length == -1):
			length = len(self.vectors)
			
		count = 0
		clippedcount = 0
		px = 0.0
		py = 0.0
		
# uncomment to see the red 'collision' ball
#        pygame.draw.circle(globals.screen, globals.red, obj.pos, int(obj.r), 2)
		
		for TLine in self.vectors:
			
			if((count >= start) and (count < start+length)):
						 
#                dotvec = obj.vec[0] * TLine.a - obj.vec[1] * TLine.b               
#                if(dotvec >= 0.0):               
				tx = obj.pos[0] + obj.vec[0]
				ty = obj.pos[1] + obj.vec[1]
				
				ldist = - TLine.b * tx + TLine.a * ty - TLine.c1
				rdist = - TLine.b * tx + TLine.a * ty - TLine.c2
				
				if((ldist >= 0.0) and (rdist < 0.0)):
					origdist = TLine.a * obj.pos[0] + TLine.b * obj.pos[1] + TLine.c
					dist = TLine.a * tx + TLine.b * ty + TLine.c
					
					if((dist < obj.r) and (origdist > 0.0)):
						self.ClipVectorPlane(obj, origdist, dist, TLine.a, TLine.b)
						clippedcount += 1
						
					# The following checks for endpoing collisions
					# Its important to remember that this code _should_ be included for more 'correct'
					# testing. But for performance reasons, I have chosen a simplistic implementation.
					
					#~ else:
						#~ ptest = 0
						
						#~ if(ldist < 0.0):
							#~ px = TLine.x1
							#~ py = TLine.y1
							#~ ptest = 1
						
						#~ if(rdist > 0.0):
							#~ px = TLine.x2
							#~ py = TLine.y2
							#~ ptest = 1
						
						#~ if(ptest == 1):
							#~ dist = (px - tx) * (px - tx) + (py - ty) * (py - ty)
							#~ odist = (px - obj.pos[0]) * (px - obj.pos[0]) + (py - obj.pos[1]) * (py - obj.pos[1])
							#~ if(dist < (obj.r * obj.r)):
								#~ dist = math.sqrt(dist)
								#~ a = (obj.pos[0] - px) / dist
								#~ b = (obj.pos[1] - py) / dist
								#~ self.ClipVectorPlane(obj, math.sqrt(odist), rdist, a, b)
								#~ clippedcount += 1
						
			count += 1
		
		return clippedcount
	
	# ------------------------------------
	# Draw the lines of the collision area
	def DrawLines(self):
		
		for TLine in self.vectors:
			startpos = [TLine.x1, TLine.y1]
			endpos = [TLine.x2, TLine.y2]
			pygame.draw.line(globals.screen, globals.green, startpos, endpos, 1)
	

