#!/usr/bin/ruby
# encoding: utf-8
#
# Copyright © 2013, Lucas Nussbaum <lucas@debian.org>
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# 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.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

require 'pp'
require 'debian'
require 'net/http'
require 'zlib'
require 'stringio'
require 'json'
require 'optparse'

HELPITEMS_URL = 'http://udd.debian.org/how-can-i-help.json.gz'
DATADIR = '/var/lib/how-can-i-help'
SEEN_LOCAL = "#{DATADIR}/seen.json"

include Debian

$quiet = false
$all = false
$root = (Process.euid == 0)

optparse = OptionParser.new do |opts|
  opts.on('-h', '--help', 'show help') do
    puts opts
    exit
  end

  opts.on('-a', '--all', 'show all opportunities for contribution') do
    $all = true
  end

  opts.on('-q', '--quiet', 'do not display header and footer') do
    $quiet = true
  end

end
optparse.parse!

if not $root
  puts "Not running as root, implies --all (lists all opportunities)..."
  $all = true
end

def system_r(s)
  system(s) or raise
end

if $root and File::exists?(SEEN_LOCAL)
  seen = JSON::parse(IO::read(SEEN_LOCAL))
else
  seen = []
end

# FIXME deal with caching locally
uri = URI.parse(HELPITEMS_URL)
begin
  response = Net::HTTP.get_response(uri)
  # parse file into json
  if response.code.to_i != 200
    puts "Error downloading data file: #{response.code}"
    exit(0)
  end
rescue
  puts "Error downloading data file: #{$!}"
  exit(0)
end

gz = Zlib::GzipReader.new(StringIO.new(response.body.to_s))
helpitems = JSON::parse(gz.read)

# get installed packages
packages = []
str = `dpkg -l`
if str.respond_to?(:force_encoding)
  str.force_encoding('utf-8')
end
str.split(/\n/).each do |l|
  if l =~ /^(i|h).\s+([^ ]+)\s/
    packages << $2
  end
end

helpitems_filtered = []
helpitems.each do |hi|
  next if (not $all) and seen.include?(hi['hash'])
  if hi['type'] == 'wnpp'
    if packages & hi['packages'] != []
      helpitems_filtered << hi
    end
  elsif hi['type'] == 'gift'
    if packages.include?(hi['package'])
      helpitems_filtered << hi
    end
  end
end

unless $quiet
  puts "======  How can you help?  (doc: http://wiki.debian.org/how-can-i-help ) ======"
end

wnpp = helpitems_filtered.select { |e| e['type'] == 'wnpp' }
gift = helpitems_filtered.select { |e| e['type'] == 'gift' }
def wnpptype(t)
  return 'O (Orphaned)' if t == 'O'
  return 'RFA (Maintainer looking for adopter)' if t == 'RFA'
  return 'ITA (Someone working on adoption)' if t == 'ITA'
end

if wnpp.length > 0
  puts $all ? 'Orphaned packages:' : 'New orphaned packages:'
  wnpp.each do |r|
    puts " - #{r['source']} - http://bugs.debian.org/#{r['wnppbug']} - #{wnpptype(r['wnpptype'])}"
  end
end

if gift.length > 0
  puts $all ? 'Bugs suitable for new contributors (tagged \'gift\'):' : 'New bugs suitable for new contributors (tagged \'gift\'):'
  gift.each do |r|
    puts " - #{r['package']} - http://bugs.debian.org/#{r['bug']} - #{r['title']}"
  end
end

if not $all and not $quiet
  puts "------  Show all opportunities, not just new ones: how-can-i-help --all  ------"
end

if $root and not $all
  seen = helpitems.map { |hi| hi['hash'] } & seen
  seen = seen + helpitems_filtered.map { |hi| hi['hash'] }
  File::open(SEEN_LOCAL, 'w') do |fd|
    JSON::dump(seen, fd)
  end
end
