/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 2 -*-
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 * SPDX-FileCopyrightText: Michael Terry
 */

// This file holds some abstractions around loading which ToolPlugin to use.
// (i.e. whether to use Restic or Duplicity)

using GLib;

namespace DejaDup {

ToolPlugin borg_tool = null;
ToolPlugin make_borg_tool()
{
  if (borg_tool == null)
    borg_tool = new BorgPlugin();
  return borg_tool;
}

ToolPlugin restic_tool = null;
internal ToolPlugin make_restic_tool()
{
  if (restic_tool == null)
    restic_tool = new ResticPlugin();
  return restic_tool;
}

ToolPlugin duplicity_tool = null;
ToolPlugin make_duplicity_tool()
{
  if (duplicity_tool == null)
    duplicity_tool = new DuplicityPlugin();
  return duplicity_tool;
}

ToolPlugin make_tool(string tool_name)
{
  switch(tool_name)
  {
    case "borg":
      return make_borg_tool();
    case "duplicity":
      return make_duplicity_tool();
    case "auto":
      return make_restic_tool();
    default:
      return make_restic_tool();
  }
}

public ToolPlugin get_default_tool()
{
  var settings = get_settings();
  var tool_name = settings.get_string(TOOL_WHEN_NEW_KEY);
  return make_tool(tool_name);
}

// Backend must already have prepare() called. This will inspect the files
// in the backend location to see which tool is being used there.
public async ToolPlugin? get_tool_for_backend(Backend backend) throws OptionError
{
  var filenames = yield backend.peek_at_files();
  filenames.sort(strcmp);

  // If the folder is empty, no tool present
  if (filenames == null)
    return null;

  // The basic approach is: look for files we recognize, and try to ignore
  // some files we don't notice. (Hidden files are already ignored.)
  // This covers some edge cases of random files being thrown in there, but
  // will still complain about widespread dual-uses of the folder, which we
  // largely want to allow to be completely owned by the underlying tool.
  // Note that the peek_at_files() call above only guarantees that we'll see 20
  // of the files, so if there *is* widespread dual-use of the folder, we may
  // only see a partial view.

  var unknown_filename = filenames.data;

  // Restic repos have these entries:
  //   config data/ index/ keys/ snapshots/ (and sometimes locks/)
  // Let's check for those, but allow other files, to try to be a little
  // future proof in case Restic expands its file format on us.
  string[] restic_expected = {"config", "data", "index", "keys", "snapshots"};
  int restic_found = 0;
  foreach (var filename in filenames) {
    var found = false;
    for (int i = 0; i < restic_expected.length; i++) {
      if (filename == restic_expected[i]) {
        found = true;
        break;
      }
    }
    if (found)
      restic_found++;
    else
      unknown_filename = filename;
  }
  if (restic_found == restic_expected.length)
    return make_tool("restic");

  // Check for borg too
  string[] borg_expected = {"config", "data", "nonce", "README"};
  int borg_found = 0;
  foreach (var filename in filenames) {
    for (int i = 0; i < borg_expected.length; i++) {
      if (filename == borg_expected[i]) {
        borg_found++;
        break;
      }
    }
  }
  if (borg_found == borg_expected.length)
    return make_tool("borg");

  // All duplicity files have the same basic prefix. (We also must allow for a
  // legacy "restic" folder. While we're at it, allow other random files too.)
  foreach (var filename in filenames) {
    if (filename.has_prefix("duplicity-"))
      return make_tool("duplicity");
  }

  // Error case (unrecognized files)
  var msg = _("Unrecognized file in storage location: '%s'. Choose an empty folder instead.").printf(unknown_filename);
  throw new OptionError.FAILED(msg);
}

}
