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

using GLib;

public class DuplicityPlugin : DejaDup.ToolPlugin
{
  bool has_been_setup = false;
  string version = null;

  construct
  {
    name = "duplicity";
  }

  public override bool needs_dependencies() {
    return Environment.find_program_in_path(duplicity_command()) == null;
  }

  public override string[] get_dependencies()
  {
    return Config.DUPLICITY_PACKAGES.split(",");
  }

  const int REQUIRED_MAJOR = 2;
  const int REQUIRED_MINOR = 1;
  const int REQUIRED_MICRO = 0;
  void do_initial_setup () throws Error
  {
    if (has_been_setup)
      return;

    this.version = this.find_and_parse_version();

    int major, minor, micro;
    if (!DejaDup.parse_version(version, out major, out minor, out micro))
      throw new SpawnError.FAILED(_("Could not understand duplicity version ‘%s’.").printf(version));

    if (!DejaDup.meets_version(major, minor, micro, REQUIRED_MAJOR, REQUIRED_MINOR, REQUIRED_MICRO)) {
      var msg = _("Backups requires at least version %d.%d.%.2d of duplicity, " +
                  "but only found version %d.%d.%.2d");
      throw new SpawnError.FAILED(msg.printf(REQUIRED_MAJOR, REQUIRED_MINOR, REQUIRED_MICRO, major, minor, micro));
    }

    has_been_setup = true;
  }

  string find_and_parse_version() throws SpawnError
  {
    string stderr, stdout;
    Process.spawn_sync(null, {duplicity_command(), "--version"}, null,
                       SpawnFlags.SEARCH_PATH, null, out stdout, out stderr);

    // In older versions (circa 0.6.25), there might be a deprecation warning
    // printed above the version.
    //
    // In later versions (2.2+) the output includes a build date after the
    // version (e.g. "duplicity 2.2.2 February 03, 2024").
    //
    // So to try to handle that kind of variety, we take the last line that
    // starts with "duplicity " and take the second token.

    var lines = stdout.split("\n");
    for (int i = lines.length - 1; i >= 0; i--) {
      var tokens = lines[i].split(" ");
      if (tokens.length >= 2 && tokens[0] == "duplicity") {
        return tokens[1].strip();
      }
    }

    warning("%s\n%s", stderr, stdout);
    throw new SpawnError.FAILED(_("Could not understand duplicity version."));
  }

  public override string get_version() throws Error
  {
    do_initial_setup();
    return this.version;
  }

  public override DejaDup.ToolJob create_job() throws Error
  {
    do_initial_setup();
    return new DuplicityJob();
  }

  public override bool supports_backend(DejaDup.Backend.Kind kind, out string explanation)
  {
    explanation = null;

    switch(kind) {
      case DejaDup.Backend.Kind.LOCAL:
      case DejaDup.Backend.Kind.GVFS:
      case DejaDup.Backend.Kind.GOOGLE:
      case DejaDup.Backend.Kind.MICROSOFT:
      case DejaDup.Backend.Kind.RCLONE:
        return true;

      default:
        explanation = _(
            "This storage location is no longer supported. You can still use " +
            "duplicity directly to back up or restore your files."
        );
        return false;
    }
  }

  public static string duplicity_command()
  {
    var testing_str = Environment.get_variable("DEJA_DUP_TESTING");
    if (testing_str != null && int.parse(testing_str) > 0)
      return "duplicity";
    else
      return Config.DUPLICITY_COMMAND;
  }
}
