#!/usr/bin/env ruby
# vim:encoding=UTF-8:
=begin
# sig.rb

ServerLog IRC Gateway

# Usage

 * Connect.
 * Join a channel (you can name it as you like)
 * Set topic "filename regexp"
 * You will see the log at the channel only matching the regexp.

=end

$LOAD_PATH << "lib"
$LOAD_PATH << "../lib"

$KCODE = "u" unless defined? ::Encoding

require "rubygems"
require "net/irc"
require "logger"
require "pathname"
require "yaml"

class ServerLogIrcGateway < Net::IRC::Server::Session
	def server_name
		"serverlog"
	end

	def server_version
		"0.0.0"
	end


	def initialize(*args)
		super
		@channels = {}
		@config   = Pathname.new(ENV["HOME"]) + ".sig"
	end

	def on_disconnected
		@channels.each do |chan, info|
			begin
				info[:observer].kill if info[:observer]
			rescue
			end
		end
	end

	def on_user(m)
		super
		@real, *@opts = @real.split(/\s+/)
		@opts ||= []
	end

	def on_join(m)
		channels = m.params.first.split(/,/)
		channels.each do |channel|
			@channels[channel] = {
				:topic    => "",
				:observer => nil,
			} unless @channels.key?(channel)
			post @prefix, JOIN, channel
			post nil, RPL_NAMREPLY,   @prefix.nick, "=", channel, "@#{@prefix.nick}"
			post nil, RPL_ENDOFNAMES, @prefix.nick, channel, "End of NAMES list"
		end
	end

	def on_topic(m)
		channel, topic, = m.params
		p m.params
		if @channels.key?(channel)
			post @prefix, TOPIC, channel, topic
			@channels[channel][:topic] = topic
			create_observer(channel)
		end
	end

	def create_observer(channel)
		return unless @channels.key?(channel)
		info = @channels[channel]
		@log.debug "create_observer<#{channel}>#{info.inspect}"
		begin
			info[:observer].kill if info[:observer]
		rescue
		end
		info[:observer] = Thread.start(channel, info) do |chan, i|
			file, reg, = i[:topic].split(/\s+/)
			name = File.basename(file)
			grep = Regexp.new(reg.to_s)
			@log.info "#{file} / grep => #{grep.inspect}"
			File.open(file) do |f|
				size = File.size(f)
				f.seek size
				loop do
					sleep 1
					nsize = File.size(f)
					if nsize > size
						@log.debug "follow up log"
						while l = f.gets
							if grep === l
								post name, PRIVMSG, chan, l
							end
						end
					end
					size = nsize
				end
			end
		end
	end
end

if __FILE__ == $0
	require "optparse"

	opts = {
		:port  => 16700,
		:host  => "localhost",
		:log   => nil,
		:debug => false,
		:foreground => false,
	}

	OptionParser.new do |parser|
		parser.instance_eval do
			self.banner  = <<-EOB.gsub(/^\t+/, "")
				Usage: #{$0} [opts]

			EOB

			separator ""

			separator "Options:"
			on("-p", "--port [PORT=#{opts[:port]}]", "port number to listen") do |port|
				opts[:port] = port
			end

			on("-h", "--host [HOST=#{opts[:host]}]", "host name or IP address to listen") do |host|
				opts[:host] = host
			end

			on("-l", "--log LOG", "log file") do |log|
				opts[:log] = log
			end

			on("--debug", "Enable debug mode") do |debug|
				opts[:log]   = $stdout
				opts[:debug] = true
			end

			on("-f", "--foreground", "run foreground") do |foreground|
				opts[:log]        = $stdout
				opts[:foreground] = true
			end

			parse!(ARGV)
		end
	end

	opts[:logger] = Logger.new(opts[:log], "daily")
	opts[:logger].level = opts[:debug] ? Logger::DEBUG : Logger::INFO

	def daemonize(foreground=false)
		trap("SIGINT")  { exit! 0 }
		trap("SIGTERM") { exit! 0 }
		trap("SIGHUP")  { exit! 0 }
		return yield if $DEBUG || foreground
		Process.fork do
			Process.setsid
			Dir.chdir "/"
			File.open("/dev/null") {|f|
				STDIN.reopen  f
				STDOUT.reopen f
				STDERR.reopen f
			}
			yield
		end
		exit! 0
	end

	daemonize(opts[:debug] || opts[:foreground]) do
		Net::IRC::Server.new(opts[:host], opts[:port], ServerLogIrcGateway, opts).start
	end
end

