#!/usr/bin/env ruby

require 'optparse'
require 'yaml'
require 'dynflow/rails'

vars = {
   rails_root: 'EXECUTOR_ROOT',
   pid_dir: 'EXECUTOR_PID_DIR',
   log_dir: 'EXECUTOR_LOG_DIR',
   executors_count: 'EXECUTORS_COUNT',
   memory_limit: 'EXECUTOR_MEMORY_LIMIT',
   memory_init_delay: 'EXECUTOR_MEMORY_MONITOR_DELAY',
   memory_polling_interval: 'EXECUTOR_MEMORY_MONITOR_INTERVAL',
   force_kill_waittime: 'EXECUTOR_FORCE_KILL_WAITTIME',
   process_name: 'EXECUTOR_PROCESS_NAME',
   wait_attempts: 'EXECUTOR_WAIT_ATTEMPTS',
   wait_sleep: 'EXECUTOR_WAIT_SLEEP',
   executor_user: 'EXECUTOR_USER'
}

options = vars.reduce({}) do |sum, (key, value)|
   ENV[value] && sum.merge({ key => ENV[value] }) || sum
end

o = OptionParser.new do |o|
   o.banner = <<BANNER
Usage: dynflow [options] ACTION

Actions:

    start    - starts the executor in background
    stop     - stops the run executor
    restart  - restarts the run executor
    run      - runs the executor in forebround

Options:

BANNER

   o.on("-v", "--[no-]verbose", "Run verbosely") do |v|
      options[:verbose] = v
   end

   o.on("-h", "--help", "Prints this help") do
      puts o
      exit
   end

   o.on("-r DIR", "--rails-root=DIR", "Rails root dir for a monitor host application") do |dir|
      options[:rails_root] = dir
   end

   o.on("-p DIR", "--pid-dir=DIR", "Folder to store a pidfile") do |dir|
      options[:pid_dir] = dir
   end

   o.on("-l DIR", "--log-dir=DIR", "Folder to store logs, defaulting to rails log/ folder") do |dir|
      options[:log_dir] = dir
   end

   o.on("-n NAME", "--process-name=NAME", "Name for the watcher process") do |n|
      options[:process_name] = n
   end

   o.on("-c COUNT", "--executors-count=COUNT", "Count of executors for a watcher") do |ec|
      options[:executors_count] = ec
   end

   o.on("-m LIMIT", "--memory-limit=LIMIT", "Memory consumption limit for a watcher") do |ml|
      options[:memory_limit] = ml
   end

   o.on("-d DELAY", "--memory-init-delay=DIR", "Delay for executor memory monitor to initialize in seconds") do |d|
      options[:memory_init_delay] = d
   end

   o.on("-i I", "--memory-polling-interval=I", "Interval in seconds to poll memory, max: 30") do |i|
      options[:memory_polling_interval] = i
   end

   o.on("-k TIME", "--force-kill-waittime=TIME", "Kill time gap to forced kill of the watcher") do |t|
      options[:force_kill_waittime] = t
   end

   o.on("-t TRIES", "--wait-attempts=TRIES", "Wait attempts count") do |c|
      options[:wait_attempts] = c
   end

   o.on("-w TIME", "--wait-sleep=TIME", "Wait sleep time in seconds") do |t|
      options[:wait_sleep] = t
   end

   o.on("-u USER", "--executors-user=USER", "Executor's user name or id ") do |user|
      options[:executor_user] = user
   end

   o.on("-C CONFIG", "--config-file=CONFIG", "Set config file to read options, defaulting to /etc/dynflow/dynflow.yml") do |c|
      if !File.file?(c)
         $stderr.puts "Unable to find out the configuration file. Exiting..."
         exit -2
      end

      config = begin   
         YAML.load(IO.read(c))
      rescue Exception
         $stderr.puts "Invalid format of config file. Please elaborate it. Exiting..."
         exit -3
      end

      options[:config] = config
   end
end

o.parse!

action = ARGV.first
config = options.delete(:config)
verbose = options.delete(:verbose)
user = options.delete(:executor_user)

uid = user =~ /^\d+$/ && user.to_i || Process::UID.from_name(user)

if action.to_s !~ /start|stop|restart|run/
   $stderr.puts "Invalid action is provided. Exiting..."
   puts o
   exit -1
end

if config
   options = config.merge(options)
end

if verbose
   puts "Current config: \n#{options.inspect}"
end

Dir.chdir(options[:rails_root])

if options[:rails_root]
   require 'rails/railtie'
   require File.join(options[:rails_root], 'config/application')
else
   $stderr.puts "Rails root isn't defined. Exiting..."
   exit -4
end

Process::UID.change_privilege(uid)
Dynflow::Rails::Daemon.new.run_background(action, options)
