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

using GLib;

[GtkTemplate (ui = "/org/gnome/DejaDup/ConfigFolderGroup.ui")]
public class ConfigFolderGroup : Adw.PreferencesGroup
{
  public string key {get; set;}
  public bool check_access {get; set;}
  public bool check_size {get; set;}
  public string add_label {get; set;}

  [GtkChild]
  unowned Gtk.Widget add_row;

  DejaDup.FilteredSettings settings;
  int folder_count = 0;

  [GtkCallback]
  void on_key_changed()
  {
    if (key == null)
      return;

    settings = DejaDup.get_settings();
    settings.bind_writable(key, this, "sensitive", false);

    settings.changed[key].connect(() => {update_list_items.begin();});
    update_list_items.begin();
  }

  [GtkCallback]
  void start_update_list_items()
  {
    update_list_items.begin();
  }

  async void update_list_items()
  {
    add_row.ref();
    remove(add_row);

    // Gather all files from GSettings
    var folder_value = settings.get_value(key);
    var folder_list = folder_value.get_strv();
    List<File> setting_files = new List<File>();
    foreach (var folder in folder_list) {
      var file = DejaDup.parse_dir(folder);
      if (file != null) {
        file.set_data("folder", folder);
        setting_files.append(file);
      }
    }

    // Now iterate through existing rows, keeping or removing them
    for (int i = folder_count - 1; i >= 0; i--) {
      var row = (ConfigFolderRow)get_row(i);
      var found = false;
      foreach (var file in setting_files) {
        if (file.equal(row.file)) {
          found = true;
          row.check_access = check_access;
          row.check_size = check_size;
          setting_files.remove(file);
          break;
        }
      }
      if (!found) {
        folder_count--;
        remove(row);
      }
    }

    // Now add any remaining (new) rows
    foreach (var file in setting_files) {
      var row = new ConfigFolderRow();
      row.file = file;
      row.check_access = check_access;
      row.check_size = check_size;
      row.remove_clicked.connect((r) => {
        handle_remove(((ConfigFolderRow)r).file.get_data("folder"));
      });

      folder_count++;
      add(row);
    }

    // Now add back the "add item" row
    add(add_row);
    add_row.unref();
  }

  [GtkCallback]
  void on_add_clicked()
  {
    select_folders.begin();
  }

  async void select_folders()
  {
    var dlg = new Gtk.FileDialog();
    dlg.modal = true;

    try {
      var folders = yield dlg.select_multiple_folders(this.root as Gtk.Window, null);
      add_files(folders);
    } catch (Error e) {
      // Ignore, as it is probably just a user-cancellation
    }
  }

  bool add_files(ListModel files)
  {
    // Explicitly do not call get_file_list here, because we want to avoid
    // modifying existing entries at all when we write the string list back.
    var slist_val = settings.get_value(key);
    string*[] slist = slist_val.get_strv();
    bool changed = false;

    for (int i = 0; i < files.get_n_items(); i++) {
      var folder = files.get_item(i) as File;
      if (folder.get_path() == null)
        continue;

      // Strip any leading root path in case the user somehow navigated to the
      // read root. We'll prefix it again when backing up.
      folder = DejaDup.remove_read_root(folder);

      bool found = false;
      foreach (string s in slist) {
        var sfile = DejaDup.parse_dir(s);
        if (sfile != null && sfile.equal(folder)) {
          found = true;
          break;
        }
      }

      if (!found) {
        slist += folder.get_parse_name();
        changed = true;
      }
    }

    if (changed) {
      settings.set_value(key, new Variant.strv(slist));
    }
    return changed;
  }

  void handle_remove(string folder)
  {
    var old_value = settings.get_value(key);
    var old_list = old_value.get_strv();
    var new_list = new string[0];

    foreach (string old in old_list) {
      if (old != folder)
        new_list += old;
    }

    settings.set_value(key, new Variant.strv(new_list));
  }
}
