#! /usr/bin/ruby1.8
# NAME
#  mauveserver -- receive alerts from station(s) around the network
#
# SYNOPSIS
#  mauveserver [ -h | --help ] [-m | --manual] [-V | --version] [<configuration file>]
#
# OPTIONS
#  -h, --help            Show a help message, and exit.
#
#  -V, --version         Show the version, and exit.
#
#  -m, --manual          Show this manual, and exit.
#
#  -v, --verbose         Show verbose errors
#
#  -t, --test            Test the configuration
#
#  <configuration file>  File from whence to load the configuration. If none is
#                        specified, then mauvealert.conf in the current
#                        directory is used, and failing that
#                        /etc/mauvealert/mauvealert.conf is used.
#
# CONFIGURATION FILE
#
# The configuration file consists of various stanzas, and sub-stanzas which
# give give options for each part of the server.  The example configuration
# file gives a definitive explanation of all the options.
# 
# SEE ALSO
#  mauveclient(1), mauveconsole(1)
#
# AUTHOR
#  Patrick J Cherry <patrick@bytemark.co.uk>
#

help = manual = verbose = version = test = false
while arg = ARGV.pop
  case arg
    when  /-(h|-help)/
      help = true
    when /-(V|-version)/
      version = true
    when /-(m|-manual)/
      manual = true
    when /(-(v|-verbose))/
      verbose = true
    when /(-(t|-test))/
      test = true
    else
      configuration_file = arg
  end
end

#
# CAUTION! Kwality kode.
#
if manual or help
  # Open the file, stripping the shebang line
  lines = File.open(__FILE__){|fh| fh.readlines}[1..-1]
  found_synopsis = false

  lines.each do |line|

    line.chomp!
    break if line.empty?

    if help and !found_synopsis
      found_synopsis = (line =~ /^#\s+SYNOPSIS\s*$/) if !found_synopsis
      next
    end

    puts line[2..-1].to_s

    break if help and found_synopsis and line =~ /^#\s*$/

  end
end

require 'mauve/version'

puts "#{$0}: version "+Mauve::VERSION if version

exit 0 if help or version or manual

require 'log4r'

#
# Initial logger -- gets detroyed later.
#
logger      = Log4r::Logger.new 'Mauve'
outputter   = Log4r::StderrOutputter.new("initial")
outputter.formatter = Log4r::PatternFormatter.new( :pattern => "%d [ %6.6l ] [ %12.12c ] %m" )
outputter.level     = verbose ? Log4r::DEBUG : Log4r::INFO
logger.outputters   << outputter

def error(msg)
  logger = Log4r::Logger['Mauve']
  logger.error "*** Error: #{msg}"
  logger.error "*** For help, type: #{$0} -h"

  if msg.respond_to?("backtrace")
    logger.debug "*** Backtrace:"
    logger.debug msg.backtrace.join("\n")
  end

  exit 1
end


begin
  eval "Proc.new { |a,&b| }"
rescue SyntaxError => no_blocks_with_procs
  error "mauveserver must have Ruby 1.8.7 or later."
end

configuration_file = [".", "/etc/mauvealert/"].collect{|x| File.join(x, "mauveserver.conf") }.find{|d| File.file?(d)} if configuration_file.nil?
configuration_file = File.expand_path(configuration_file) unless configuration_file.nil?

if configuration_file.nil?
  error "No configuration file could be found"
end

unless File.file?(configuration_file)
  error "Configuration file #{configuration_file} not found"
end

require 'mauve/configuration'
require 'mauve/configuration_builder'
require 'mauve/configuration_builders'

begin
  builder = Mauve::ConfigurationBuilder.new
  builder.include_file(configuration_file)
  Mauve::Configuration.current = builder.result
rescue StandardError => ex
  error ex 
end

if test
  logger.info "*** Configuration looks OK!"
  exit 0 
end

%w(HUP).each do |sig|
  trap(sig) do
    Mauve::Server.instance.logger.warn "#{sig} signal received.  Restarting."
    Mauve::Server.instance.stop

    # 
    # Reload configuration
    #
    begin
      builder = Mauve::ConfigurationBuilder.new
      builder.include_file(configuration_file)
      Mauve::Configuration.current = builder.result
    rescue BuildException => ex
      Mauve::Server.instance.logger.error "Reconfiguration failed: #{ex.to_s}.  Sticking with old one."
    end
    Mauve::Server.instance.logger.warn "Restarting."
    Mauve::Server.instance.start
  end
end

%w(USR1).each do |sig|
  trap(sig) do
    Mauve::Server.instance.logger.warn "#{sig} signal received. Re-opening logs."

    Log4r::Outputter.each_outputter do |old|
      next unless old.is_a?(Log4r::FileOutputter)

      new = Log4r::FileOutputter.new(old.name, {:filename => old.filename, :trunc => false})
      new.formatter = old.formatter
      new.level     = old.level

      Mauve::Server.instance.logger.info "Closing #{old.filename}."

      #
      # Delete the outputter from each logger.
      #
      Log4r::Logger.each_logger do |l|
        l.outputters << new
        l.outputters.delete(old)
      end

      old.flush
      old.close

      Mauve::Server.instance.logger.info "Opened #{new.filename}."
    end
  end
end

%w(QUIT TERM INT).each do |sig|
  trap(sig) do
    Mauve::Server.instance.logger.warn "#{sig} signal received.  Stopping."
    Mauve::Server.instance.stop
    exit 0
  end
end

begin
  if outputter and logger.outputters.include?(outputter)
    logger.debug "Closing initial outputter"
    logger.outputters.delete(outputter)
    outputter.flush
    outputter.close
  end

  logger.info "This is mauve #{Mauve::VERSION}"
  Mauve::Server.instance.start
rescue StandardError => ex
  error ex 
end