
---- The Circle poor Alis is bound to ----
-------------------------------------------------------------------------------

Circle = { 
	points = {},
	quads = nil, area = 0,
	drawcount = 0
}

function Circle:reset()
	self.points = { {S_BORDER, S_BORDER}, 
		{SCREEN_WIDTH-S_BORDER, S_BORDER}, 
		{SCREEN_WIDTH-S_BORDER, SCREEN_HEIGHT-S_BORDER-2}, 
		{S_BORDER, SCREEN_HEIGHT-S_BORDER-2} }
	quads = nil 
	self.area = 0
	self.drawcount = 0
	self:tesselate()
end

function Circle:draw()
	local draw = false
	self.drawcount = self.drawcount +1
	if self.drawcount == 5 then
		draw = true
	elseif self.drawcount == 18 then
		draw = true
	elseif self.drawcount == 36 then
		draw = true
		self.drawcount = 0
	end
	if draw then
		self:eachLine(function(p1, p2)
			screen:drawLine(p1[1], p1[2], p2[1], p2[2],
				(p1 == Alis.cur_point) and colors.line or colors.activeline)
		end)
	end
end

function Circle:reallyDraw()
	self.drawcount = 4
	self:draw()
end

function Circle:hasPoint(p)
	for _, point in pairs(self.points) do
		if p == point then return true end
	end
	return false
end

function Circle:getPrevious(p)
	local i = getIndex(self.points, p)
	return self.points[i-1] or self.points[table.getn(self.points)] 
end

function Circle:getTriplet(p)
	local np, nnp = nil, nil
	for i, point in pairs(self.points) do
		if p == point then
			local np, nnp = self.points[i+1], self.points[i+2]
			if nnp == nil then nnp = self.points[1] end -- close the circle
			if np == nil then -- close the circle
				np = self.points[1]
				nnp = self.points[2] 
			end
			return p, np, nnp
		end
	end
end

function Circle:eachLine(f)
	local nextpoint, hor, s = nil, self:isStartHorizontal(), table.getn(self.points) -- horizontal or vertical line
	for i=1, s-1 do
		if f(self.points[i], self.points[i+1], hor) == false then return false end
		hor = not hor
	end
	f(self.points[s], self.points[1], hor) -- close the Circle
end

function Circle:isStartHorizontal()
	return not(self.points[1][1] == self.points[2][1])
end

function Circle:tesselate()
	-- I worked this one out on a piece of paper :P
	local result, rem, i = {}, copy(self.points), 1
	local p1, p2, p3, p4, p12hdiff, p12vdiff, p43hdiff, p43vdiff, pn, skip, remi
	self.area = 0
	while table.getn(rem) > 4 do
		-- the 4 points we are looking at in this iteration, for notational convenience
		p1, p2, p3, p4 = rem[i], rem[i+1], rem[i+2], rem[i+3]
		-- check whether the rect bomposed of these points is inside -> L| vs |``|
		if isRightTurn(p1, p2, p3) and isRightTurn(p2, p3, p4) then
			-- whether to skip this rect and the index of insert/remove ops
			skip, remi = false, i
			p12hdiff, p12vdiff = p1[1] - p2[1], p1[2] - p2[2]
			p43hdiff, p43vdiff = p4[1] - p3[1], p4[2] - p3[2]
			if math.abs(p12hdiff + p12vdiff) > math.abs(p43hdiff + p43vdiff) then
				pn = {p2[1]+p43hdiff, p2[2]+p43vdiff}
				rect = orderedRect(pn, p2, p3, p4)
				remi = i + 1
			else
				pn = {p3[1]+p12hdiff, p3[2]+p12vdiff}
				rect = orderedRect(p1, p2, p3, pn)
			end
			-- determine if we should skip this rect (lines are inside or crossing it)
			for j, p in pairs(rem) do
				if colDetRectLine(rect, {p, rem[j+1] or p}) then
					skip = true
					break
				end
			end
			if skip then
				i = i+1
			else
				self.area = self.area + rectArea(rect)
				table.insert(result, rect) -- insert the newly created rect
				table.remove(rem, remi) -- remove the points
				table.remove(rem, remi) --   that have been taken
				table.remove(rem, remi) --   care of
				table.insert(rem, remi, pn) -- insert the newly created point
				i = 1
			end
		else i = i + 1 end
		removeSuperfluous(rem) -- important! removes points like this: o---x---o
	end
	rect = orderedRect(unpack(rem))
	table.insert(result, rect)
	self.area = self.area + rectArea(rect)
	self.quads = result
end

function Circle:showQuads()
	local lc = { Color.new(255, 0, 0, 120), Color.new(0, 255, 0, 120),
		Color.new(0, 0, 255, 120), Color.new(255, 255, 0, 80), Color.new(255, 0, 255, 80),
		Color.new(0, 255, 255, 80) }
	local cc
	for i, q in pairs(self.quads) do
		cc = i
		while cc > table.getn(lc) do cc = cc - table.getn(lc) end
		screen:fillRect(q[1][1], q[1][2], q[2][1] - q[1][1], q[2][2] - q[1][2], lc[cc])
		screen:print((q[1][1]+q[2][1])/2-10, (q[1][2]+q[2][2])/2-4, "R:"..i, colors.lightgray)
	end
	screen.flip()
	System.sleep(200)
	repeat until Controls.read():triangle()
	System.sleep(200)
end

function Circle:setPoints(newcircle)
	local oldpoints = self.points
	local oldarea = self.area
	local oldquads = self.quads
	screen:fillRect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT, colors.newcircleflash)
	screen.flip()
	self.points = newcircle
	self:tesselate()
	if self.area >= oldarea/2 then
		if not Crysts:testAlive() then
			return true
		else
			screen.blitScaled(SCREEN_WIDTH2-98, SCREEN_HEIGHT2-98, imgs.bosshit, 1.5, 1.5)
		end
	else
		screen:blit(SCREEN_WIDTH2 + (Alis.x-SCREEN_WIDTH2) * 0.6 - 32,
			SCREEN_HEIGHT2 + (Alis.y-SCREEN_HEIGHT2) * 0.6 - 16, imgs.hasty)
	end
	self.points = oldpoints
	self.area = oldarea
	self.quads = oldquads
end

function Circle:eachQuad(f)
	for _, q in self.quads do
		if f(q) == false then return false end
	end
end
