local entity ={}

entity.setPosition 		= function (e,x,y,z)
	if type(x)=="table" or vec3.is_vec3(x) then 
		y=x.y
		z=x.z
		x=x.x
	end
	e.x,e.y,e.z  	= x or e.x, y or e.y, mc(-4000,z or e.z,4000)
	if editingLevel then 
		e.ox,e.oy,e.oz 	= x or e.ox, y or e.oy, z or e.oz
		e.bx,e.by,e.bz 	= x or e.bx, y or e.by, z or e.bz
	end
	e:updateTransform()
end

entity.getPosition 	= function (e) 
	return ((e.selected and editor.transformTime>1) and e.nextPosition or e.position) 
end

entity.setOrigin 		= function (e,x,y,z)
	e:setPosition(x and e.x+x-e.ox or e.x,y and e.y+y-e.oy or e.y,z and e.z+z-e.oz or e.z)
	e.ox,e.oy,e.oz = x or e.ox, y or e.oy, z or e.oz
end

entity.setBase 			= function (e,x,y,z)
	e.bx,e.by,e.bz = x or e.bx, y or e.by, z or e.bz
end

entity.move  			= function (e,x,y,z)
	if x then 
		if type(x)=="number" then 
			e:setPosition(e.x+x,e.y+y,e.z + (z or 0))
		else
			e:setPosition(e.x+x.x,e.y+x.y,e.z+x.z)
		end
	else
		e:setPosition(e.x+e.v.x,e.y+e.v.y,e.z+e.v.z)
	end
end

entity.setVelocity 		= function (e,x,y,z)
	e.v.x = mc(e.vmin.x, x or e.v.x ,e.vmax.x)
	e.v.y = mc(e.vmin.y, y or e.v.y ,e.vmax.y) 
	e.v.z = mc(e.vmin.z, z or e.v.z ,e.vmax.z) 
end

entity.accelerate 	= function (e,x,y,z)

end

entity.changeVelocity 	= function (e,x,y,z)
	e.v = { x=x and e.v.x+x or e.v.x, 	y=y and e.v.y+y or e.v.y, 	z=z and e.v.z+z or e.v.z }
end

entity.setMaxVelocity 	= function (e,x,y,z,x2,y2,z2)
	e.vmin = { 	x=x2 and x or -x,	y=y2 and y or -y,	z=z2 and z or -z 	}
	e.vmax = { 	x=x2 or x, 			y=y2 or y,			z=z2 or z 	}
end

entity.setDamping 		= function (e,x,y,z)
	e.vdamp = { 	x = x, 		y = y or x, 	z = z or x 	}
end

entity.damp 			= function (e,x,y,z)
	e.v.x=e.v.x*(type(x)=="table" and x.x or x or e.vdamp.x)
	e.v.y=e.v.y*(type(x)=="table" and x.y or y or x or e.vdamp.y)
	e.v.z=e.v.z*(type(x)=="table" and x.z or z or x or e.vdamp.z)
end

entity.setScale 		= function (e,x,y,z)
	if y then 
		e.scale:set(x,y,z)
	else
		e.scale:set(x,x,x)
	end
	e:updateTransform()
end

entity.setRotation 		= function (e,angle,axis)
	local axis = type(axis)=="string" and axes[axis] or axis or axes.z
	e.orientation =  quat.rotate(angle,axis)
	e:updateTransform()
end

entity.rotate 			= function (e,angle,axis)
	local axis = type(axis)=="string" and axes[axis] or axis or axes.z
	e.orientation = (e.orientation) * quat.rotate(angle,axis)
	e:updateTransform()
end


entity.transfer 		= function (e,pos,dest)
	e.nextRoom  = dest
	e.nextSet   = game.findSet(dest)
	table.insert 	 (scene.transfers,{entity=e,source=room.key,dest=dest,pos=pos})
end
 
local temp = mat4()
entity.updateTransform = function(e)

	e.position.x,e.position.y,e.position.z=e.x,e.y,e.z
	e.transform = e.transform or mat4()
	if multiTool.dragging then 
		e.nextPosition = vec3.add(e.position,multiTool.translation)
		e.transform:identity()
		e.transform:scale(e.transform,e.scale)
		e.transform = e.transform*mat4.from_quaternion(e.orientation)
		e.transform:translate(e.transform,e.nextPosition)
	elseif multiTool.rotating then 
		e.nextOrientation = (e.orientation) * quat.rotate(multiTool.angle,multiTool.axis)
		e.transform:identity()
		e.transform:scale(e.transform,e.scale)
		e.transform = e.transform*mat4.from_quaternion(e.nextOrientation)
		e.transform:translate(e.transform,multiTool.position-(multiTool.position-e.position):rotate(-multiTool.angle,multiTool.axis))
	elseif multiTool.scaling then 
		e.nextScale = e.scale*multiTool.scale
		e.transform:identity()
		e.transform:scale(e.transform,e.nextScale)
		e.transform = e.transform*mat4.from_quaternion(e.orientation)
		e.transform:translate(e.transform,e.position)
	else 
		nextScale       = e.scale       
		nextOrientation = e.orientation 
		nextPosition 		= e.position 		
		e.transform:identity()
		e.transform:scale(e.transform,e.scale)
		e.transform:mul(mat4.from_quaternion(e.orientation),e.transform)
		e.transform:translate(e.transform,e.position)
	end

	for m,model in ipairs(e.models) do
		model.matrix = scene.getMatrix(model)
	end
	return e.transform
