#!/usr/bin/env ruby
# frozen_string_literal: true

require "optparse"
require "open-uri"
require "uri"
require "rubygems"
require "nokogiri"
autoload :IRB, "irb"

parse_class = Nokogiri
encoding = nil

# This module provides some tunables with the nokogiri CLI for use in
# your ~/.nokogirirc.
module Nokogiri
  module CLI
    class << self
      # Specify the console engine, defaulted to IRB.
      #
      # call-seq:
      #   require 'pry'
      #   Nokogiri::CLI.console = Pry
      attr_writer :console

      def console
        case @console
        when Symbol
          Kernel.const_get(@console)
        else
          @console
        end
      end

      attr_accessor :rcfile
    end

    self.rcfile  = File.expand_path("~/.nokogirirc")
    self.console = :IRB
  end
end

def safe_read(uri_or_path)
  uri = URI.parse(uri_or_path)
  case uri
  when URI::HTTP
    uri.read
  when URI::File
    File.read(uri.path)
  else
    File.read(uri_or_path)
  end
end

opts = OptionParser.new do |opts|
  opts.banner = "Nokogiri: an HTML, XML, SAX, and Reader parser"
  opts.define_head("Usage: nokogiri <uri|path> [options]")
  opts.separator("")
  opts.separator("Examples:")
  opts.separator("  nokogiri https://www.ruby-lang.org/")
  opts.separator("  nokogiri ./public/index.html")
  opts.separator("  curl -s http://www.nokogiri.org | nokogiri -e'p $_.css(\"h1\").length'")
  opts.separator("")
  opts.separator("Options:")

  opts.on("--type type", "Parse as type: xml or html (default: auto)", [:xml, :html]) do |v|
    parse_class = { xml: Nokogiri::XML, html: Nokogiri::HTML }[v]
  end

  opts.on("-C file", "Specifies initialization file to load (default #{Nokogiri::CLI.rcfile})") do |v|
    Nokogiri::CLI.rcfile = v
  end

  opts.on("-E", "--encoding encoding", "Read as encoding (default: #{encoding || "none"})") do |v|
    encoding = v
  end

  opts.on("-e command", "Specifies script from command-line.") do |v|
    @script = v
  end

  opts.on("--rng <uri|path>", "Validate using this rng file.") do |v|
    @rng = Nokogiri::XML::RelaxNG(safe_read(v))
  end

  opts.on_tail("-?", "--help", "Show this message") do
    puts opts
    exit
  end

  opts.on_tail("-v", "--version", "Show version") do
    puts Nokogiri::VersionInfo.instance.to_markdown
    exit
  end
end
opts.parse!

url = ARGV.shift

if url.to_s.strip.empty? && $stdin.tty?
  puts opts
  exit 1
end

if File.file?(Nokogiri::CLI.rcfile)
  load Nokogiri::CLI.rcfile
end

@doc = if url || $stdin.tty?
  parse_class.parse(safe_read(url), url, encoding)
else
  parse_class.parse($stdin, nil, encoding)
end

$_ = @doc

if @rng
  @rng.validate(@doc).each do |error|
    puts error.message
  end
elsif @script
  begin
    eval(@script, binding, "<main>") # rubocop:disable Security/Eval
  rescue Exception => e # rubocop:disable Lint/RescueException
    warn("ERROR: Exception raised while evaluating '#{@script}'")
    raise e
  end
else
  puts "Your document is stored in @doc..."
  Nokogiri::CLI.console.start
end
