require 'eventmachine'
require 'mixlib/cli'
require 'servolux'

require 'ganymed'
require 'ganymed/collector'
require 'ganymed/version'

require 'metriks'
require 'metriks/reporter/logger'

module Ganymed
  # @private
  class Master < ::Servolux::Server

    def initialize(cli)
      # initialize servolux
      super('ganymed',
            :interval => 1,
            :logger => $log,
            :pid_file => cli[:pidfile])
    end

    def run
      $log.info("starting Ganymed reactor in #{Env.mode} mode")

      # configure eventmachine
      $log.debug("EventMachine threadpool_size=#{$config.eventmachine.threadpool_size}")
      EventMachine.threadpool_size = $config.eventmachine.threadpool_size

      EventMachine.epoll # use epoll
      EventMachine.run do
        Collector.new($config) if $config.collectors.any?
        Metriks::Reporter::Logger.new({
          :logger => $log,
          :interval => $config.interval,
          :on_error => ->(e) { $log.exception(e) },
        }).start
      end

    rescue Exception => exc
      $log.exception(exc)
    end

    def before_starting
      if $config.profiling.perftools
        $log.info("activating PerfTools CPU profiler")
        require 'perftools'
        PerfTools::CpuProfiler.start('profile')
      end

      if $config.profiling.gcprofiler
        $log.info("activating GC::Profiler")
        GC::Profiler.enable
      end

      if $config.profiling.rubyprof
        require 'ruby-prof'
        $log.info("activating RubyProf")
        RubyProf.start
      end
    end

    def before_stopping
      if EventMachine.reactor_running?
        $log.info("shutting down Ganymed reactor")
        EventMachine.stop_event_loop
      end
    end

    def after_stopping
      if $config.profiling.perftools
        PerfTools::CpuProfiler.stop
        `pprof.rb --svg profile > profile.svg`
      end

      if $config.profiling.rubyprof
        result = RubyProf.stop
        result.eliminate_methods!([
          /Queue#pop/,
          /Queue#push/,
          /Mutex#synchronize/,
          /Mutex#sleep/,
        ])
        printer = RubyProf::MultiPrinter.new(result)
        printer.print(:path => "prof", :profile => "ganymed")
      end

      $log.info("done shutting down. exiting ...")
    end

    class CLI
      include Mixlib::CLI

      option :config_file,
        :short => '-c CONFIG',
        :long => '--config CONFIG',
        :description => "The configuration file to use"

      option :log_backend,
        :short => '-l BACKEND',
        :long => '--log-backend BACKEND',
        :description => "The log backend to use",
        :default => "stdout"

      option :pidfile,
        :short => '-p PIDFILE',
        :long => '--pidfile PIDFILE',
        :description => "The daemon pidfile",
        :default => "ganymed.pid"

      option :debug,
        :short => '-D',
        :long => '--debug',
        :description => "Enable debug output",
        :boolean => true

      option :daemonize,
        :short => '-d',
        :long => '--daemonize',
        :description => "Daemonize the server process",
        :boolean => true

      option :kill,
        :short => '-k',
        :long => '--kill',
        :description => "Kill the currently running daemon instance",
        :boolean => true

      option :environment,
        :short => '-e ENVIRONMENT',
        :long => '--environment ENVIRONMENT',
        :description => "Set the daemon environment",
        :default => "development",
        :proc => ->(value) { ENV[Env.key] = value }

      option :help,
        :short => '-h',
        :long => '--help',
        :description => "Show this message",
        :on => :tail,
        :boolean => true,
        :show_options => true,
        :exit => 0

      def self.parse_options
        new.tap do |cli|
          cli.parse_options
        end
      end
    end
  end
end