#!/usr/bin/env ruby
#
#  equityctl - management client for equity
#
#  Usage: equityctl [<host>:]<port> <command>
#
#  The host defaults to localhost.
#
#  Command    Description
#  status     Displays each node's address, port, connection status, and
#             connection counter.
#
#  Equity uses UDP packets to send control information, so all of UDP's caveats
#  apply to equityctl.
#

require 'equity/controller'
require 'getoptlong'

# Process options.
options = GetoptLong.new(
  ["--genkey", GetoptLong::NO_ARGUMENT]
)
options.each do |option, argument|
  case option
  when "--genkey"
    $genkey = true
  end
end

if ($genkey && !ARGV.empty?) || (!$genkey && ARGV.length != 2)
  STDERR.puts 'Usage: equityctl [<host>:]<port> <command>'
  STDERR.print "\n"
  STDERR.puts 'The host defaults to localhost.'
  STDERR.print "\n"
  STDERR.puts 'Command    Description'
  STDERR.puts 'status     Displays each node\'s address, port, connection status,'
  STDERR.puts '           connection counter, and failure counter.'
  STDERR.puts 'shutdown   Close connections immediately and shut down.'
  STDERR.print "\n\n"
  STDERR.puts 'Usage: equityctl --genkey'
  STDERR.print "\n"
  STDERR.puts 'With the --genkey option, equityctl generates a public/private key pair for'
  STDERR.puts 'authenticating itself to equity.'
  exit(64) # EX_USAGE
end

# If --genkey was specified, generate a key pair and exit.
if $genkey
  puts "Generating key..."
  begin
    key = Equity::Controller::Key.generate
  rescue Exception => e
    STDERR.puts e.message
    exit(1)
  end
  puts "Done! For reference, your key is stored here:"
  key.paths.each {|path| puts "  #{path}"}
  # Tell the user where they need to put their public key in order for it to be
  # useful.
  puts "\nTo be authorized to use equityctl with your own equity processes, your public"
  puts "key must be appended to:"
  puts "  " + Equity::Controller::Key::PERSONAL_AUTHORIZED_KEYS_PATH  
  puts "\nTo be authorized to use equityctl with other people's equity processes, your"
  puts "public key must be appended to:"
  puts "  " + Equity::Controller::Key::SYSTEM_AUTHORIZED_KEYS_PATH
  exit
end

# Extract address, port, and command from arguments.
address, port = ARGV.shift.split(':', 2)
if port.nil?
  port = address
  address = 'localhost'
end

command = ARGV.shift

# Send command.
class NoResponseError < Exception; end

controller = Equity::Controller.new(address, port.to_i)
begin
  case command
  when 'status'
    nodes = controller.node_status || raise(NoResponseError)
    nodes.each do |node|
      puts "#{node} #{node.connected? ? 'C' : '-'} #{node.counter} #{node.failure_counter}"
    end
  when 'shutdown'
    controller.shutdown || raise(NoResponseError)
  else
    STDERR.puts "Unrecognized command: #{command}"
    STDERR.puts 'Run equityctl with no arguments for a list of commands.'
    exit(64)
  end
rescue NoResponseError
  STDERR.puts "No response from #{address}:#{port}"
  exit(1)
end
