#!/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'
require 'fileutils'
require 'time'

HOME=ENV['HOME']
HELPITEMS_URL = 'http://udd.debian.org/how-can-i-help.json.gz'
CACHEDIR = "#{HOME}/.cache/how-can-i-help"
CONFIGDIR = "#{HOME}/.config/how-can-i-help"
SEEN_LOCAL = "#{CACHEDIR}/seen.json"
CACHE = "#{CACHEDIR}/how-can-i-help.json.gz"
PACKAGES = "#{CONFIGDIR}/packages"

include Debian

$quiet = false
$all = false
$proxy_url = ENV["HTTP_PROXY"] || ENV["http_proxy"]

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!

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

FileUtils.mkdir_p CACHEDIR unless File.exists?(CACHEDIR)

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

# Cache request data
uri = URI(HELPITEMS_URL)
request = Net::HTTP::Get.new(uri.request_uri)
if File::exists?(CACHE)
  stat = File.stat CACHE
  request['If-Modified-Since'] = stat.mtime.httpdate
end

# Dealing with proxy, authenticated or not
proxy_uri = $proxy_url.nil? ? OpenStruct.new : URI.parse($proxy_url)
proxy_user, proxy_pass = proxy_uri.userinfo.split(/:/) if proxy_uri.userinfo
http_object = Net::HTTP.new(uri.host, uri.port, proxy_uri.host, proxy_uri.port,
                     proxy_user, proxy_pass)
# proceeding get_response

begin
  response = http_object.request(request)
rescue
  puts "Error downloading data file: #{$!}"
  exit(0)
end
open CACHE, 'w' do |cc|
  cc.write response.body.to_s
end if response.is_a?(Net::HTTPSuccess)

gz = Zlib::GzipReader.open(CACHE)
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

# add user defined packages
if File.file?(PACKAGES)
  additionals = File.read(PACKAGES).gsub(/\s+/m, ' ').strip.split(" ")
  packages += additionals
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
  elsif hi['type'] == 'no-testing'
    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' }
notesting = helpitems_filtered.select { |e| e['type'] == 'no-testing' }
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 notesting.length > 0
  puts $all ? 'Packages removed from Debian \'testing\' (the maintainer might need help):' : 'New packages removed from Debian \'testing\' (the maintainer might need help):'
  notesting.each do |r|
    puts " - #{r['package']} - http://packages.qa.debian.org/#{r['source']}"
  end
end

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

if 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
