require "fpm/namespace"
require "fpm/source"
require "rubygems/package"
require "rubygems"
require "fileutils"

class FPM::Source::Gem < FPM::Source
  def get_source(params)
    gem = @paths.first
    looks_like_name_re = /^[A-Za-z0-9_-]+$/
    if !File.exists?(gem) 
      if gem =~ looks_like_name_re
        download(gem, params[:version])
      else
        raise "Path '#{gem}' is not a file and does not appear to be the name of a rubygem."
      end
    end
  end # def get_source

  def can_recurse_dependencies
    true
  end

  def download(gem_name, version=nil)
    # This code mostly mutated from rubygem's fetch_command.rb
    # Code use permissible by rubygems's "GPL or these conditions below"
    # http://rubygems.rubyforge.org/rubygems-update/LICENSE_txt.html

    puts "Trying to download #{gem_name} (version=#{version})"
    dep = ::Gem::Dependency.new gem_name, version
    # How to handle prerelease? Some extra magic options?
    #dep.prerelease = options[:prerelease]
    
    if ::Gem::SpecFetcher.fetcher.respond_to?(:fetch_with_errors)
      specs_and_sources, errors =
        ::Gem::SpecFetcher.fetcher.fetch_with_errors(dep, true, true, false)
    else
      specs_and_sources = 
        ::Gem::SpecFetcher.fetcher.fetch(dep, true)
      errors = "???"
    end
    spec, source_uri = specs_and_sources.sort_by { |s,| s.version }.last

    if spec.nil? then
      raise "Invalid gem? Name: #{gem_name}, Version: #{version}, Errors: #{errors}"
    end

    path = ::Gem::RemoteFetcher.fetcher.download spec, source_uri
    FileUtils.mv path, spec.file_name
    @paths = [spec.file_name]
  end

  def get_metadata
    File.open(@paths.first, 'r') do |f|
      ::Gem::Package.open(f, 'r') do |gem|
        spec = gem.metadata
        %w(
          description
          license
          summary
          version
        ).each do |field|
          self[field.to_sym] = spec.send(field) rescue "unknown"
        end

        self[:name] = "rubygem#{self[:suffix]}-#{spec.name}"
        self[:maintainer] = spec.author
        self[:url] = spec.homepage

        # TODO [Jay]: this will be different for different
        # package managers.  Need to decide how to handle this.
        self[:category] = 'Languages/Development/Ruby'

        self[:dependencies] = []
        spec.runtime_dependencies.map do |dep|
          # rubygems 1.3.5 doesn't have 'Gem::Dependency#requirement'
          if dep.respond_to?(:requirement)
            reqs = dep.requirement.to_s.gsub(/,/, '')
          else
            reqs = dep.version_requirements
          end

          # Some reqs can be ">= a, < b" versions, let's handle that.
          reqs.to_s.split(/, */).each do |req|
            self[:dependencies] << "rubygem#{self[:suffix]}-#{dep.name} #{req}"
          end
        end # runtime_dependencies
      end # ::Gem::Package
    end # File.open (the gem)
  end # def get_metadata

  def make_tarball!(tar_path, builddir)
    tmpdir = "#{tar_path}.dir"
    installdir = "#{tmpdir}/#{::Gem::dir}"
    ::FileUtils.mkdir_p(installdir)
    args = ["gem", "install", "--quiet", "--no-ri", "--no-rdoc",
       "--install-dir", installdir, "--ignore-dependencies", @paths.first]
    system(*args)
    
    @paths = [ ::Gem::dir ]
    tar(tar_path, ".#{@paths.first}", tmpdir)
    FileUtils.rm_r(tmpdir)

    # TODO(sissel): Make a helper method.
    system(*["gzip", "-f", tar_path])
  end

end # class FPM::Source::Gem
