#!/usr/bin/env ruby

require 'optparse'

@options = {}
@options[:pid_file] = "/etc/rubycas-server/rubycas-server.pid"
@options[:conf_file] = nil
@options[:verbose] = false

def start
  # use local rubycas-server bin if it exists and is executable -- makes debugging easier
  bin = File.dirname(File.expand_path(__FILE__)) + "/rubycas-server"

  if File.exists?(bin)
    exec = "ruby #{bin}"
  else
    exec = "rubycas-server"
  end
  
  case get_state
  when :ok
    $stderr.puts "rubycas-server is already running"
    exit 1
  when :not_running, :empty_pid
    $stderr.puts "The pid file '#{@options[:pid_file]}' exists but rubycas-server is not running." +
      " The pid file will be automatically deleted for you, but this shouldn't have happened!"
    File.delete(@options[:pid_file])
  when :dead
    $stderr.puts "The pid file '#{@options[:pid_file]}' exists but rubycas-server is not running." +
      " Please delete the pid file first."
    exit 1
  when :missing_pid
    # we should be good to go (unless the server is already running without a pid file)
  else
    $stderr.puts "rubycas-server could not be started. Try looking in the log file for more info."
    exit 1
  end
  	
  cmd = "#{exec} -d -P #{@options[:pid_file]}"
  cmd += " -c #{@options[:conf_file]}" if !@options[:conf_file].nil?
  
  puts ">>> #{cmd}" if @options[:verbose]
  
  output = `#{cmd}`
  
  puts "<<< #{output}" if @options[:verbose]
  
  if s = get_state == :ok
    exit 0
  else
    $stderr.puts "rubycas-server could not start properly! (#{s})\nTry running with the --verbose option for details." 
    case s
    when :missing_pid
      exit 4
    when :not_running
      exit 3
    when :dead
      exit 1
    else
      exit 4
    end
  end
end

def stop
  if File.exists? @options[:pid_file]
    pid = open(@options[:pid_file]).read.to_i
    begin
      Process.kill("TERM", pid)
      exit 0
    rescue Errno::ESRCH
      $stderr.puts "rubycas-server process '#{pid}' does not exist."
      exit 1
    end
  else
    $stderr.puts "#{@options[:pid_file]} not found.  Is rubycas-server running?"
    exit 4
  end
end

def status
  case get_state
  when :ok
    puts "rubycas-server appears to be up and running."
    exit 0
  when :missing_pid
    $stderr.puts "rubycas-server does not appear to be running (pid file not found)."
    exit 3
  when :empty_pid
    $stderr.puts "rubycas-server does not appear to be running (pid file exists but is empty)."
  when :not_running
    $stderr.puts "rubycas-server is not running."
    exit 1
  when :dead
    $stderr.puts "rubycas-server is dead or unresponsive."
    exit 102
  end
end

def get_state
  if File.exists? @options[:pid_file]
    pid = File.read(@options[:pid_file]).strip
    
    return :empty_pid unless pid and !pid.empty? # pid file exists but is empty
    
    state = `ps -p #{pid} -o state=`.strip
    if state == ''
      return :not_running
    elsif state == 'R' || state == 'S'
      return :ok
    else
      return :dead
    end
  else
    # TODO: scan through the process table to see if server is running without pid file
    return :missing_pid
  end
end

OptionParser.new do |opts|
  opts.banner = "Usage: #{$0} (start|stop|restart) [options]"
  opts.banner += "\nruby-server-ctl is only usable when using webrick or mongrel"
 
  opts.on("-c", "--config FILE", "Path to rubycas-server configuration file") { |value| @options[:conf_file] = value }
  opts.on("-P", "--pid_file FILE", "Path to rubycas-server pid file") { |value| @options[:pid_file] = value }
  opts.on('-v', '--verbose', "Print all called commands and output.") { |value| @options[:verbose] = value }

  if ARGV.empty?
    puts opts
    exit
  else
    @cmd = opts.parse!(ARGV)
    if @cmd.nil?
      puts opts
      exit
    end
  end
end

if !@options[:conf_file].nil? && !File.exists?(@options[:conf_file])
  puts "Invalid path to rubycas-server configuration file: #{@options[:conf_file]}"
  exit
end

case @cmd[0]
when "start": 
  puts "Starting rubycas-server..."
  start
when "stop":
  puts "Stopping rubycas-server..."
  stop
when "restart":
  puts "Restarting rubycas-server..."
  stop
  start
when "status":
  puts "Checking status of rubycas-server..."
  status
else
 puts "Invalid command. Usage: rubycas-server-ctl [-cPv] start|stop|restart|status"
end

exit