# control your levers from the dfhack console

def lever_pull_job(bld)
	ref = DFHack::GeneralRefBuildingHolderst.cpp_new
	ref.building_id = bld.id

	job = DFHack::Job.cpp_new
	job.job_type = :PullLever
	job.pos = [bld.centerx, bld.centery, bld.z]
	job.general_refs << ref
	bld.jobs << job
	df.job_link job

	puts lever_descr(bld)
end

def lever_pull_cheat(bld)
	bld.linked_mechanisms.each { |i|
		i.general_refs.grep(DFHack::GeneralRefBuildingHolderst).each { |r|
			r.building_tg.setTriggerState(bld.state)
		}
	}

	bld.state = (bld.state == 0 ? 1 : 0)

	puts lever_descr(bld)
end

def lever_descr(bld, idx=nil)
	ret = []

	# lever description
	descr = ''
	descr << "#{idx}: " if idx
	descr << "lever ##{bld.id} @[#{bld.centerx}, #{bld.centery}, #{bld.z}] #{bld.state == 0 ? '\\' : '/'}"
	bld.jobs.each { |j|
		if j.job_type == :PullLever
			flags = ''
			flags << ', repeat' if j.flags.repeat
			flags << ', suspended' if j.flags.suspend
			descr << " (pull order#{flags})"
		end
	}

	bld.linked_mechanisms.map { |i|
		i.general_refs.grep(DFHack::GeneralRefBuildingHolderst)
	}.flatten.each { |r|
		# linked building description
		tg = r.building_tg
		state = ''
		if tg.respond_to?(:gate_flags)
			state << (tg.gate_flags.closed ? 'closed' : 'opened')
			state << ", closing (#{tg.timer})" if tg.gate_flags.closing
			state << ", opening (#{tg.timer})" if tg.gate_flags.opening
		end

		ret << (descr + " linked to #{tg._rtti_classname} ##{tg.id} @[#{tg.centerx}, #{tg.centery}, #{tg.z}] #{state}")

		# indent other links
		descr = descr.gsub(/./, ' ')
	}

	ret << descr if ret.empty?

	ret
end

def lever_list
	@lever_list = []
	df.world.buildings.other[:TRAP].find_all { |bld|
		bld.trap_type == :Lever
	}.sort_by { |bld| bld.id }.each { |bld|
		puts lever_descr(bld, @lever_list.length)
		@lever_list << bld.id
	}
end


@lever_list ||= []

case $script_args[0]
when 'pull'
	cheat = $script_args.delete('--cheat') || $script_args.delete('--now')

	id = $script_args[1].to_i
	id = @lever_list[id] || id
	bld = df.building_find(id)
	raise 'invalid lever id' if not bld

	if cheat
		lever_pull_cheat(bld)
	else
		lever_pull_job(bld)
	end

when 'list'
	lever_list

when /^\d+$/
	id = $script_args[0].to_i
	id = @lever_list[id] || id
	bld = df.building_find(id)
	raise 'invalid lever id' if not bld

	puts lever_descr(bld)

else

	puts <<EOS
Lever control from the dfhack console

Usage:
lever list
 shows the list of levers in the fortress, with their id and links

lever pull 42
 order the dwarves to pull lever 42

lever pull 42 --cheat
 magically pull lever 42 immediately
EOS

end