require 'time'
require 'socket'
require 'optparse'
require 'thread'

loop_file = false
port = 7878
scenario = false
verbose = false
fast = false
server = '0.0.0.0'

OptionParser.new do |opts|
  opts.banner = 'Usage: run_scenrio.rb [-lfh] [-s server] [-p port] <file>'

  opts.on('-l', '--[no-]loop', 'Loop file') do  |v|
    loop_file = v
  end

  opts.on('-p', '--port [port]', OptionParser::DecimalNumeric, 'Port (default: 7878)') do  |v|
    port = v
  end

  opts.on('-h', '--help', 'Show help') do
    puts opts
    exit 1
  end

  opts.on('-t', '--[no-]scenario', 'Run scenario or log') do |v|
    scenario = v
  end
  
  opts.on('-v', '--[no-]verbose', 'Verbose output') do |v|
    verbose = v
  end
  
  opts.on('-f', '--[no-]fast', 'Pump as fast as possible') do |v|
    puts "FAST - Will deliver data at maximum speed!"
    fast = v
  end
  
  opts.on('-s', '--server [server]', OptionParser::String, 'Server IP port to bind to (default: 0.0.0.0)') do |v|
    server = v
  end
  
  opts.parse!
  if ARGV.length < 1
    puts "Missing log file <file>"
    puts opts
    exit 1
  end
end

def heartbeat(socket)
  Thread.new do
    while (select([socket], nil, nil))
      begin
        if (r = socket.read_nonblock(256)) =~ /\* PING/
          puts "Received #{r.strip}, responding with pong" #if verbose
          mutex.synchronize {
            socket.puts "* PONG 10000"
          }
        else
          puts "Received '#{r.strip}'"
        end
      rescue
      end
    end
  end
end

server = TCPServer.new(server, port)
sockets = []
mutex = Mutex.new

Thread.new do
  while true
    puts "Waiting on #{server} #{port}"
    s = server.accept
    mutex.synchronize {
      sockets << s
    }
    heartbeat(s)
    puts "Client connected"
  end
end


def format_time
  time = Time.now.utc
  time.strftime("%Y-%m-%dT%H:%M:%S.") + ("%06d" % time.usec)
end

puts "Waiting for first connection"
while sockets.empty?
  sleep 1
end
sleep 1

begin
  File.open(ARGV[0]) do |file|
    last = nil
    file.each do |l|
      if scenario or l =~ /^\d{4,4}-\d{2,2}-\d{2,2}.+\|/o
        f, r = l.chomp.split('|', 2)
      
        if fast
          sleep 0.0001
        elsif scenario
          if f == nil
            f = 1
          end
        else
          time = Time.parse(f)
      
          if last
            delta = time - last
            sleep delta if delta > 0.0
          end
        end
        line = "#{format_time}|#{r}"
      else
        line = l
      end
      
      mutex.synchronize {
        sockets.each do |socket|
          begin
            puts  line if verbose        
            socket.puts line
            socket.flush
          rescue
            puts $!
            sockets.delete socket
          end
        end
      }
      last = time
      sleep(f.to_f) if scenario
    end
  end
end while (loop_file)
