# Ruby interface to WMII.

require 'find'

module Wmii
	# Writes the given content to the given WM path, and returns the exit status of the operation.
	def Wmii.write aPath, aContent
		IO.popen("wmiir write #{aPath}", 'w') do |io|
			puts "wmiir: writing '#{aContent}' into '#{aPath}'" if $DEBUG
			io.write aContent
		end

		$?
	end

	# Reads the filenames from a long listing of the given WM path.
	def Wmii.read aPath
		`wmiir read #{aPath}`.scan(/\S+$/)
	end

	# Shows the view with the given name.
	def Wmii.showView aName
		Wmii.write '/ctl', "view #{aName}"
	end

	# Shows a WM menu with the given content and returns its output.
	def Wmii.showMenu aContent
		output = nil

		IO.popen('wmiimenu', 'r+') do |io|
			io.write aContent
			io.close_write

			output = io.read
		end

		output
	end

	# Changes the current view to an adjacent one (:left or :right).
	def Wmii.cycleView aTarget
		tags = Wmii.read('/tags')

		curTag = `wmiir read /view/name`
		curIndex = tags.index(curTag)

		newIndex =
			case aTarget
				when :right
					curIndex + 1

				when :left
					curIndex - 1

				else
					return

			end % tags.length

		newTag = tags[newIndex]

		Wmii.showView newTag
	end

	# Shows the client which has the given ID.
	def Wmii.showClient aClientId
		Wmii.read('/tags').each do |view|
			Wmii.read("/#{view}").grep(/^\d+$/).each do |column|
				Wmii.read("/#{view}/#{column}").grep(/^\d+$/).each do |client|
					if `wmiir read /#{view}/#{column}/#{client}/index` == aClientId
						Wmii.showView view
						Wmii.write '/view/ctl', "select #{column}"
						Wmii.write "/view/sel/ctl", "select #{client}"
						return
					end
				end
			end
		end
	end

	# Renames the given view and sends its clients along for the ride.
	def Wmii.renameView aOld, aNew
		Wmii.read('/client').each do |id|
			tags = `wmiir read /client/#{id}/tags`

			Wmii.write "/client/#{id}/tags", tags.gsub(aOld, aNew).squeeze('+')
		end
	end

	# Returns a list of program names available in the given paths.
	def Wmii.findPrograms *aPaths
		list = []

		Find.find(*aPaths) do |f|
			if File.executable?(f) && !File.directory?(f)
				list << File.basename(f)
			end
		end

		list
	end
end
