-- copy all globals into locals, some locals are prefixed with a G to reduce name clashes
local coroutine,package,string,table,math,io,os,debug,assert,dofile,error,_G,getfenv,getmetatable,ipairs,Gload,loadfile,loadstring,next,pairs,pcall,print,rawequal,rawget,rawset,select,setfenv,setmetatable,tonumber,tostring,type,unpack,_VERSION,xpcall,module,require=coroutine,package,string,table,math,io,os,debug,assert,dofile,error,_G,getfenv,getmetatable,ipairs,load,loadfile,loadstring,next,pairs,pcall,print,rawequal,rawget,rawset,select,setfenv,setmetatable,tonumber,tostring,type,unpack,_VERSION,xpcall,module,require

local apps=apps
local win=win


local function print(...) _G.print(...) end

local wstr=require("wetgenes.string")

module("bulb.can")

function bake(state,can)
	local can=can or {}

-- Can this ID be considered a colored ball (level ends after all colors are removed)
	local t={
		[25]=-1, -- this ball might turn into anything so all colors are valid
	}
	function can.color(id)
		if id>0 and id<16 then return id end
		if id>=33 and id<=40 then return id-32 end -- these are wrapped balls, subtract 32 to turn them into a color
		return t[id] or false
	end

-- this is a wrapped ball that can be unwrapped into a color
	function can.unwrap(id)
		if id>=33 and id<=40 then return true end
		return false
	end

-- Can this ID match3?
	function can.match_three(id)
		if id>0 and id<16 then return true end
		return false
	end

-- can we remove? some balls last forever
	local t={
		[45]=true,
	}
	function can.remove(id)
		if id== 0 then return false end -- nothing to remove
		if can.blob(id) then return false end -- blobs are special
		if can.float(id) then return false end -- floaters last
		if t[id] then return false end
		return true
	end

-- can we move? some balls are stuck fast
	function can.move(id)
		if can.blob(id) then return false end -- blobs are special
		if can.float(id) then return false end -- floaters last
		return true
	end

-- can we duplicate? some balls should not clone easily
	local t={
		[43]=true,
		[44]=true,
		[45]=true,
	}
	function can.clone(id)
		if can.blob(id) then return false end -- blobs are special
		if can.float(id) then return false end -- floaters last
		if t[id] then return false end
		return true
	end

-- can we damage (boss)
	local t={
		[45]=true,
	}
	function can.damage(id)
		if t[id] then return true end
		return false
	end

-- Can this ID trigger when hit by a falling ball?
	local t={
		[17]={["shatter"]=true},
		[18]={["boom"]=true},
		[21]={["genocide"]=true},
		[23]={["fire"]=true},
		[24]={["sponge"]=true},
		[25]={["dopple"]=true},
		[26]={["upturn"]=true},
		[30]={["skip"]=true},
		[31]={["reset"]=true},
		[32]={["suicide"]=true},
		[41]={["warp"]=true},
		[42]={["refill"]=true},
		[57]={["topdrop"]=true},
	}
	function can.trigger_hit(id)
		return t[id] or false
	end

-- Can this ID trigger when landing on another ball?
	local t={
		[17]={["freeze"]=true},
		[18]={["boom"]=true},
		[19]={["squash"]=true},
		[21]={["genocide"]=true},
		[23]={["fire"]=true},
		[24]={["sponge"]=true},
		[25]={["dopple"]=true},
		[26]={["upturn"]=true},
		[30]={["skip"]=true},
		[31]={["reset"]=true},
		[32]={["suicide"]=true},
		[41]={["warp"]=true},
		[42]={["refill"]=true},
		[57]={["topdrop"]=true},
	}
	function can.trigger_land(id)
		return t[id] or false
	end

-- Can this ID trigger when close to a batch of cells that just cleared?
	local t={
		[33]={["unwrap"]=true},
		[34]={["unwrap"]=true},
		[35]={["unwrap"]=true},
		[36]={["unwrap"]=true},
		[37]={["unwrap"]=true},
		[38]={["unwrap"]=true},
		[39]={["unwrap"]=true},
		[40]={["unwrap"]=true},
	}
	function can.trigger_proximity(id)
		return t[id] or false
	end

-- Can this ID trigger when it reaches the bottom?
	local t={
		[49]={["escape"]=true},
		[50]={["escape"]=true},
		[51]={["escape"]=true},
		[52]={["escape"]=true},
		[53]={["escape"]=true},
		[54]={["escape"]=true},
		[55]={["escape"]=true},
		[56]={["escape"]=true},
		[57]={["escape"]=true},
		[58]={["escape"]=true},
		[59]={["escape"]=true},
		[60]={["escape"]=true},
		[61]={["escape"]=true},
		[62]={["escape"]=true},
		[63]={["escape"]=true},
		[64]={["escape"]=true},
	}
	function can.trigger_bottom(id)
		return t[id] or false
	end	
	
-- This id should trigger after every user action (but only once)
	local t={
		[43]={["flea"]=true},
		[44]={["mole"]=true},
		[45]={["boss"]=true},
	}
	function can.trigger_update(id)
		return t[id] or false
	end	

-- Can this ID make falling balls bounce of it once
	local t={
		[20]=true,
		[59]=true,
	}
	function can.bounce_off(id)
		return t[id] or false
	end

-- Can this ID defy gravity
	local t={
		[20]=true,
		[27]=true,
		[28]=true,
		[29]=true,
	}
	function can.float(id)
		return t[id] or false
	end

-- Can this ID make others stick to it
	local t={
		[27]=true,
	}
	function can.stick(id)
		return t[id] or false
	end
	
-- Can this ID push balls left
	local t={
		[28]=true,
	}
	function can.push_left(id)
		return t[id] or false
	end

-- Can this ID push balls right
	local t={
		[29]=true,
	}
	function can.push_right(id)
		return t[id] or false
	end
	
-- This ID is part of a blob (sticky collection of balls) has pointer to master
	local t={
		[49]=true,
		[50]=true,
		[51]=true,
		[52]=true,
		[53]=true,
		[54]=true,
		[55]=true,
		[56]=true,
		[57]=true,
		[58]=true,
		[59]=true,
		[60]=true,
		[61]=true,
		[62]=true,
		[63]=true,
		[64]=true,
	}
	function can.blob(id)
		return t[id] or false
	end
	
	-- convert name to and from id
	local t={
		[0]="space",
		[17]="ice",
		[18]="boom",
		[19]="rock",
		[20]="floater",
		[21]="clear",
		[22]="stone",
		[23]="fire",
		[24]="sponge",
		[25]="dopple",
		[26]="upturn",
		[27]="stick",
		[28]="left",
		[29]="right",

		[30]="skip",
		[31]="reset",
		[32]="suicide",

		[41]="warp",
		[42]="refill",
		[43]="flea",
		[44]="mole",
		[45]="boss",

		[49]="blob16",
		[50]="blob15",
		[51]="blob14",
		[52]="blob13",
		[53]="blob12",
		[54]="blob11",
		[55]="blob10",
		[56]="blob09",
		[57]="blob08_stamp",
		[58]="blob07_duck",
		[59]="blob06_lizard",
		[60]="blob05_button_blue",
		[61]="blob04_button_red",
		[62]="blob03_button_green",
		[63]="blob02_flowerpot",
		[64]="blob01_boot",
	}
	for i=0,64 do
		if t[i] then t[ t[i] ] = i end
	end
	function can.id_from_name(n)
		return t[n] or 0
	end
	function can.name_from_id(n)
		return t[n] or "space"		
	end
	
	return can
end
