from Box2D2 import *

class Body:
	def ApplyImpulse(self, v1, v2):
		self._body.ApplyImpulse(b2Vec2(*v1), b2Vec2(*v2))

class Circle(Body):
	def __init__(self, physics, pos=(1.0, 0), radius=1.5, damping=0.1, density=1.0, friction=0.3, restitution=0.5):
		world = physics._world
		
		bodyDef = b2BodyDef()
		bodyDef.position.Set(pos[0], pos[1])
		bodyDef.angularDamping = damping
		bodyDef.linearDamping = damping
		bodyDef.allowSleep = True
		
		self._body = world.CreateBody(bodyDef)
		
		bdef = b2CircleDef()
		bdef.radius = radius
		bdef.density = density
		bdef.friction = friction
		
		self._shape = self._body.CreateShape(bdef)
		self._body.SetMassFromShapes()
		self._shape.SetUserData(self)
	
	def AddCollision(self, other):
		pass

class World(b2World):
	def __init__(self, rectangle=(-100, -100, 100, 100), gravity=(0, -10)):
		BB = b2AABB()
		BB.lowerBound.Set(rectangle[0], rectangle[1])
		BB.upperBound.Set(rectangle[2], rectangle[3])
		b2World.__init__(self, BB, b2Vec2(gravity[0], gravity[1]), True)

class ContactListener(b2ContactListener):
	def __init__(self):
		b2ContactListener.__init__(self)
	
	def Add(self, point):
		"""Called when a contact point is created"""
		s1 = point.shape1.GetUserData()
		s2 = point.shape2.GetUserData()
		s1.AddCollision(s2)
		s2.AddCollision(s1)
	
	def Persist(self, point):
		"""Called when a contact point persists for more than a time step"""
		#print "Persist:", point
	
	def Remove(self, point):
		"""Called when a contact point is removed"""
		#print "Remove:",point

class Physics:
	timeStep = 1.0 / 60
	velocityIterations = 10
	positionIterations = 8
	
	def __init__(self, *args, **kwargs):
		self.listener = ContactListener()
		if kwargs.has_key('contactlistener'):
			self.listener = kwargs['contactlistener']
			del kwargs['contactlistener']
		self._world = World(*args, **kwargs)
		self._world.SetContactListener(self.listener)
	
	def Update(self):
		self._world.Step(self.timeStep, self.velocityIterations, self.positionIterations)

if __name__ == "__main__":
	p = Physics()
	body = Circle(p)
	body2 = Circle(p, pos=(1.0, -4.0), density=0)
	
	for i in xrange(80):
		p.Update()
		position = body._body.GetPosition()
		angle = body._body.GetAngle()
		print position, angle


