# Version 0.2.0 (2005-01-18)
# watch_dir only watch
# add next_event
# add watch_dir_recursively
#
# Version 0.1.1 (2005-01-17)
# Correct IN_ var for inotify 0.18

require 'find'

class INotify

	INOTIFY_WATCH    = 0x80085101
	INOTIFY_IGNORE   = 0x80045102

	IN_ACCESS        = 0x00000001
	IN_MODIFY        = 0x00000002
	IN_ATTRIB        = 0x00000004
	IN_CLOSE_WRITE   = 0x00000008
	IN_CLOSE_NOWRITE = 0x00000010
	IN_OPEN          = 0x00000020
	IN_MOVED_FROM    = 0x00000040
	IN_MOVED_TO      = 0x00000080
	IN_DELETE_SUBDIR = 0x00000100
	IN_DELETE_FILE   = 0x00000200
	IN_CREATE_SUBDIR = 0x00000400
	IN_CREATE_FILE   = 0x00000800
	IN_DELETE_SELF   = 0x00001000
	IN_UNMOUNT       = 0x00002000
	IN_Q_OVERFLOW    = 0x00004000
	IN_IGNORED       = 0x00008000
	IN_ALL_EVENTS    = 0xffffffff
	
	def initialize
		@watch_dir = Array.new
		@io = File.open('/dev/inotify')
	end	

	def close
		@io.close
	end

	def watch_dir (dir, option)
		arg = [dir, option]
		arg = arg.pack("PL")
		wd = @io.ioctl(INOTIFY_WATCH, arg)
		if (wd >= 0)
			@watch_dir[wd] = dir
		else
			return -1
		end
	end
	
	def watch_dir_recursively (dir, option)
		Find.find(dir) {|sub_dir|
			if (File::directory?(sub_dir) == true)
				watch_dir(sub_dir, option)
			end
		}
	end

	def next_event
		loop {
			begin
				read_cnt = @io.sysread(268)
				wd, mask, cookie, filename = read_cnt.unpack('lLLZ*')
			end while (mask == IN_Q_OVERFLOW && sleep(0.05))
			evt = Event.new(path(wd), mask, cookie, filename)
			yield(evt)
		}
	end

	def path (wd)
		return @watch_dir[wd]
	end

end

class Event
	attr_reader :filename, :mask, :path

	def initialize (path, mask, cookie, filename)
		@path     = path
		@mask     = mask
		@cookie   = cookie
		@filename = filename
	end

	def dump
		return "path: "+@path.to_s+" mask: "+@mask.to_s+" cookie: "+@cookie.to_s+" filename: "+@filename.to_s+" mask_name: "+mask_name
	end

	def mask_name
		case @mask
		when INotify::IN_ACCESS
			return 'access'
		when INotify::IN_MODIFY
			return 'modify'
		when INotify::IN_ATTRIB
			return 'attrib'
		when INotify::IN_CLOSE_WRITE
			return 'close_write'
		when INotify::IN_CLOSE_NOWRITE
			return 'close_nowrite'
		when INotify::IN_OPEN
			return 'open'
		when INotify::IN_MOVED_FROM
			return 'moved_from'
		when INotify::IN_MOVED_TO
			return 'moved_to'
		when INotify::IN_DELETE_SUBDIR
			return 'delete_subdir'
		when INotify::IN_DELETE_FILE
			return 'delete_file'
		when INotify::IN_CREATE_SUBDIR
			return 'create_subdir'
		when INotify::IN_CREATE_FILE
			return 'create_file'
		when INotify::IN_DELETE_SELF
			return 'delete_self'
		when INotify::IN_Q_OVERFLOW
			return 'event_queued_overflow'
		when INotify::IN_UNMOUNT
			return 'unmount'
		else
			return 'unknown'
		end
	end
end