end

entity.applyTransform = function(e)
	if multiTool.dragging then 
		e.position = e.nextPosition
	elseif multiTool.rotating then 
		e.position = multiTool.position-(multiTool.position-e.position):rotate(-multiTool.angle,multiTool.axis)
		e.orientation=e.nextOrientation
	elseif multiTool.scaling then 
		e.scale = e.nextScale
	end
	e.x,e.y,e.z = e.position:unpack()
end

--entity.setLayerVisible
--entity.showLayer
--entity.hideLayer

entity.setLayerSolo 	= function(e,layer)
	--if e.fdata then 
	--	for i,l in ipairs(e.fdata) do
	--		l.visible=(l.name==layer)
	--		if (l.name==layer) then 
	--			--trace(l.name)
	--		end
	--	end
	--end
end

entity.setColor 		= function(e,r,g,b,a)
	e.color = {r=r,g=g,b=b,a=a or 1}
end

entity.dist 				= function(e,e2)
	return (e and e2) and math.dist3(e.x,e.y,e.z,e2.x,e2.y,e2.z) or false
end

entity.floorDist 				= function(e,e2)
	return e.plane.group==e2.plane.group and math.dist(e.x,e.z,e2.x,e2.z) or math.huge
end

entity.setLayerByAngle 	= function(e,a)
	local a2 = a+pi+pi/16+pi/32
	local p = pi/4
	local dirs = {
		{ 	0, 		p,		"side"			, true},
		{ 	p, 		p*2.25,	"south side"	, true},
		{ 	p*2.25, p*2.75,	"south"			},
		{ 	p*2.75,  	p*4,	"south side"	},
		{ 	p*4,  	p*5,	"side"			},
		{ 	p*5,  	p*6.25,	"north side"	},
		{ 	p*6.25, p*6.75,	"north"			},
		{ 	p*6.75, p*8,	"north side"	, true},
	}
	local facing
	local flip = e.flip.h
	for i,dir in ipairs(dirs) do
		if a2>dir[1] and a2<dir[2] then
			facing = dir[3]
			flip=dir[4]
		end
	end
	if facing then 
		e.flip.h = flip 
	end

	entity.facing 	= facing or entity.facing
	e:setLayerSolo 	(entity.facing)
end

entity.setPlaybackSpeed = function(e,s)
	e.playbackSpeed = s	
end


entity.setGhost 	= function(e,g)
	e.group=(type(g)=="nil" or g) and 0 or -1
	e.ghost=(type(g)=="nil" or g)
end

entity.setPath  	= function(e,p)
	entity.paths = {getPath(p)}
end

function getPath(p)
	for i,path in pairs(room.paths) do
		if path.name == p then 
			return path
		end
	end
end


--entity.setPlaying

entity.play = function(e,a)
	if a then 
		e:setAnim(a)
	end
	e.playing = true
end

entity.pause = function(e)
	e.playing=false
end


entity.setAnim  		= function (e,name,frame)
	local _,key  = lume.match(e.data.animations,function(x) return x.name==name end)
	if name~=e.animation then 
		e.models  = {}
		e.anim  	= key or e.anim
		e.adata = objects[e.key].animations[e.anim]
	end
	e.animation = name or e.animation
	e.frame 	= frame or 1
	e.tick  	= frame and 0 or e.tick
	e.fdata 		= scene.getEntityFrameData(e,frame)
end

entity.setFrame 		= function (e,frame)
	e.frame 	= frame
	e.tick  	= 0
end

entity.setRandomFrame  	= function (e)
	e:setFrame(math.random()*e.adata.length)
end

entity.playExternal = function(e,t,a,o)
	local t = type(t)=="string" and scene.findEntity(t) or t
	t:play(a)
	e.visible = false
	t.visible = true
	waitFor(function() 
		if t.frame==t.adata.length then 
			t:pause() 
			e.visible = true 
			t.visible = false

			if o then 
				local offset = -(-t.models[t.adata.offsetLayer or 1].transform*-t.transform*vec3(0))
				e:setPosition(offset.x,offset.y,offset.z)
			end
			t.models = {}
			return true 
		end 
	end)
end

--self.onAnimMark()
--self.onAnimEnd()

--entity.add/enable Scripts
--entity.remove/disable Scripts

--entity.addChild
--entity.removeChild
--entity.destroy
--entity.reset


--entity.addWobble
--entity.removeWobble
--entity.setWobble

entityMethods = entity