require 'fileutils'
require 'yaml'

class ActiveListener
  attr_reader :events

  def self.autostart(opts = {})
    begin
      config_file = File.expand_path(opts[:config])
      pid_file    = File.expand_path(opts[:pid_file])
      log_file    = File.expand_path(opts[:log_file])
      rake_root   = File.expand_path(opts[:rake_root])
    rescue
      raise "Need :config :pid_file :log_file :rake_root"
    end
    ActiveListener.stop(opts)
    command = [
      "start-stop-daemon --start",
      "--make-pidfile --pidfile #{pid_file}",
      "--background",
      "--exec #{File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'active-listener'))}",
      "--chdir #{File.expand_path(File.dirname(__FILE__))}",
      "--",
      "#{config_file}",
      "#{log_file}",
      "#{rake_root}"
    ].join(" ")
    `#{command}`
  end

  def self.stop(opts = {})
    pid_file = opts[:pid_file]
    `start-stop-daemon --stop --oknodo --quiet --pidfile #{File.expand_path(pid_file)}`
  end

  def initialize(opts = {})
    self.events = []
    self.log_file = opts[:log_file]
    self.rake_root = opts[:rake_root]
    clear_log
    log("ActiveListener Initialized")
    load_events(opts[:config])
  end

  def add_event(evt)
    self.events.push(evt)
    log("Added Event #{evt.inspect}")
  end

  def fire_events
    self.events.select{|e| e.time_to_fire < 0}.each do |evt|
      log("Firing event: #{evt.inspect}")
      log(evt.fire(:rake_root => rake_root))
    end
  end

  def sleep_to_next_event
    self.events.sort{|x,y| x.time_to_fire <=> y.time_to_fire}
    if self.events.first
      sleep_time = self.events.first.time_to_fire+0.01
    else
      sleep_time = 0.5
    end
    log("Sleeping for #{sleep_time}")
    sleep(sleep_time)
  end

  class Event
    def initialize(opts = {})
      self.task = opts[:task] || opts["task"]
      self.period = opts[:period] || opts["period"]
      self.last_fire = 0
    end

    def time_to_fire
      last_fire + period - Time.now.to_f
    end

    def fire(opts = {})
      self.last_fire = Time.now.to_f
      Dir.chdir(opts[:rake_root]) if opts[:rake_root]
      `rake #{task}`
      opts[:rake_root]
    end

    private

    attr_accessor :task, :period, :last_fire

  end

  private

  attr_writer :events
  attr_accessor :log_file, :rake_root

  def load_events(config_file)
    return if config_file.nil?
    unless File.exists?(config_file)
      log("Config file not found at #{config_file}")
      return
    end
    log("Loading tasks from #{config_file}")
    f = File.new(config_file,'r')
    yml = YAML.load(f)
    yml["tasks"].each do |task|
      self.add_event(Event.new(task))
    end
  end

  def clear_log
    return unless log_file
    FileUtils.rm_f log_file
  end

  def log(text)
    return unless log_file
    f = File.new(log_file, 'a')
    f.write text
    f.write "\n"
    f.close
  end

end