#!/usr/bin/env ruby
# encoding: utf-8

# ruby1.8 doesn't provide Encoding, so make sure it's defined
if defined? Encoding
  output_encoding = Encoding.default_external
  Encoding.default_external = 'BINARY'
end

require 'yaml'

if ARGV[0].nil?
  $stderr.puts "Usage: #{File.basename $0} <file>"
  exit 1
end

if system "which pycodestyle >/dev/null 2>&1"
  tool = "pycodestyle"
elsif system "which pep8 >/dev/null 2>&1"
  tool = "pep8"
end

if not tool
  $stderr.puts "Error: Neither pycodestyle nor pep8 tool exists (install pycodestyle package)."
  exit 1
end

file = ARGV[0]

if not File.exist? file
  $stderr.puts "Error: file #{file} could not be read."
  exit 1
end

# Make sure we're looking at Python code.
mimetype = `file -Pbytes=32 -b -i #{file}`.gsub(/\n/,"")
if not /.*x-python/i.match(mimetype) and not /.*x-script\.python/i.match(mimetype)
  $stderr.puts "File #{file} doesn't look like Python [#{mimetype}]. Ignoring."
  exit 0
end


ISSUE_PREFIX = 'ISSUE:'

output = %x{#{tool} -r --show-source --format 'ISSUE:%(path)s:%(row)d:%(col)d: %(code)s %(text)s' #{file} 2>&1}

def is_issue_line(l)
  l.start_with?(ISSUE_PREFIX)
end

class Issue
  def initialize(firstline, file)
    @firstline = firstline.sub(ISSUE_PREFIX, '')
    @file = file
    @source = []
    @code = @firstline.split(': ', 3)[1]
    @severity = case @code[0]
      when 'E'
        'error'
      when 'W'
        'warning'
      end
  end

  def add_source(line)
    @source << line
  end

  def format(counter)
    body = YAML.dump({
      'message' => @firstline,
      'severity' => @severity,
      'code' => @code,
      'source' => @source.join("\n"),
      'file' => @file
    }) + '...'  # end of yaml
    return ("not ok #{counter} #{@firstline}\n  " + body.gsub("\n","\n  "))
  end
end

issues = []

output.each_line do |l|
  if defined? Encoding
    l = l.rstrip().encode(output_encoding, **{:invalid => :replace, :undef => :replace})
  else
    l = l.rstrip()
  end
  if is_issue_line(l)
    issues << Issue.new(l, file)
  else
    issues.last.add_source(l) unless issues.last.nil?
  end
end
exit 0 if issues.length == 0

# output result in TAP format
puts "TAP version 13"
puts "1..#{issues.length}"
issues.each_index do |idx|
  puts issues[idx].format(idx+1)
end
