# = Autoreload
#
# Autoreload feature files.
#
# Automatically reload, at regular intervals, any previously loaded features,
# and/or other files not already loaded, if they have been modified since the last
# interval check. A numeric parameter sets the reload interval in seconds
# and the file parameter can either be a glob string or an array
# of file paths. If a glob string, it is expanded only once on the initial
# method call. Supplying a boolean parameter of 'false' will force autreload to
# skip previously loaded features and only reload the specified files.
# Also keeps a "dirty" flag.
#
# == Authors
#
#   - Michael Neumann
#   - George Moschovitis
#
# == TODO
#
# * Create tests for autoreload.
#
# == Copying
#
# Copyright (c) 2003 Michael Neumann
#
# Ruby License
#
# This module is free software. You may use, modify, and/or redistribute this
# software under the same terms as Ruby.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.

#
module Kernel

  # Autoreload feature files.
  #
  # Automatically reload, at regular intervals, any previously loaded features,
  # and/or other files not already loaded, if they have been modified since the last
  # interval check. A numeric parameter sets the reload interval in seconds
  # and the file parameter can either be a glob string or an array
  # of file paths. If a glob string, it is expanded only once on the initial
  # method call. Supplying a boolean parameter of 'false' will force autreload to
  # skip previously loaded features and only reload the specified files.
  # Also keeps a "dirty" flag.

  def autoreload( *args )

    check_interval=10
    include_features = true
    files = nil

    args.each do |arg|
      case arg
      when Numeric
        check_interval = arg
      when String
        files = Dir.glob( arg )
      when Array
        files = arg
      when TrueClass, FalseClass
        include_features = arg
      end
    end

    file_mtime = {}

    Thread.new(Time.now) do |start_time|
      loop do
        sleep check_interval

        if include_features
          feature_files = $LOADED_FEATURES.collect { |feature|
            $LOAD_PATH.each { |lp| file = File.join(lp, feature) }
          }.flatten

          feature_files.each { |file|
            if File.exists?(file) and (mtime = File.stat(file).mtime) > (file_mtime[file] || start_time)
              $autoreload_dirty = true
              file_mtime[file] = mtime
              STDERR.puts "File '#{ file }' reloaded"
              begin
                load(file)
              rescue Exception => e
                STDERR.puts e.inspect
              end
            end
          }
        end

        if files
          files.each do |file|
            if File.exists?(file) and (mtime = File.stat(file).mtime) > (file_mtime[file] || start_time)
              $autoreload_dirty = true
              file_mtime[file] = mtime
              STDERR.puts "File '#{ file }' changed"
            end
          end
        end

      end
    end

  end

  # Same as #autoreload, but does not include previously loaded features.
  # This is equivalent to as adding a 'false' parameter to #autoreload.
  #
  def autoreload_files( *args )
    autoreload( false, *args )
  end

  # deprecate
  #def autoreload_glob(*args)
  #  warn "autoreload_glob will be deprecated. Use autoreload_files instead."
  #  autoreload_files(*args)
  #end

end

#--
#   # OLD VERSION
#   def autoreload(check_interval=10)
#     Thread.new(Time.now) { |start_time|
#       file_mtime = {}
#       loop {
#         sleep check_interval
#         $LOADED_FEATURES.each { |feature|
#           $LOAD_PATH.each { |lp|
#             file = File.join(lp, feature)
#             if (File.exists?(file) and
#               File.stat(file).mtime > (file_mtime[file] || start_time))
#               file_mtime[file] = File.stat(file).mtime
#               STDERR.puts "reload #{ file }"
#               begin
#                 load(file)
#               rescue Exception => e
#                 STDERR.puts e.inspect
#               end
#             end
#           }
#         }
#       }
#     }
#   end
#++

