#!/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 run_idnits(txt_fn)
  unless system("idnits", txt_fn)
    warn "*** problem #$? running idnits"
  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

XML2RFC_WEBSERVICE = ENV["KRAMDOWN_XML2RFC_WEBSERVICE"] ||
                     'http://xml2rfc.tools.ietf.org/cgi-bin/xml2rfc-dev.cgi'


def process_xml_remotely(input, output)
  warn "* converting remotely from xml #{input} to txt #{output}" if $options.verbose
  url = URI(XML2RFC_WEBSERVICE)
  req = Net::HTTP::Post.new(url)
  form = [["modeAsFormat", "txt/#{"v3" if $options.v3}ascii"],
          ["type", "binary"],
          ["input", File.open(input),
           {filename: "input.xml",
            content_type: "text/plain"}]]
  diag = ["url/form: ", url, form].inspect
  req.set_form(form, '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'
      if res.body == ''
        warn "*** HTTP response is empty with status #{res.code}, not written"
        exit 1
      end
      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}, #{diag}"
      warn res.body
      exit 1
    end
  else
    warn "*** HTTP response: #{res.code}, #{diag}"
    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("-c", "--[no-]convert", "Convert xml to v3 xml") do |v|
    $options.v2v3 = v
  end
  opts.on("-i", "--[no-]idnits", "Run idnits on the resulting text") do |v|
    $options.idnits = 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}.v2v3.xml", "--v2v3") if $options.v2v3
  process_xml(fn, "#{base}.txt") if $options.txt || $options.idnits
  process_xml(fn, "#{base}.html", "--html") if $options.html
  run_idnits("#{base}.txt") if $options.idnits
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
