module Hoe::Deps

def check_extra_deps_task # :nodoc:

:nodoc:
def check_extra_deps_task # :nodoc:
  (extra_deps + extra_dev_deps).each do |dep|
    begin
      gem(*dep)
    rescue Gem::LoadError
      name, req, = dep
      install_gem name, req, false
      gem(*dep)
    end
  end
end

def define_deps_tasks

def define_deps_tasks
  namespace :deps do
    desc "List all the dependent gems of this gem"
    task :list do
      deps_list_task
    end
    desc "Print a contact list for gems dependent on this gem"
    task :email do
      deps_email_task
    end
    desc "Fetch all the dependent gems of this gem into tarballs"
    task :fetch do
      deps_fetch_task
    end
  end
  desc "Install missing dependencies."
  task :check_extra_deps do
    check_extra_deps_task
  end
  desc "Install missing plugins."
  task :install_plugins do
    install_missing_plugins
  end
end

def dependent_upon name

def dependent_upon name
  get_latest_gems.find_all { |gem|
    gem.dependencies.any? { |dep| dep.name == name }
  }
end

def deps_email_task # :nodoc:

:nodoc:
def deps_email_task # :nodoc:
  gems = self.get_gems_by_name
  gem  = gems[self.name]
  abort "Couldn't find gem: #{self.name}" unless gem
  deps = self.dependent_upon self.name
  email = deps.map(&:email).compact.flatten.sort.uniq
  email = email.map { |s| s.split(/,\s*/) }.flatten.sort.uniq
  email.map! { |s| # don't you people realize how easy this is?
    s.gsub(/ at | _at_ |\s*(atmark|@nospam@|-at?-|@at?@|<at?>|\[at?\]|\(at?\))\s*/i, "@").gsub(/\s*(dot|\[d(ot)?\]|\.dot\.)\s*/i, ".").gsub(/\s+com$/, ".com")
  }
  bad, good = email.partition { |e| e !~ /^[\w.+-]+\@[\w.+-]+$/ }
  warn "Rejecting #{bad.size} email. I couldn't unmunge them." unless
    bad.empty?
  puts good.join(", ")
  warn "Warning: couldn't extract any email addresses" if good.empty?
end

def deps_fetch_task # :nodoc:

:nodoc:
def deps_fetch_task # :nodoc:
  deps = self.dependent_upon self.name
  mkdir "deps" unless File.directory? "deps"
  Dir.chdir "deps" do
    begin
      deps.sort_by(&:full_name).each do |spec|
        full_name = spec.full_name
        tgz_name  = "#{full_name}.tgz"
        gem_name  = "#{full_name}.gem"
        next if File.exist? tgz_name
        FileUtils.rm_rf [full_name, gem_name]
        begin
          warn "downloading #{full_name}"
          Gem::RemoteFetcher.fetcher.download(spec, GEMURL, Dir.pwd)
          FileUtils.mv "cache/#{gem_name}", "."
        rescue Gem::RemoteFetcher::FetchError
          warn "  failed"
          next
        end
        warn "converting #{gem_name} to tarball"
        system "gem unpack #{gem_name} 2> /dev/null"
        system "gem spec -l #{gem_name} > #{full_name}/gemspec.rb"
        system "tar zmcf #{tgz_name} #{full_name}"
        FileUtils.rm_rf [full_name, gem_name, "cache"]
      end
    ensure
      FileUtils.rm_rf "cache"
    end
  end
end

def deps_list_task # :nodoc:

:nodoc:
def deps_list_task # :nodoc:
  gems = self.get_gems_by_name
  gem  = gems[self.name]
  abort "Couldn't find gem: #{self.name}" unless gem
  deps = self.dependent_upon self.name
  max  = deps.map { |s| s.full_name.size }.max
  puts "  dependents:"
  unless deps.empty? then
    deps.sort_by(&:full_name).each do |spec|
      vers = spec.dependencies.find { |s| s.name == name }.requirements_list
      puts "    %-*s - %s" % [max, spec.full_name, vers.join(", ")]
    end
  else
    puts "    none"
  end
end

def get_gems_by_name

def get_gems_by_name
  @@by_name ||= Hash[*get_latest_gems.map { |gem|
                       [gem.name, gem, gem.full_name, gem]
                     }.flatten]
end

def get_latest_gems

def get_latest_gems
  @@cache ||= Hash[*get_source_index.flatten].values
end

def get_source_index

def get_source_index
  @@index ||= nil
  return @@index if @@index
  dump = unless File.exist? ".source_index" then
           warn "Fetching full index and caching. This can take a while."
           url = GEMURL + "Marshal.#{Gem.marshal_version}.Z"
           dump = Gem::RemoteFetcher.fetcher.fetch_path url
           dump = Gem.inflate dump
           warn "stripping index to latest gems"
           ary = Marshal.load dump
           h = {}
           Hash[ary].values.sort.each { |spec| h[spec.name] = spec }
           ary = h.map { |_, v| [v.full_name, v] }
           dump = Marshal.dump ary
           open ".source_index", "wb" do |io| io.write dump end
           dump
         else
           open ".source_index", "rb" do |io| io.read end
         end
  @@index = Marshal.load dump
end

def install_missing_plugins plugins = Hoe.bad_plugins

def install_missing_plugins plugins = Hoe.bad_plugins
  version = ">= 0"
  plugins.each do |name|
    dash_name = name.to_s.gsub "_", "-"
    next if have_gem?("hoe-#{name}") or
              have_gem?(name) or
              have_gem?(dash_name)
    install_gem("hoe-#{name}", version, false) or
      install_gem(name, version, false) or
      install_gem(dash_name, version, false) or
      warn "could not install gem for #{name} plugin"
  end
end