#!/usr/bin/env ruby

$: << '.'
$: << '..'
$: << '../lib'
$: << '../ext'

if __FILE__ == $0
  if (i = ARGV.index('-I'))
    x = ARGV.slice!(i, 2)
    $: << x[1]
  end
end

require 'optparse'
require 'ox'
require 'sample'
require 'test/ox/doc'
require 'files'
require 'perf'
begin
  require 'nokogiri'
rescue Exception => e
end
begin
  require 'libxml'
rescue Exception => e
end

$verbose = 0
$ox_only = false

do_sample = false
do_files = false
do_load = false
do_dump = false
do_read = false
do_write = false
$iter = 1000

opts = OptionParser.new
opts.on("-v", "increase verbosity")                         { $verbose += 1 }

opts.on("-x", "ox only")                                    { $ox_only = true }

opts.on("-s", "load and dump as sample Ruby object")        { do_sample = true }
opts.on("-f", "load and dump as files Ruby object")         { do_files = true }

opts.on("-l", "load")                                       { do_load = true }
opts.on("-d", "dump")                                       { do_dump = true }
opts.on("-r", "read")                                       { do_read = true }
opts.on("-w", "write")                                      { do_write = true }
opts.on("-a", "load, dump, read and write")                 { do_load = true; do_dump = true; do_read = true; do_write = true }

opts.on("-i", "--iterations [Int]", Integer, "iterations")  { |it| $iter = it }

opts.on("-h", "--help", "Show this display")                { puts opts; Process.exit!(0) }
files = opts.parse(ARGV)

Ox.default_options = {mode: :generic}

data = []

if files.empty?
  data = []
  obj = do_sample ? sample_doc(2) : files('..')
  xml = Ox.dump(obj, :indent => 2, :opt_format => true)
  File.open('sample.xml', 'w') { |f| f.write(xml) }
  gen = Ox.parse(xml)
  h = { :file => 'sample.xml', :xml => xml, :ox => gen }
  h[:nokogiri] = Nokogiri::XML::Document.parse(xml) unless defined?(::Nokogiri).nil?
  h[:libxml] = LibXML::XML::Document.string(xml) unless defined?(::LibXML).nil?
  data << h
else
  puts "loading and parsing #{files}\n\n"
  data = files.map do |f|
    xml = File.read(f)
    obj = Ox.parse(xml)
    gen = Ox.parse(xml)
    h = { :file => f, :xml => xml, :ox => gen }
    h[:nokogiri] = Nokogiri::XML::Document.parse(xml) unless defined?(::Nokogiri).nil?
    h[:libxml] = LibXML::XML::Document.string(xml) unless defined?(::LibXML).nil?
    h
  end
end

data.each do |d|
  if do_load
    perf = Perf.new()
    perf.add('Ox', 'parse') { Ox.parse(xml) }
    perf.add('Nokogiri', 'parse') { Nokogiri::XML::Document.parse(xml) } unless defined?(::Nokogiri).nil?
    perf.add('LibXML', 'parse') { LibXML::XML::Document.string(xml) } unless defined?(::LibXML).nil?
    perf.run($iter)
  end

  if do_dump
    perf = Perf.new()
    perf.add('Ox', 'dump') { Ox.dump($obj, :indent => 2) }
    perf.before('Ox') { $obj = d[:ox] }
    unless defined?(::Nokogiri).nil?
      perf.add('Nokogiri', 'dump') { $obj.to_xml(:indent => 2) }
      perf.before('Nokogiri') { $obj = d[:nokogiri] }
    end
    unless defined?(::LibXML).nil?
      perf.add('LibXML', 'dump') { $obj.to_s() }
      perf.before('LibXML') { $obj = d[:libxml] }
    end
    perf.run($iter)
  end

  if do_read
    $filename = d[:file]
    perf = Perf.new()
    perf.add('Ox', 'load_file') { Ox.load_file($filename) }
    perf.add('Nokogiri', 'parse') { Nokogiri::XML::Document.parse(File.open($filename)) } unless defined?(::Nokogiri).nil?
    perf.add('LibXML', 'parse') { LibXML::XML::Document.file($filename) } unless defined?(::LibXML).nil?
    perf.run($iter)
  end

  if do_write
    $filename = 'out.xml'
    perf = Perf.new()
    perf.add('Ox', 'to_file') { Ox.to_file($filename, $obj, :indent => 0) }
    perf.before('Ox') { $obj = d[:ox] }
    unless defined?(::Nokogiri).nil?
      perf.add('Nokogiri', 'dump') {
        xml = $obj.to_xml(:indent => 0)
        File.open($filename, "w") { |f| f.write(xml) }
      }
    end
    perf.before('Nokogiri') { $obj = d[:nokogiri] }
    unless defined?(::LibXML).nil?
      perf.add('LibXML', 'dump') {
        xml = $obj.to_s()
        File.open($filename, "w") { |f| f.write(xml) }
      }
      perf.before('LibXML') { $obj = d[:libxml] }
    end
    perf.run($iter)
  end

end
