class RubyForge

def add_file(group_name, package_name, release_name, userfile)

def add_file(group_name, package_name, release_name, userfile)
  type_id      = @userconfig["type_id"]
  group_id     = lookup "group", group_name
  package_id   = lookup "package", package_name
  release_id   = (Integer === release_name) ? release_name : lookup("release", package_name)[release_name]
  url = "/releases/#{release_id}/files.js"
  userfile = open userfile, 'rb'
  type_id ||= userfile.path[%r|\.[^\./]+$|]
  type_id = (lookup "type", type_id rescue lookup "type", ".oth")
  processor_id = @userconfig["processor_id"]
  processor_id ||= "Any"
  processor_id = lookup "processor", processor_id
  form = {
    "file[filename]"      => File.basename(userfile.path),
    "file[processor_id]"  => processor_id,
    "file[type_id]"       => type_id,
    "contents"            => userfile.read
  }
  run url, form
end

def add_release(group_id, package_id, release_name, *files)

def add_release(group_id, package_id, release_name, *files)
  group_id        = lookup "group", group_id
  package_id      = lookup "package", package_id
  release_date    = @userconfig["release_date"]
  release_notes   = @userconfig["release_notes"]
  release_changes = @userconfig["release_changes"]
  preformatted    = @userconfig["preformatted"]
  release_date ||= Time.now.strftime("%Y-%m-%d %H:%M")
  release_notes = IO::read(release_notes) if
    test(?e, release_notes) if release_notes
  release_changes = IO::read(release_changes) if
    test(?e, release_changes) if release_changes
  preformatted = preformatted ? 1 : 0
  form = {
      "release[name]"    => release_name,
      "release[release_date]"     => release_date,
      "release[notes]"   => release_notes,
      "release[changes]" => release_changes,
      "release[preformatted]"    => preformatted,
  }
  url = "/packages/#{package_id}/releases"
  json = run url, form
  
  release_id = JSON.parse(json)["release_id"].to_i rescue nil
  unless release_id then
    puts json if $DEBUG
    raise "Couldn't get release_id, upload failed?"
  end
  # FIXME
  #raise "Invalid package_id #{package_id}" if html[/Invalid package_id/]
  #raise "You have already released this version." if html[/That filename already exists in this project/]
  files.each do |file|
    add_file(group_id, package_id, release_id, file)
  end
  package_name = @autoconfig["package_ids"].invert[package_id]
  raise "unknown package name for #{package_id}" if package_name.nil?
  @autoconfig["release_ids"][package_name] ||= {}
  @autoconfig["release_ids"][package_name][release_name] = release_id
  save_autoconfig
  release_id
end

def client

def client
  return @client if @client
  @client = RubyForge::Client::new ENV["HTTP_PROXY"]
  @client.debug_dev = STDERR if ENV["RUBYFORGE_DEBUG"] || ENV["DEBUG"] || $DEBUG
  @client
end

def configure opts = {}

def configure opts = {}
  user_path        = CONFIG_F
  dir, file        = File.split(user_path)
  @userconfig      = if test(?e, user_path) then
                       YAML.load_file(user_path)
                     else
                       CONFIG
                     end.merge(opts)
  @autoconfig_path = File.join(dir, file.sub(/^user/, 'auto'))
  @autoconfig      = if test(?e, @autoconfig_path) then
                       YAML.load_file(@autoconfig_path)
                     else
                       CONFIG["rubyforge"].dup
                     end
  @autoconfig["type_ids"] = CONFIG['rubyforge']['type_ids'].dup
  raise "no <username>"   unless @userconfig["username"]
  raise "no <password>"   unless @userconfig["password"]
  self
end

def create_package(group_id, package_name)

def create_package(group_id, package_name)
  page = "/groups/#{group_id}/packages"
  group_id = lookup "group", group_id
  is_private = @userconfig["is_private"]
  is_public = is_private ? 0 : 1
  form = {
    "package[name]" => package_name,
    "package[is_public]"    => is_public
  }
  run page, form
  group_name = @autoconfig["group_ids"].invert[group_id]
  scrape_project(group_name)
end

def delete_package(group_id, package_id)

def delete_package(group_id, package_id)
  group_id = lookup "group", group_id
  package_id = lookup "package", package_id
  package_name = @autoconfig["package_ids"].invert[package_id]
  @autoconfig["package_ids"].delete package_name
  @autoconfig["release_ids"].delete package_name
  save_autoconfig
  url = "/packages/#{package_id}"
  run url, {"_method" => "delete"}
end

def force

def force
  @userconfig['force']
end

def get_via_rest_api(path)

