#!ruby

require 'optparse'
require 'yaml'

begin
	load_attempted ||= false
	require 'swiftcore/Swiftiply'
rescue LoadError => e
	unless load_attempted
		load_attempted = true
		require 'rubygems'
		retry
	end
	raise e
end

module Swiftcore
	class SwiftiplyExec
		Ccluster_address = 'cluster_address'.freeze
		Ccluster_port = 'cluster_port'.freeze
		Cbackend_address = 'backend_address'.freeze
		Cbackend_port = 'backend_port'.freeze
		Cmap = 'map'.freeze
		Cincoming = 'incoming'.freeze
		Coutgoing = 'outgoing'.freeze
		Ckeepalive = 'keepalive'.freeze
		Cdaemonize = 'daemonize'.freeze
		Curl = 'url'.freeze
		Chost = 'host'.freeze
		Cport = 'port'.freeze
		Ctimeout = 'timeout'.freeze

#####
#
# --cluster-address
# --cluster-port
# --config-file -c (default swiftiply.cnf)
# --daemonize -d
# 
# Config file format (YAML):
# 
# cluster_address:
# cluster_port:
# daemonize:
# map:
#   - incoming:
#     - 127.0.0.1:8080
#     - foo.bar.com:8090
#     url:
#			keepalive:
#			outgoing:
# 
#####
		def self.parse_options(config = {})
			OptionParser.new do |opts|
				opts.banner = 'Usage: swiftiply.rb [options]'
				opts.separator ''
				opts.on('-c','--config CONFFILE',"The configuration file to read.") do |conf|
					config = YAML.load(File.open(conf))
					postprocess_config_load(config)
				end
				opts.on('--cluster-address [ADDRESS]',String,'The hostname/IP address that swiftiply will listen for connections on.') do |address|
					config[Ccluster_address] = address
				end
				opts.on('--cluster-port [PORT]',Integer,'The port that swiftiply will listen for connections on.') do |port|
					config[Ccluster_port] = port
				end
				opts.on('--backend-address [ADDRESS]',String,'The hostname/IP address that swiftiply will listen for backend connections on.') do |address|
					config[Cbackend_address] = address
				end
				opts.on('--backend-port [PORT]',Integer,'The port that swiftiply will listen for backend connections on.') do |port|
					config[Cbackend_port] = port
				end
				opts.on('-d','--daemonize [YN]',[:y,:yes,:n,:no],'Whether swiftiply should put itself into the background.') do |yn|
					config[Cdaemonize] = yn.to_s =~ /^y/i
				end
				opts.on('-t','--timeout [SECONDS]',Integer,'The server unavailable timeout.  Defaults to 3 seconds.') do |timeout|
					config[Ctimeout] = timeout
				end
				opts.on('-p','--print-config','Print the full configuration.') do
					verify_config(config)
					require 'pp'
					pp config
					exit
				end

			end.parse!
			puts("Configuration failed validation; exiting.") && exit unless verify_config(config)
			config
		end

		def self.daemonize
			if (child_pid = fork)
				puts "PID #{child_pid}"
				exit!
			end

			Process.setsid

		rescue Exception
			puts "Platform (#{RUBY_PLATFORM}) does not appear to support fork/setsid; skipping"
		end

		def self.postprocess_config_load(config)
			config[Cmap] = [] unless Array === config[Cmap]
			config[Ctimeout] ||= 3
			config[Cmap].each do |m|
				m[Ckeepalive] = true unless m.has_key?(Ckeepalive)
				m[Ckeepalive] = !!m[Ckeepalive]
				m[Coutgoing] = [m[Coutgoing]] unless Array === m[Coutgoing]
				m[Cincoming] = [m[Cincoming]] unless Array === m[Cincoming]
			end
		end

		def self.verify_config(config)
			if config[Cbackend_address] and config[Cbackend_port]
				config[Cmap] << {Cincoming => nil, Curl => nil, Coutgoing => "#{config[Cbackend_address]}:#{config[Cbackend_port]}", Ckeepalive => true}
			end
			true
		end

		def self.run
			config = parse_options
			daemonize if config[Cdaemonize]
			Swiftcore::Swiftiply.run(config)
		end

		def self.on_windows?
			return @on_windows unless @on_windows.nil?
      @on_windows = !![/mswin/i, /cygwin/i, /mingw/i, /bccwin/i, /wince/i].find {|p| RUBY_PLATFORM =~ p}
		end
	end
end

Swiftcore::SwiftiplyExec.run
