function CloseDeadEnds(deadends,nodes)
	--paiguta tupikud
	while nodes[1] do
		local spot=nodes[1]
		local modname=deadends[math.random(#deadends)]
		
		dofile("mods/"..modname..".lua")
		if modlist[modname]==nil then print("ERROR:module ".. modname .. " does not exist!\n")  return end
		local spot2=table.copy(modlist[modname][1])

		local turn=spot2.a+3.141-spot.a
		spot2.x,spot2.y=TransformPoint(spot2.x,spot2.y,0,0,-turn)
		
		PlaceModule(spot.x-spot2.x,spot.y-spot2.y,-turn,modname)
		table.remove(nodes,1)
	end
end

function GenerateLevel(modules,itemlist,rareitemlist,citemlist,enemylist,deadendtable,maxtries,pstart,startitems
,terminalscripts)
	local tries=0
	local modules2=table.copy(modules)
	while GenerateLevelIteration(modules2,itemlist,rareitemlist,citemlist,enemylist,deadendtable,pstart,
	startitems,terminalscripts)==-1 do
		modules2=table.copy(modules)
		
		tries=tries+1
		if tries>=maxtries then
			print("ERROR:Level generation failed! Tried "..tries.." times.\n")
			return
		else
			ClearLevel()
		end
	end
	print("INFO:Level successfully generated after "..tries.." failed attempts.\n")
end

function GenerateLevelIteration(modules,itemlist,rareitemlist,citemlist,enemylist,deadendtable,pstart,startitems,terminalscripts)
	terminalscripts=terminalscripts or {}
	SetDefault(enemylist,0)
	SetDefault(itemlist,0)
	SetDefault(rareitemlist,0)
	SetDefault(citemlist,0)

	rnddestructiontable={}
	rnddestructiontable["kast"]={}
	for k,v in pairs(enemylist) do
		rnddestructiontable[k]={}
		rnddestructiontable[k].count=v		
	end

	tmp_itemspawntable={}
	tmp_rareitemspawntable={}
	tmp_containertable={}
	if enemylist["zspawner"]==nil then enemylist["zspawner"]=10 end
	placedmodlist={}
	nodelist={}
	--pane paika algusmoodul
	-----------------------
	local rot=math.random(6.282)
	
	dofile("mods/"..modules[1]..".lua")
	PlaceModuleLevel(0,0,rot,modules[1]) 
	table.remove(modules,1)

	--pane paika mängija
	SetCreationTransform(0,0,rot)
	local player=CreatePlayer(pstart.x,pstart.y)
	if startitems and preservestatus_~=1 then
		for k,v in pairs(startitems) do
			player:GiveItem(v)
		end
	end

	SetCreationTransform(0,0,0)

	local cycles=0		--loeb genereerimise tsükleid, et võimatu kombinatsioon ei tekitaks infinite loopi
	local max_cycles=500
	--paiguta moodulid ja kollid
	
	for i,v in ipairs(modules) do
		if type(v)=="table" then
			_,modules[i]=RandomField(v)
		end
		if modules[i]~="FILLHOLES" then LoadModule(modules[i]..".lua") end
	end
	
	while modules[1] do
		if modules[1]=="FILLHOLES" then
			--viimane jääb
			local node=nodelist[#nodelist]
			nodelist[#nodelist]=nil
			CloseDeadEnds(deadendtable,nodelist)
			nodelist[1]=node
			table.remove(modules,1)
			goto nextloop
		end
		
		if modlist[modules[1]]==nil then
			print("ERROR:Module " .. modules[1] .. " not found!\n")
			return -1
		end
		if #nodelist==0 then
			console.Print("ERROR:No open paths left, change module order in level file.\n")
			return -1
		end
		local gatenr=math.random(#nodelist)
		local spot=nodelist[gatenr]

		if #modlist[modules[1]]==0 then
			print("ERROR: module "..modules[1].." has no exits!\n")
		end
		local gatenr2=math.random(#modlist[modules[1]])
		local spot2=table.copy(modlist[modules[1]][gatenr2])

		--teise yhenduskoha nurk peab olema 180 kraadi esimese omast.
		local turn=spot2.a+3.141-spot.a
		spot2.x,spot2.y=TransformPoint(spot2.x,spot2.y,0,0,-turn)
		cycles=cycles+1
		if PlaceModuleLevel(spot.x-spot2.x,spot.y-spot2.y,-turn,modules[1],gatenr2,spot.parent) then
			table.remove(nodelist,gatenr)
			table.remove(modules,1)
		end
		if cycles>max_cycles then
			print("ERROR:failed to place module "..modules[1].."\n")
			return -1
		end
		::nextloop::
	end
	print("---\n")

	--paiguta tupikud
	CloseDeadEnds(deadendtable,nodelist)

	--Jaga terminalidele funktsioonid
	--------------------------------------------------------------------
	local terminaltbl=rnddestructiontable["terminal"]
	if terminaltbl then
		GenerateTerminalScripts(terminalscripts)
		table.shuffle(terminalscripts)
		table.shuffle(terminaltbl)

		local termdifference=#terminalscripts-#terminaltbl
		for k,v in pairs(terminalscripts) do
			if #terminaltbl==0 then
				print("WARNING:Not enough terminals for all scripts! "..termdifference.." scripts left over.\n")
				break 
			end
			local dest=terminaltbl[1]
			dest:SetFunction("_"..v)
			
			if progress.story[v] then
				dest:HideMarker()
			end
			table.remove(terminaltbl,1)
		end

		if #terminaltbl>0 then
			print("WARNING:Not enough items for all terminals! "..#terminaltbl.." terminals left over.\n")
		end
	end
	--kustuta liigsed vaenlased, kastid ja terminalid
	--------------------------------------------------------------------
	rnddestructiontable["kast"].count=#rnddestructiontable["kast"]/2
	rnddestructiontable["terminal"].count=0
	for k,v in pairs(rnddestructiontable) do
		console.Print("INFO: Number of \"" ..k.. "\" spawned: " .. #v .. " maximum in level file: "..v.count.."\n")
		while #v>v.count do
			local deletenr=math.random(#v)
			if not v[deletenr]:GetName() then 
				v[deletenr]:Delete()
			end
			table.remove(v,deletenr)
			
		end	
	end
	SetCreationTransform(0,0,0)

	--paiguta hea nodi
	----------------------------------------------------
	if #tmp_itemspawntable==0 then print("WARNING: No item spawn points defined!\n")
	else PlaceItems(tmp_itemspawntable,itemlist) end
	
	if #tmp_rareitemspawntable==0 then print("WARNING: No secret item spawn points defined!\n")
	else PlaceItems(tmp_rareitemspawntable,rareitemlist) end

	--Kastid
	----------------------------------------------------
	local counter=1
	local count=#rnddestructiontable["kast"]
	table.shuffle(rnddestructiontable["kast"])
	if count>0 then
		for k,v in pairs(citemlist) do
			for i=0,v-1 do
				local dest=rnddestructiontable["kast"][counter]
				dest:AddItem(k)
				counter=counter+1
				if counter>count then counter=1 end
			end
		end
	end
	--Terminalid

	
	return 0;
end

function PlaceModuleLevel(x,y,a,module,spotnr,previous)
	if modlist[module]==nil then dofile("mods/"..module..".lua") end
	
	local md=modlist[module]
    if md==nil then print("ERROR:Module " .. module .. " does not exist\n") return false end

	local moduleptr
	if ModuleFits(x,y,a,module) then
		moduleptr=_PlaceModuleLevel(x,y,a,module,previous)
	else
		return false
	end

	for i,v in ipairs(md) do
		if i~=spotnr then 
			local rx,ry=TransformPoint(v.x, v.y, x, y, a)
			local ra=v.a+a
			if nodelist then table.insert(nodelist,{x=rx,y=ry,a=ra,parent=moduleptr}) end
		end
	end
	return true
end

function PlaceItems(locations,items)
	table.shuffle(locations)
	local currentspot=1
	for k,v in pairs(items) do
		for i=0,v-1 do
			local randpos=locations[currentspot]
			CreateItem(randpos.x+math.random(-3,3)/24,randpos.y+math.random(-3,3)/24,k)
			currentspot=currentspot+1
			if currentspot>#locations then currentspot=1 end
		end
	end
end

function GenerateTerminalScripts(functionnames)
	for k,v in pairs(functionnames) do
		if v=="SHOWEND" then
			scripttable["_SHOWEND"]=function() 
				ForeachNamedObject("EndMarker",function(o) o:MakeVisible() end) 
				ShowSmallMessage("TELEPORTER LOCATION MARKED ON MAP")
			end
		elseif v=="SHOWBOXES" then
			scripttable["_SHOWBOXES"]=function()
				ShowSmallMessage("STORAGE CABINETS MARKED ON MAP")
			
				ForeachNamedObject("ContainerMarkers",function(o) o:MakeVisible() end)
			end
		elseif v:starts("RECIPE:") then
			local itemname=v:sub(8)
			local texttitle=replacetitles[v] or v

			local str=string.format(
[[
ShowMessageDelay("%s \n\n"..storytable["%s"])
StatsRegisterCombination("%s")
StatsRegisterStory("%s")
]],texttitle,texttitle,itemname,texttitle)
			
			scripttable["_"..v],err=loadstring(str)
			if not scripttable["_"..v] then print(err) end

		else
			if not storytable[v] then
				console.Print(string.format("ERROR: Text named %s doesn't exist\n",v))
			end
			
			local str=string.format(
[[
ShowMessageDelay("%s \n\n"..storytable["%s"])
StatsRegisterStory("%s")]],v,v,v)
			scripttable["_"..v],err=loadstring(str)
			if not scripttable["_"..v] then print(err) end
		end
	end
end
