/* -*- 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/Browser.ui")]
public class Browser : Adw.Bin
{
  public signal void folder_changed();

  public bool has_content {get; private set;}
  public bool has_selection {get; private set;}
  public bool can_go_up {get; protected set;}
  public string tag {get; private set;}
  public string folder_name {get; private set;}
  public string search_filter {get; set; default = "";}

  [GtkChild]
  unowned Gtk.Stack view_stack;
  [GtkChild]
  unowned Gtk.Stack overlay_stack;
  [GtkChild]
  unowned Gtk.GridView icon_view;
  [GtkChild]
  unowned Gtk.ColumnView list_view;

  FileStore store;
  Gtk.MultiSelection selection;

  construct
  {
    // Set up store
    store = new FileStore();
    selection = new Gtk.MultiSelection(store);
    selection.selection_changed.connect(selection_changed);
    selection.items_changed.connect(items_changed);

    // Connect file store and views
    icon_view.model = selection;
    icon_view.factory = new Gtk.BuilderListItemFactory.from_resource(
      null, "/org/gnome/DejaDup/BrowserGridItem.ui"
    );

    // Connections
    notify["search-filter"].connect(update_search_filter);
    // selection-changed doesn't emit automatically on clear for some reason
    folder_changed.connect(selection_changed);
    folder_changed.connect(update_folder_name);

    notify["search-filter"].connect(update_can_go_up);
    store.notify["can-go-up"].connect(update_can_go_up);
  }

  void selection_changed() {
    var bitset = selection.get_selection();
    has_selection = !bitset.is_empty();
  }

  void update_folder_name() {
    folder_name = store.current.filename;
  }

  void items_changed() {
    update_content_view();
    selection_changed(); // I wish the selection model did this automatically
  }

  public void select_all() {
    selection.select_all();
  }

  void update_can_go_up() {
    can_go_up = store.can_go_up && search_filter == "";
  }

  public void go_up() {
    if (can_go_up && store.go_up())
      folder_changed();
  }

  [GtkCallback]
  void go_down(uint position) {
    if (store.go_down(position))
      folder_changed();
  }

  // Shows the right pane - search view, normal view, empty versions of either
  void update_content_view()
  {
    if (search_filter != "") {
      view_stack.visible_child_name = "list";
      icon_view.model = null;
      list_view.model = selection;

      if (selection.get_n_items() == 0) {
        switch_overlay_to_empty_search();
      } else {
        switch_overlay_off();
      }
    } else {
      view_stack.visible_child_name = "icons";
      list_view.model = null;
      icon_view.model = selection;

      if (selection.get_n_items() == 0) {
        switch_overlay_to_empty_folder();
      } else {
        switch_overlay_off();
      }
    }
  }

  void update_search_filter()
  {
    update_content_view();
    store.search_filter = search_filter;
  }

  void switch_overlay_to_empty_folder() {
    switch_overlay_to("empty-folder");
  }

  void switch_overlay_to_empty_search() {
    view_stack.visible_child_name = "icons";
    switch_overlay_to("empty-search");
  }

  void switch_overlay_to(string name) {
    overlay_stack.visible_child_name = name;
    overlay_stack.visible = true;
  }

  void switch_overlay_off() {
    overlay_stack.visible = false;
  }

  public List<File> get_selected_files()
  {
    var bitset = selection.get_selection();
    var iter = Gtk.BitsetIter();
    uint position;
    if (!iter.init_first(bitset, out position))
      return new List<File>();

    List<File> files = null;
    files.append(store.get_file(position));
    while (iter.next(out position)) {
      files.append(store.get_file(position));
    }

    return files;
  }

  public DejaDup.FileTree get_tree()
  {
    return store.tree;
  }

  void update_has_content()
  {
    has_content = tag != null;
  }

  public void clear_tree()
  {
    store.clear();
    folder_name = "";
    this.tag = null;
    update_has_content();
  }

  public void set_tree(string tag, DejaDup.FileTree tree)
  {
    this.tag = tag;
    store.set_file_tree(tree);
    items_changed();
    update_folder_name();
    update_has_content();
  }
}
