##
# Used to implement Module#autoload.

class Autoload
  attr_reader :name
  attr_reader :scope
  attr_reader :path
  attr_reader :original_path

  def initialize(name, scope, path)
    @name = name
    @scope = scope
    @original_path = path
    @path, = __split_path__(path)
    Autoload.add(self)
  end

  def call
    require(path)
    scope.const_get(name)
  end

  def discard
    scope.__send__(:remove_const, name)
  end

  class << self
    def autoloads
      @autoloads ||= []
    end

    def add(al)
      autoloads << al
    end

    ##
    # ruthlessly taken from Array#delete
    # modified to return after the first one
    # This code is specific to Autoload, see line 52
    # for the coupling. It calls #path on the Autoload object
    def delete_first(array, obj)
      i = array.start
      tot = array.start + array.total
      already_placed = false # initialize our check

      # Leaves the tuple to the original size still
      while i < tot
        if array.tuple.at(i) == obj
          j = i
          i += 1

          while i < tot
            if (array.tuple.at(i).path != obj) || already_placed
              array.tuple.put(j, array.tuple.at(i))
              j += 1
            else
              already_placed = true # move all the others if we placed one
            end

            i += 1
          end

          array.total = j - array.start
          return obj
        end

        i += 1
      end

      yield if block_given?
    end

    def remove(path)
      al = delete_first(autoloads, path)
      al.discard if al
    end
  end
end

__END__

##
# Used to implement Module#autoload.

class Autoload
  attr_reader :name
  attr_reader :scope
  attr_reader :path
  attr_reader :original_path

  def initialize(name, scope, path)
    @name = name
    @scope = scope
    @original_path = path
    @path, = __split_path__(path)
    Autoload.add(self)
  end

  def call
    require(path)
    scope.const_get(name)
  end

  def discard
    scope.__send__(:remove_const, name)
  end

  class << self
    def autoloads
      @autoloads ||= {}
    end

    def add(al)
      autoloads[al.path] = al
    end

    def remove(path)
      al = autoloads.delete(path)
      al.discard if al
    end
  end
end