def get_via_rest_api(path)
  url = "#{self.uri}#{path}"
  puts "Hitting REST API: #{url}" if $DEBUG
  JSON.parse(client.get_content(url, {}, {}, @userconfig))
end

def initialize(userconfig=nil, autoconfig=nil, opts=nil)

def initialize(userconfig=nil, autoconfig=nil, opts=nil)
  # def initialize(userconfig=CONFIG_F, opts={})
  @userconfig, @autoconfig = userconfig, autoconfig
  @autoconfig ||= CONFIG["rubyforge"].dup
  @userconfig.merge! opts if opts
  @client = nil
  @uri = nil
end

def login ; end

These are no-ops now, but we'll keep them here for backwards compatibility
def login ; end

def logout ; end

def logout ; end

def lookup(type, val) # :nodoc:

:nodoc:
def lookup(type, val) # :nodoc:
  unless Fixnum === val then
    key = val.to_s
    val = @autoconfig["#{type}_ids"][key]
    raise "no <#{type}_id> configured for <#{ key }>" unless val
  end
  val
end

def post_news(group_id, subject, body)

def post_news(group_id, subject, body)
  # TODO - what was the post_changes parameter for?
  form = {
    "news_byte[summary]"      => subject,
    "news_byte[details]"      => body
  }
  group_id = lookup "group", group_id
  url = "/groups/#{group_id}/news_bytes"
  run url, form
end

def run(page, form, extheader={}) # :nodoc:

:nodoc:
def run(page, form, extheader={}) # :nodoc:
  uri = self.uri + page
  puts "client.post_content #{uri.inspect}, #{form.inspect}, #{extheader.inspect}" if $DEBUG
  response = client.post_content uri, form, extheader, @userconfig
  puts response if $DEBUG
  response
end

def save_autoconfig

def save_autoconfig
  File.open(@autoconfig_path, "w") do |file|
    YAML.dump @autoconfig, file
  end
end

def scrape_config

def scrape_config
  username = @userconfig['username']
  %w(group package processor release).each do |type|
    @autoconfig["#{type}_ids"].clear if @autoconfig["#{type}_ids"]
  end

  json = get_via_rest_api "/users/#{username}/groups.js"
  projects = json.collect {|group| group['group']['unix_group_name'] }
  puts "Fetching #{projects.size} projects"
  projects.each do |project|
    scrape_project(project)
  end
end

def scrape_project(project)

def scrape_project(project)
  data = {
    "group_ids"     => {},
    "package_ids"   => {},
    "processor_ids" => Hash.new { |h,k| h[k] = {} },
    "release_ids"   => Hash.new { |h,k| h[k] = {} },
  }
  unless data["group_ids"].has_key? project then
    json = get_via_rest_api "/groups/#{project}.js"
    group_id = json["group"]["group_id"].to_i
    data["group_ids"][project] = group_id
  end
  # Get project's packages 
  json = get_via_rest_api "/groups/#{project}/packages.js"
  json.each do |package|
    data["package_ids"][package["package"]["name"]] = package["package"]["package_id"]
    # Get releases for this package
    json = get_via_rest_api "/packages/#{package["package"]["package_id"]}/releases.js"
    json.each do |release|
      data["release_ids"][package["package"]["name"]][release["name"]] = release["release_id"]
    end
  end
  # Get processor ids
  if @autoconfig['processor_ids'].nil? || @autoconfig['processor_ids'].empty?
    puts "Fetching processor ids" if $DEBUG
    json = get_via_rest_api "/processors.js"
    json.each do |processor|
      data["processor_ids"][processor["processor"]["name"]] = processor["processor"]["processor_id"]
    end
  end
  data.each do |key, val|
    @autoconfig[key] ||= {}
    @autoconfig[key].merge! val
  end
  save_autoconfig
end

def setup

def setup
  FileUtils::mkdir_p RUBYFORGE_D, :mode => 0700 unless test ?d, RUBYFORGE_D
  test ?e, CONFIG_F and FileUtils::mv CONFIG_F, "#{CONFIG_F}.bak"
  config = CONFIG.dup
  config.delete "rubyforge"
  open(CONFIG_F, "w") { |f|
    f.write YAML.dump(config)
  }
  edit = (ENV["EDITOR"] || ENV["EDIT"] || "vi") + " '#{CONFIG_F}'"
  system edit or puts "edit '#{CONFIG_F}'"
end

def uri

def uri
  uri = @userconfig['uri']
  abort "Using new REST api, but uri isn't api.rubyforge.org.
n `rubyforge setup` and fix please" if
    uri =~ /rubyforge.org/ and uri !~ /api.rubyforge.org/
  @uri ||= URI.parse uri
end