dofile "Scripts/box2d_oo.lua"

function ShapeCircle:Plot ( canvas )
	canvas:move_to ( 0, 0 )
	canvas:circle ( self.radius )
end

function ShapePolygon:Plot ( canvas )
	canvas:move_to ( self.vertices[1].x, self.vertices[1].y )
	for i = 2, #self.vertices do
		canvas:line_to ( self.vertices[i].x, self.vertices[i].y )
	end
	canvas:close_path ( )
end



function Body:OnCreate ( )
	self.sprite = Sprite ( self.x, self.y )
	scene:add_child ( self.sprite )
end

function Body:OnDestroy ( )
	scene:remove_child ( self.sprite )
	self.sprite = nil
end

function Body:OnTransform ( )

	self.sprite:set_position ( self.x, self.y )
	self.sprite:set_rotation_r ( -self.angle )

end

function Body:Paint ( )
	self.sprite.canvas:clear ( )

	for i, v in pairs ( self.shapes ) do
		if v.isSensor == false then
			v:Plot ( self.sprite.canvas )
		end
	end
	self.sprite.canvas:set_fill_style ( BLACK, 1 )
	self.sprite.canvas:fill ( )
end







function RevoluteJoint:Plot ( canvas )

	local a = self.b2joint:GetAnchor1 ( )

	canvas:move_to ( a.x, a.y )
	canvas:circle ( 5 )

end

function DistanceJoint:Plot ( canvas )

	local a1 = self.b2joint:GetAnchor1 ( )
	local a2 = self.b2joint:GetAnchor2 ( )

	canvas:move_to ( a1.x, a1.y )
	canvas:circle ( 5 )
	canvas:line_to ( a2.x, a2.y )
	canvas:circle ( 5 )

end

function PulleyJoint:Plot ( canvas )

	local a1 = self.b2joint:GetAnchor1 ( )
	local a2 = self.b2joint:GetAnchor2 ( )
	local ga1 = self.b2joint:GetGroundAnchor1 ( )
	local ga2 = self.b2joint:GetGroundAnchor2 ( )

	canvas:move_to ( a1.x, a1.y )
	canvas:circle ( 5 )
	canvas:line_to ( ga1.x, ga1.y )
	canvas:circle ( 5 )
	canvas:line_to ( ga2.x, ga2.y )
	canvas:circle ( 5 )
	canvas:line_to ( a2.x, a2.y )
	canvas:circle ( 5 )

end





if colorblind == false then
	colors = { MAGENTA, YELLOW, LIME }
else
	colors = { MAGENTA, YELLOW, CYAN }
end


Ball = {}
BallMT = { __index = Ball }

-- inherit Body
setmetatable ( Ball, { __index = Body } )


function Ball:Paint ( )
	self.sprite.canvas:clear ( )
	if self.color == nil then
		self.sprite.canvas:move_to ( 0, 0 )
		self.sprite.canvas:circle ( self.shapes[1].radius - 3 )
		self.sprite.canvas:set_fill_style ( BLACK, 0.5 )
		self.sprite.canvas:fill ( )

	else
		local ratio = ( self.shapes[1].radius - 2 ) / 48

		self.sprite.canvas:clear ( )
		self.sprite.canvas:move_to ( 0, 0 )
--		self.sprite.canvas:circle ( self.shapes[1].radius - 2 )
		self.sprite.canvas:circle ( 48 )
		self.sprite.canvas:set_fill_style ( BLACK, 0.5 )
		self.sprite.canvas:fill_preserve ( )

		self.sprite.canvas:set_source_image ( ball )
		self.sprite.canvas:paint ( )
		self.sprite.color = colors[self.color]

		self.sprite.canvas:set_line_style ( 3 / ratio, colors[self.color], 1 )
		self.sprite.canvas:stroke ( )

		if self.ishead == true then
			self.sprite.canvas:circle ( 6 / ratio )
			self.sprite.canvas:set_fill_style ( colors[self.color], 0.75 )
			self.sprite.canvas:fill ( )
			self.sprite.canvas:circle ( 4 / ratio )
			self.sprite.canvas:set_line_style ( 1.5 / ratio, BLACK, 0.5 )
			self.sprite.canvas:stroke ( )
		elseif self.selected == true then
			self.sprite.canvas:circle ( 3 / ratio )
			self.sprite.canvas:set_fill_style ( colors[self.color], 0.75 )
			self.sprite.canvas:fill ( )
		end

		self.sprite.scalex = ratio
		self.sprite.scaley = ratio
	end
