#!/usr/bin/ruby
require 'digest'
require 'oj'
require 'optparse'
require 'opal/paths'
require 'opal/source_map'
require 'opal/compiler'
require 'opal-webpack-loader/load_path_manager'
require 'opal-webpack-loader/compile_worker'
require 'opal-webpack-loader/compile_server'

modules_to_require = []
compiler_options = {}
compile_server_options = {}

OptionParser.new do |opts|
  opts.on('-r', '--require MODULE', 'Require the module before starting the compile server.') do |m|
    modules_to_require << m
  end

  opts.on('-I', '--include DIR', 'Append a load path (may be used more than once)') do |i|
    $:.unshift(File.expand_path(i))
  end

  opts.on('-d', '--dynamic-require-severity SEVERITY', 'Compiler option, one of: error, warning, ignore.') do |s|
    if %w[error warning ignore].include?(s)
      compiler_options[:dynamic_require_severity] = s.to_sym
    end
  end

  opts.on('-t', '--true FLAG', 'Set compiler flag to true.' ) do |f|
    compiler_options[f.to_sym] = true
  end

  opts.on('-f', '--false FLAG', 'Set compiler flag to false.' ) do |f|
    compiler_options[f.to_sym] = false
  end

  opts.on('-l', '--load-paths-cache PATH', 'Path to load path cache json') do |l|
    compile_server_options[:load_paths_cache] = l
  end

  opts.on('-s', '--socket-path PATH', 'Path of the socket the compile server should create.') do |s|
    compile_server_options[:socket_path] = s
  end

  opts.on('-m', '--memcached URL', 'URL of memcached server. Will enable use of memcached for caching compiler results.') do |m|
    compile_server_options[:memcached] = m
    require 'dalli'
  end

  opts.on('-e', '--redis URL', 'URL of redis server. Will enable use of redis for caching compiler results.') do |e|
    compile_server_options[:redis] = e
    require 'redis'
  end
end.parse!

modules_to_require.each do |mod|
  require mod
end

at_exit do
  if OpalWebpackLoader::CompileServer.unlink_socket?
    if File.exist?(compile_server_options[:socket_path])
      File.unlink(compile_server_options[:socket_path])
    end
  end
end

if ARGV[0] == 'stop' || ARGV[0] == 'kill'
  OpalWebpackLoader::CompileServer.stop(compile_server_options[:socket_path])
else
  if ARGV[0] == 'start'
    OpalWebpackLoader::CompileServer.stop(compile_server_options[:socket_path],false)
    number_of_workers = ARGV[1].to_i
    number_of_workers == 4 if number_of_workers == 0
    number_of_workers == 16 if number_of_workers > 16
  else
    raise 'arguments must be either "stop" or "start number_of_workers"'
    exit(1)
  end

  load_paths = OpalWebpackLoader::LoadPathManager.read_load_paths_cache(compile_server_options[:load_paths_cache])
  if load_paths
    Opal.append_paths(*load_paths)
  end

  pid = fork { OpalWebpackLoader::CompileServer.new(compile_server_options).start(number_of_workers, compiler_options) }

  have_socket = false
  start_time = Time.now
  begin
    until have_socket
      if File.exist?(compile_server_options[:socket_path])
        have_socket = true
      else
        if Time.now - start_time > 60
          STDERR.puts "opal-webpack-compile-server didnt start in time. Exiting"
          OpalWebpackLoader::CompileServer.stop(false)
          Process.kill("TERM", pid)
          exit 1
        end
      end
    end
  rescue Exception => e
    OpalWebpackLoader::CompileServer.stop(false)
    STDERR.puts "opal-webpack-compile-server couldn't start:"
    STDERR.puts e.backtrace.join("\n")
    STDERR.puts e.message
    Process.kill("TERM", pid)
    exit 1
  end

  begin
    Process.waitpid(pid)
  rescue Interrupt
    STDERR.puts "opal-webpack-compile-server got interrupted. Exiting with drama."
    Process.kill("TERM", pid)
    exit 0
  end
  Process.kill("TERM", pid)
end
