require "fileutils"

namespace :protobuf do

  desc "Clean & Compile the protobuf source to ruby classes. Pass PB_NO_CLEAN=1 if you do not want to force-clean first."
  task :compile, [:package, :source, :destination, :plugin, :file_extension] do |_tasks, args|
    binpath = ::File.expand_path("../../../../bin", __FILE__)

    args.with_defaults(:destination => "lib")
    args.with_defaults(:source => "definitions")
    args.with_defaults(:plugin => "protoc-gen-ruby-protobuf=#{binpath}/protoc-gen-ruby")
    args.with_defaults(:file_extension => ".pb.rb")

    # The local Ruby generator collides with the builtin Ruby generator
    #
    # From the protoc docs:
    #
    #   --plugin=EXECUTABLE
    #
    #   ...EXECUTABLE may be of the form NAME=PATH, in which case the given plugin name
    #   is mapped to the given executable even if the executable"s own name differs.
    #
    # Use the NAME=PATH form to specify an alternative plugin name that avoids the name collision
    #
    plugin_name, _plugin_path = args[:plugin].split("=")

    # The plugin name MUST have the protoc-gen- prefix in order to work, but that prefix is dropped
    # when using the plugin to generate definitions
    plugin_name.gsub!("protoc-gen-", "")

    unless do_not_clean?
      force_clean!
      ::Rake::Task[:clean].invoke(args[:package], args[:destination], args[:file_extension])
    end

    command = []
    command << "protoc"
    command << "--plugin=#{args[:plugin]}"
    command << "--#{plugin_name}_out=#{args[:destination]}"
    command << "-I #{args[:source]}"
    command << Dir["#{args[:source]}/#{args[:package]}/**/*.proto"].join(" ")
    full_command = command.join(" ")

    puts full_command
    system(full_command)
  end

  desc "Clean the generated *.pb.rb files from the destination package. Pass PB_FORCE_CLEAN=1 to skip confirmation step."
  task :clean, [:package, :destination, :file_extension] do |_task, args|
    args.with_defaults(:destination => "lib")
    args.with_defaults(:file_extension => ".pb.rb")

    file_extension = args[:file_extension].sub(/\*?\.+/, "")
    files_to_clean = ::File.join(args[:destination], args[:package], "**", "*.#{file_extension}")

    if force_clean? || permission_to_clean?(files_to_clean)
      ::Dir.glob(files_to_clean).each do |file|
        ::FileUtils.rm(file)
      end
    end
  end

  def do_not_clean?
    ! ::ENV.key?("PB_NO_CLEAN")
  end

  def force_clean?
    ::ENV.key?("PB_FORCE_CLEAN")
  end

  def force_clean!
    ::ENV["PB_FORCE_CLEAN"] = "1"
  end

  def permission_to_clean?(files_to_clean)
    puts "Do you really want to remove files matching pattern #{files_to_clean}? (y/n)"
    ::STDIN.gets.chomp =~ /y(es)?/i
  end

end