end

function Ball:Die ( )
	self.state = 'dead'
	world:DestroyBody ( self )
	return true
end


function Ball:Distance ( ball )
	local dx = self.x - ball.x
	local dy = self.y - ball.y
	local dist = math.sqrt ( dx * dx + dy * dy )
	dist = dist - self.shapes[1].radius
	dist = dist - ball.shapes[1].radius
	return dist
end














BodyMove = {}
BodyMoveMT = { __index = BodyMove }

function BodyMove:Create ( body, x, y )
	local effect = {}
	setmetatable ( effect, BodyMoveMT )

	effect.body = body
	effect.velocity = b2Vec2 ( x, y )
	return effect
end

function BodyMove:Begin ( )
end

function BodyMove:Update ( delta )
	self.body.b2body:SetLinearVelocity ( self.velocity )
end

function BodyMove:End ( )
	self.body = nil
end



BodyDestroy = {}
BodyDestroyMT = { __index = BodyDestroy }

function BodyDestroy:Create ( body )
	local effect = {}
	setmetatable ( effect, BodyDestroyMT )

	effect.body = body
	return effect
end

function BodyDestroy:Begin ( )
end

function BodyDestroy:Update ( delta )
end

function BodyDestroy:End ( )
	world:DestroyBody ( self.body )
	self.body = nil
end




Fade = {}
FadeMT = { __index = Fade }

function Fade:Create ( sprite, alpha )
	local effect = {}
	setmetatable ( effect, FadeMT )

	effect.sprite = sprite
	effect.alpha_b = alpha
	return effect
end

function Fade:Begin ( )
	self.alpha_a = self.sprite.alpha
end

function Fade:Update ( delta )
	local v = ( self.alpha_b - self.alpha_a ) * delta + self.alpha_a
	self.sprite.alpha = v
end

function Fade:End ( )
	self.sprite = nil
end







Rotate = {}
RotateMT = { __index = Rotate }

function Rotate:Create ( sprite, r )
	local effect = {}
	setmetatable ( effect, RotateMT )

	effect.sprite = sprite
	effect.rotation_b = r
	return effect
end

function Rotate:Begin ( )
	self.rotation_a = self.sprite.rotation
end

function Rotate:Update ( delta )
	local v = ( self.rotation_b - self.rotation_a ) * delta + self.rotation_a
	self.sprite.rotation = v
end

function Rotate:End ( )
	self.sprite = nil
end






Resize = {}
ResizeMT = { __index = Resize }

function Resize:Create ( sprite, scalex, scaley )
	local effect = {}
	setmetatable ( effect, ResizeMT )

	effect.scalex_b = scalex
	effect.scaley_b = scaley
	effect.sprite = sprite
	return effect
end

function Resize:Begin ( )
	self.scalex_a = self.sprite.scalex
	self.scaley_a = self.sprite.scaley
end

function Resize:Update ( delta )
	local vx = ( self.scalex_b - self.scalex_a ) * delta + self.scalex_a
	local vy = ( self.scaley_b - self.scaley_a ) * delta + self.scaley_a

	self.sprite:set_scale ( vx, vy )
end

function Resize:End ( )
	self.sprite = nil
end



Remove = {}
RemoveMT = { __index = Remove }

function Remove:Create ( object, parent )
	local effect = {}
	setmetatable ( effect, RemoveMT )

	effect.object = object
	effect.parent = parent
	return effect
end

function Remove:Begin ( )
end

