#!/usr/bin/env ruby
require 'optparse'
require 'socket'
require 'biodiversity'

DEFAULT_PORT = 4334
RUBY_VERSION_INT = RUBY_VERSION.split('.')[0..1].join('').to_i
OPTIONS = {
  output: 'json',
  canonical_with_rank: false, 
  port: DEFAULT_PORT
}

options = {}
ARGV.options do |opts|
  script_name = File.basename($0)
  opts.banner = "Usage: #{script_name} [options]"

  opts.separator ""

  opts.on('-r', 
          '--canonical_with_rank', 
          'Adds infraspecies rank to canonical forms'
          ) { |rank| options[:canonical_with_rank] = rank }

  opts.separator ''

  opts.on('-o', '--output=output', String,
          'Specifies the type of the output:
    json - parsed results in json
    canonical - canonical form only',
          'Default: json') { |output| options[:output] = output }

  opts.separator ''

  opts.on('-p', '--port=port', String,
          'Specifies the port number',
          "Default: #{DEFAULT_PORT}") { |port| options[:port] = port }

  opts.separator ''

  opts.on('-h', '--help',
          'Show this help message.') { puts opts; exit }

  opts.parse!
end

OPTIONS[:output] = options[:output] if ['canonical'].include?(options[:output])
OPTIONS[:port] = options[:port].to_i if options[:port].to_i > 0
OPTIONS[:canonical_with_rank] = !!options[:canonical_with_rank]

def get_output(name_string, parser)
  begin
    parsed = parser.parse(name_string)
  rescue
    parsed = ScientificNameParser::FAILED_RESULT.(name_string)
  end
  output =  OPTIONS[:output]
  return parsed.to_json if output == 'json'
  parsed[:scientificName][:canonical].to_s
end

puts "Running parser service on port %s, output type is '%s'" % 
     [OPTIONS[:port], OPTIONS[:output]]
opts = {}
opts = {canonical_with_rank: true} if OPTIONS[:canonical_with_rank]
parser = ScientificNameParser.new(opts)
server = TCPServer.open(OPTIONS[:port])  # Socket to listen on a port
loop do                         # Servers run forever
  Thread.start(server.accept) do |client|
    puts 'opening client'
    count = 0
    while a = client.readline rescue nil
      count += 1
      puts "parsed %s'th name" % count if count % 1000 == 0
      a.force_encoding('utf-8') if a && RUBY_VERSION_INT >= 19
      if ['end','exit','q', '.'].include? a.strip
        client.close
        break
      end
      out = get_output(a, parser).strip
      client.write(out + "\n") rescue break
    end
    puts 'closing client'
    client.close
  end
end