local module = {}

local function rpm(rot)
	return (rot/(math.pi*2))*60
end

local function rot(hinge)
	return hinge.CFrame.Rotation:PointToObjectSpace(hinge.AssemblyAngularVelocity).Magnitude
end

function module.new(this,engine,context)
	this.powered = _G.GetValue(engine,"Powered",true)
	this.inverted = _G.GetInstance(engine,"Inverted")
	this.speed = _G.GetInstance(engine,"Speed")
	this.rotor = _G.GetInstance(engine,"Hinge")
	this.hinge = _G.GetInstance(engine,"HingeConstraint")
	this.rotor_sound = this.rotor:FindFirstChild("RotorSound")
	this.starter_sound = this.rotor:FindFirstChild("Starter")
	this.starter_ratio = engine:GetAttribute("StarterRatio") or 1
	if this.powered then
		this.hinge.ActuatorType = Enum.ActuatorType.Motor
	else
		this.hinge.ActuatorType = Enum.ActuatorType.None
	end
	this.hinge.LimitsEnabled = false
	this.torque = engine:GetScale() * 100000
	return this
end

function module.idle(this,engine) return true end

local begin = tick()
module.run = _G.Protect(function(this,engine,context)
	local throttle = this.throttle or context.controls[_G.GetValue(engine,"Binding","throttle")] or this.Throttle or 0
	if this.inverted.Value then throttle = throttle * -1 end
	local starter = math.abs(throttle) > 0.1
	local target_speed = this.speed.Value * throttle
	local current_speed = rot(this.rotor)
	local accel
	if math.abs(current_speed) > this.speed.Value * 0.1 then
		-- Running
		starter = false
		accel = 40
	else
		-- Starting
		accel = 40 * this.starter_ratio --this.torque * (math.clamp(math.noise(0.123,0.456,(begin-tick())*0.5),0,1) + 0.5) * 0.2
	end
	this.hinge.MotorMaxAcceleration = accel
	if math.abs(throttle) > 0.05 then
		this.hinge.AngularVelocity = target_speed
	else
		this.hinge.AngularVelocity = 0
	end
	if not this.torque then print(this) return false end
	this.hinge.MotorMaxTorque = this.torque * ((engine:GetAttribute("Health") or 1) / (engine:GetAttribute("MaxHealth") or 1)) * (1/(this.speed.Value + 1)) * 60
	context.replicate(this,engine,module,{Throttle = throttle, Starter = starter})
	return true
end)

local legal_detail = {
	Throttle = true,
	Mixture = true,
	Temperature = true,
	Oil = true,
	Air = true,
	Fuel = true,
	Coolant = true,
	Power = true
}
module.replication_delta = 0.25
function module.replicate(this,engine,context,details)
	for index,item in pairs(details) do
		if legal_detail[index] then 
			this[index] = item
			engine:SetAttribute(index,item)
		end
	end
	local speed = math.abs(rot(this.rotor))
	if details.Starter then
		-- Starter on
		if this.starter_sound then if not this.starter_sound.Playing then this.starter_sound:Play() end end
		if this.rotor_sound then if this.rotor_sound.Playing then this.rotor_sound:Pause() end end
	elseif speed > this.speed.Value * 0.1 then
		-- Running
		if this.rotor_sound then
			if not this.rotor_sound.Playing then this.rotor_sound:Play() end
			_G.Print(engine,this.rotor_sound.PlaybackSpeed,speed,this.speed.Value/60)
			this.rotor_sound.PlaybackSpeed = math.clamp(math.abs(speed/150) * 1.5,0.5,1.5)
			this.rotor_sound.Volume = math.clamp(math.abs(speed/150) * 0.05 + 0.05,0,0.1)
		end
		if this.starter_sound then if this.starter_sound.Playing then this.starter_sound:Stop() end end
	else
		if this.rotor_sound then if this.rotor_sound.Playing then this.rotor_sound:Stop() end end
		if this.starter_sound then if this.starter_sound.Playing then this.starter_sound:Stop() end end
	end
end

module.messages = {
	control = function(this,object,context,value)
		this.throttle = value
	end,
	starter = function(this,object,context,value)
		this.starter = value
	end,
}
module.messages.default = module.messages.control

module.manifest = {
	"Engine",
	"Engine2",
	"BigEngine",
	"BigRadial",
	"Radial",
	"Jet",
	"Motor",
	"Motor1",
	"BigSpinWheel",
	"SpinWheel"
}

return module