function Remove:Update ( delta )
end

function Remove:End ( )
	self.parent:remove_child ( self.object )
	self.object = nil
end






Move = {}
MoveMT = { __index = Move }

function Move:Create ( object, x, y )
	local effect = {}
	setmetatable ( effect, MoveMT )

	effect.object = object
	effect.x_b = x
	effect.y_b = y
	return effect
end

function Move:Begin ( )
	self.x_a = self.object.x
	self.y_a = self.object.y
end

function Move:Update ( delta )
	local dx = ( self.x_b - self.x_a ) * delta + self.x_a
	local dy = ( self.y_b - self.y_a ) * delta + self.y_a
	self.object:set_position ( dx, dy )
end

function Move:End ( )
	self.object = nil
end







Modulate = {}
ModulateMT = { __index = Modulate }

function Modulate:Create ( object, color )
	local effect = {}
	setmetatable ( effect, ModulateMT )

	effect.object = object
	effect.color = color
	return effect
end

function Modulate:Begin ( )
	local c = self.object.color
	self.start = Color ( c.red, c.green, c.blue )
end

function Modulate:Update ( delta )
	local c = self.object.color
	c.red = ( self.color.red - self.start.red ) * delta + self.start.red
	c.green = ( self.color.green - self.start.green ) * delta + self.start.green
	c.blue = ( self.color.blue - self.start.blue ) * delta + self.start.blue
end

function Modulate:End ( )
	self.color = nil
	self.start = nil
	self.object = nil
end







ChangeVisibility = {}
ChangeVisibilityMT = { __index = ChangeVisibility }

function ChangeVisibility:Create ( object, v )
	local effect = {}
	setmetatable ( effect, ChangeVisibilityMT )

	effect.object = object
	effect.visibility = v
	return effect
end

function ChangeVisibility:Begin ( )
end

function ChangeVisibility:Update ( delta )
end

function ChangeVisibility:End ( )
	self.object.visible = self.visibility
end









Play = {}
PlayMT = { __index = Play }

function Play:Create ( file, v )
	local effect = {}
	setmetatable ( effect, PlayMT )

	effect.file = Sound ( file )
	effect.file.volume = v
	return effect
end

function Play:Begin ( )

end

function Play:Update ( delta )
end

function Play:End ( )
	self.file:play ( )
	self.file = nil
end












EffectsManager = {}
EffectsManagerMT = { __index = EffectsManager }

function EffectsManager:Create ( )
	local em = {}
	setmetatable ( em, EffectsManagerMT )

	return em
end

function EffectsManager:Update ( delta )
	local last
	local it = self.head
	while it do
		if it.delay >= 0 then
			it.delay = it.delay - delta
			if it.delay <= 0 then
				it:Begin ( )
			end
			last = it
			it = it.next
		else
			it.elapsed = it.elapsed + delta
			if it.elapsed < it.duration then
				it:Update ( it.elapsed / it.duration )
				last = it
				it = it.next
			else
				it:Update ( 1 )
				it:End ( )
				if last then
					-- severe the link from last to it
					last.next = it.next
					it.next = nil
					it = last.next
				else
					self.head = it.next
					it.next = nil
					it = self.head
				end
			end
		end
	end
end

function EffectsManager:AddEffect ( effect, duration, delay )
	effect.duration = duration
	effect.delay = delay
	effect.elapsed = 0

	effect.next = self.head
	self.head = effect
end

function EffectsManager:RemoveEffect ( effect )
	local last
	local it = self.head
	while it do
		if it == effect then
			if last then
				-- severe the link from last to it
				last.next = it.next
				it.next = nil
			else
				self.head = it.next
				it.next = nil
				it = self.head
			end
			break
		end
		last = it
		it = it.next
	end
end

function EffectsManager:RemoveAll ( )
	local it = self.head
	while it do
		local last = it
		it = it.next
		last.next = nil
	end
end

function EffectsManager:IsDone ( )
	if self.head == nil then
		return true
	else
		return false
	end
end
