class KPM::PluginsManager

def add_plugin_identifier_key(plugin_key, plugin_name, language, coordinates)

def add_plugin_identifier_key(plugin_key, plugin_name, language, coordinates)
  identifiers = read_plugin_identifiers
  # If key does not already exists we update it, if not nothing to do
  if !identifiers.has_key?(plugin_key)
    entry = {'plugin_name' => plugin_name}
    entry['language'] = language
    if coordinates
      entry['group_id'] = coordinates[0]
      entry['artifact_id'] = coordinates[1]
      entry['packaging'] = coordinates[2]
      entry['classifier'] = coordinates[3]
      entry['version'] = coordinates[4]
    end
    identifiers[plugin_key] = entry
    write_plugin_identifiers(identifiers)
  end
  identifiers
end

def get_plugin_name_from_key(plugin_key)

def get_plugin_name_from_key(plugin_key)
  identifiers = read_plugin_identifiers
  return nil if identifiers.nil? || !identifiers.has_key?(plugin_key)
  identifiers[plugin_key]['plugin_name']
end

def guess_plugin_name(artifact_id)

def guess_plugin_name(artifact_id)
  return nil if artifact_id.nil?
  captures = artifact_id.scan(/(.*)-plugin/)
  if captures.empty? || captures.first.nil? || captures.first.first.nil?
    short_name = artifact_id
  else
    # 'analytics-plugin' or 'stripe-plugin' passed
    short_name = captures.first.first
  end
  Dir.glob(@plugins_dir.join('*').join('*')).each do |plugin_path|
    plugin_name = File.basename(plugin_path)
    if plugin_name == short_name ||
        plugin_name == artifact_id ||
        !plugin_name.scan(/-#{short_name}/).empty? ||
        !plugin_name.scan(/#{short_name}-/).empty?
      return plugin_name
    end
  end
  nil
end

def initialize(plugins_dir, logger)

def initialize(plugins_dir, logger)
  @plugins_dir = Pathname.new(plugins_dir)
  @logger = logger
end

def read_plugin_identifiers

def read_plugin_identifiers
  path = Pathname.new(@plugins_dir).join('plugin_identifiers.json')
  identifiers = {}
  begin
    identifiers = File.open(path, 'r') do |f|
      JSON.parse(f.read)
    end
  rescue Errno::ENOENT
  end
  identifiers
end

def remove_plugin_identifier_key(plugin_key)

def remove_plugin_identifier_key(plugin_key)
  identifiers = read_plugin_identifiers
  # If key does not already exists we update it, if not nothing to do.
  if identifiers.has_key?(plugin_key)
    identifiers.delete(plugin_key)
    write_plugin_identifiers(identifiers)
  end
  identifiers
end

def restart(plugin_name_or_path, plugin_version=nil)

def restart(plugin_name_or_path, plugin_version=nil)
  update_fs(plugin_name_or_path, plugin_version) do |tmp_dir|
    # Remove disabled.txt so that the plugin is started if it was stopped
    FileUtils.rm_f(tmp_dir.join('disabled.txt'))
    FileUtils.touch(tmp_dir.join('restart.txt'))
  end
end

def set_active(plugin_name_or_path, plugin_version=nil)

def set_active(plugin_name_or_path, plugin_version=nil)
  if plugin_name_or_path.nil?
    @logger.warn('Unable to mark a plugin as active: no name or path specified')
    return
  end
  if plugin_version.nil?
    # Full path specified, with version
    link = Pathname.new(plugin_name_or_path).join('../SET_DEFAULT')
    FileUtils.rm_f(link)
    FileUtils.ln_s(plugin_name_or_path, link, :force => true)
  else
    # Plugin name (fs directory) specified
    plugin_dir_glob = @plugins_dir.join('*').join(plugin_name_or_path)
    # Only one should match (java or ruby plugin)
    Dir.glob(plugin_dir_glob).each do |plugin_dir_path|
      plugin_dir = Pathname.new(plugin_dir_path)
      link = plugin_dir.join('SET_DEFAULT')
      FileUtils.rm_f(link)
      FileUtils.ln_s(plugin_dir.join(plugin_version), link, :force => true)
    end
  end
  update_fs(plugin_name_or_path, plugin_version) do |tmp_dir|
    FileUtils.rm_f(tmp_dir.join('disabled.txt'))
    FileUtils.rm_f(tmp_dir.join('restart.txt'))
  end
end

def uninstall(plugin_name_or_path, plugin_version=nil)

def uninstall(plugin_name_or_path, plugin_version=nil)
  update_fs(plugin_name_or_path, plugin_version) do |tmp_dir|
    FileUtils.rm_f(tmp_dir.join('restart.txt'))
    # Be safe, keep the code, just never start it
    FileUtils.touch(tmp_dir.join('disabled.txt'))
  end
end

def update_fs(plugin_name_or_path, plugin_version=nil, &block)

Note: the plugin name here is the directory name on the filesystem
def update_fs(plugin_name_or_path, plugin_version=nil, &block)
  if plugin_name_or_path.nil?
    @logger.warn('Unable to update the filesystem: no name or path specified')
    return
  end
  p = plugin_version.nil? ? plugin_name_or_path : @plugins_dir.join('*').join(plugin_name_or_path).join(plugin_version == :all ? '*' : plugin_version)
  modified = []
  Dir.glob(p).each do |plugin_dir_path|
    plugin_dir = Pathname.new(plugin_dir_path)
    tmp_dir = plugin_dir.join('tmp')
    FileUtils.mkdir_p(tmp_dir)
    yield(tmp_dir) if block_given?
    modified << plugin_dir
  end
  if modified.empty?
    if plugin_version.nil?
      @logger.warn("No plugin found with name #{plugin_name_or_path}. Installed plugins: #{Dir.glob(@plugins_dir.join('*').join('*'))}")
    else
      @logger.warn("No plugin found with name #{plugin_name_or_path} and version #{plugin_version}. Installed plugins: #{Dir.glob(@plugins_dir.join('*').join('*').join('*'))}")
    end
  end
  modified
end

def validate_plugin_identifier_key(plugin_key, coordinates)

def validate_plugin_identifier_key(plugin_key, coordinates)
  identifiers = read_plugin_identifiers
  entry = identifiers[plugin_key]
  if entry
    [:group_id, :artifact_id, :packaging, :classifier, :version].each_with_index do |value_type, idx|
      return false if !validate_plugin_identifier_key_value(plugin_key, value_type, entry[value_type.to_s], coordinates[idx])
    end
  end
  true
end

def validate_plugin_identifier_key_value(plugin_key, value_type, entry_value, coordinate_value)

def validate_plugin_identifier_key_value(plugin_key, value_type, entry_value, coordinate_value)
  # The json does not contain the coordinates (case when installed from install_plugin_from_fs)
  return true if entry_value.nil?
  if entry_value != coordinate_value
    @logger.warn("Entry in plugin_identifiers.json for key #{plugin_key} does not match for coordinate #{value_type}: got #{coordinate_value} instead of #{entry_value}")
    return false
  end
  true
end

def write_plugin_identifiers(identifiers)

def write_plugin_identifiers(identifiers)
  path = Pathname.new(@plugins_dir).join('plugin_identifiers.json')
  Dir.mktmpdir do |tmp_dir|
    tmp_path = Pathname.new(tmp_dir).join('plugin_identifiers.json')
    File.open(tmp_path, 'w') do |f|
      f.write(identifiers.to_json)
    end
    FileUtils.mv(tmp_path, path)
  end
end