#!/usr/bin/env ruby -KU
require 'uri'
require 'net/http'
require 'open3'

# try to get this from gemspec.
KDRFC_VERSION=Gem.loaded_specs["kramdown-rfc2629"].version rescue "unknown-version"

def v3_flag?
  $options.v3 ? ["--v3"] : []
end

def process_mkd(input, output)
  warn "* converting locally from markdown #{input} to xml #{output}" if $options.verbose
  o, s = Open3.capture2("kramdown-rfc2629", *v3_flag?, input)
  if s.success?
    File.open(output, "w") do |fo|
      fo.print(o)
    end
    warn "* #{output} written" if $options.verbose
  else
    warn "*** kramdown-rfc failed, status #{s.exitstatus}"
    exit 1
  end
end

def process_xml(*args)
  if $options.remote
    process_xml_remotely(*args)
  else
    process_xml_locally(*args)
  end
end

def process_xml_locally(input, output, *flags)
  warn "* converting locally from xml #{input} to txt #{output}" if $options.verbose
  begin
    o, s = Open3.capture2("xml2rfc", *v3_flag?, *flags, input)
    puts o
    if s.success?
      warn "* #{output} written" if $options.verbose
    else
      warn "*** xml2rfc failed, status #{s.exitstatus} (possibly try with -r)"
      exit 1
    end
  rescue Errno::ENOENT
    warn "*** falling back to remote processing" if $options.verbose
    process_xml_remotely(input, output)
  end
end

def process_xml_remotely(input, output)
  warn "* converting remotely from xml #{input} to txt #{output}" if $options.verbose
  url = URI('http://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc.cgi')
  req = Net::HTTP::Post.new(url)
  req.set_form([["modeAsFormat", "txt/#{"v3" if $options.v3}ascii"],
                ["type", "binary"],
                ["input", File.open(input),
                 {filename: "input.xml",
                  content_type: "text/plain"}]],
               'multipart/form-data')
  res = Net::HTTP::start(url.hostname, url.port,
                         :use_ssl => url.scheme == 'https' ) {|http|
    http.request(req)
  }
  case res
  when Net::HTTPOK
    case res.content_type
    when 'application/octet-stream'
      File.open(output, "w") do |fo|
        fo.print(res.body)
      end
      warn "* #{output} written" if $options.verbose
    else
      warn "*** HTTP response has unexpected content_type #{res.content_type} with status #{res.code}"
      warn res.body
      exit 1
    end
  else
    warn "*** HTTP response: #{res.code}"
    exit 1
  end
end

require 'optparse'
require 'ostruct'

$options = OpenStruct.new
$options.txt = true             # default
op = OptionParser.new do |opts|
  opts.banner = <<BANNER
Usage: kdrfc [options] file.md|file.mkd|file.xml
Version: #{KDRFC_VERSION}
BANNER
  opts.on("-V", "--version", "Show version and exit") do |v|
    puts "kdrfc, from kramdown-rfc2629 #{KDRFC_VERSION}"
    exit
  end
  opts.on("-H", "--help", "Show option summary and exit") do |v|
    puts opts
    exit
  end
  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
    $options.verbose = v
  end
  opts.on("-r", "--[no-]remote", "Run xml2rfc remotely even if there is a local one") do |v|
    $options.remote = v
  end
  opts.on("-x", "--[no-]xml", "Convert to xml only") do |v|
    $options.xml_only = v
  end
  opts.on("-p", "--[no-]prep", "Convert xml to prepped xml") do |v|
    $options.prep = v
  end
  opts.on("-h", "--[no-]html", "Convert to html as well") do |v|
    $options.html = v
  end
  opts.on("-t", "--[no-]txt", "Convert to txt as well") do |v|
    $options.txt = v
  end
  opts.on("-3", "--[no-]v3", "Use RFCXML v3 processing rules") do |v|
    $options.v3 = v
  end
end
op.parse!

def process_the_xml(fn, base)
  process_xml(fn, "#{base}.prepped.xml", "--preptool") if $options.prep
  process_xml(fn, "#{base}.txt") if $options.txt
  process_xml(fn, "#{base}.html", "--html") if $options.html
end

case ARGV.size
when 1
  fn = ARGV[0]
  case fn
  when /(.*)\.xml\z/
    if $options.xml_only
      warn "*** You already have XML"
    else                        # FIXME: copy/paste
      process_the_xml(fn, $1)
    end
  when /(.*)\.mk?d\z/
    xml = "#$1.xml"
    process_mkd(fn, xml)
    process_the_xml(xml, $1) unless $options.xml_only
  else
    warn "Unknown file type: #{fn}"
    exit 1
  end
else
  puts op
  exit 1
end
