<template>
  <v-layout fill-height style="overflow-y:auto;max-height:400px;">
    <v-progress-circular v-if="loading && !items.length"></v-progress-circular>
    <v-treeview v-else
      activatable
      :active.sync="active"
      :items="items"
      item-key="path"
      item-name="basename"
      :load-children="readdir"
      @update:active="activeChanged"
      style="min-width:100%"
    >
      <template v-slot:label="{item}">
        <div style="cursor:pointer;">
          {{ item.basename }}
        </div>
      </template>
    </v-treeview>
  </v-layout>
</template>

<script>
import { mapActions, mapGetters } from 'vuex';

function find(haystack, needle) {
  for (const item of haystack) {
    if (item.path == needle) {
      return item;
    } else if (item.children) {
      const found = find(item.children, needle);
      if (found) {
        return found;
      }
    }
  }
}

export default {
  name: "DougalFileBrowser",

  props: [ "value", "mimetypes", "root" ],

  data () {
    return {
      loading: false,
      items: [],
      active: [],
      selected: null,
      path: "",
    };
  },

  computed: {

    dirsAreSelectable () {
      return !this.mimetypes ||
        this.mimetypes == "inode/directory" ||
        (Array.isArray(this.mimetypes) && this.mimetypes.includes("inode/directory"));
    }

  },

  watch: {
  },

  methods: {

    activeChanged (active) {
      const candidate = find(this.items, active[0]);
      if (!this.dirsAreSelectable && this.isDirectory(candidate)) {
        this.selected = null;
      } else {
        this.selected = candidate;
      }
      this.$emit("input", this.selected?.path);
    },

    isDirectory (item) {
      return item && item["Content-Type"] == "inode/directory";
    },

    filterMimetypes (item) {
      if (!this.mimetypes) {
        return true;
      } else if (Array.isArray(this.mimetypes)) {
        return item["Content-Type"] == "inode/directory" ||
          this.mimetypes.includes(item["Content-Type"].split(";")[0]) ||
          this.filterGlob(item);
      } else {
        return item["Content-Type"] == "inode/directory" ||
          this.mimetypes == item["Content-Type"].split(";")[0];
      }
      return false;
    },

    filterGlob (item) {
      const globs = (Array.isArray(this.mimetypes)
        ? this.mimetypes
        : [ this.mimetypes ])
      .filter(i => /^\*\..+$/.test(i));

      for (const glob of globs) {
        const ext = (glob.match(/^\*\.(.+)$/)||[])[1];
        if (item.path.toLowerCase().endsWith(ext.toLowerCase())) {
          return true;
        }
      }

      return false;
    },

    async readdir (item) {
      this.loading = true;
      const url = `/files/${item? item.path : (this.root || this.path || "")}`;
      const list = await this.api([url]);
      this.loading = false;
      const items = list?.map(item => {
        if (item["Content-Type"] == "inode/directory") {
          item.children = [];
        }
        item.id = item.path;
        item.name = item.basename;
        return item;
      }).filter(this.filterMimetypes);
      if (item) {
        item.children = items;
      } else {
        this.items = items;
      }
    },

    async refresh () {
      this.items = []
      this.$nextTick(this.readdir);
    },

    ...mapActions(["api"])

  },

  mounted () {
    if (this.value) {
      this.path = this.value;
    }
    this.readdir();
  }
}

</script>
