"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.useFileStructure = exports.garbageFiles = void 0;
var _react = require("react");
var _utilities = require("./utilities");
const garbageFiles = exports.garbageFiles = ['.DS_Store', 'Thumbs.db'];

/**
 * This functionality is built on File and Directory Entries API and is possible through
 * support of limited number of major browsers, such as Chrome, Firefox,
 * Edge and even Safari (at least 13.0.3).
 * https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/webkitGetAsEntry
 *
 * @param {number} maxDepth - Limit file tree to specified depth.
 * @param {array} filesToExclude - A list of garbage files.
 * @param {func} allowFile - A method to validate provided File before proceeding.
 * @param {func} fileStructureAdapter - allows to shape the output for purpose
 * @param {boolean} hideEmptyFolders - To not handle empty folders
 * @param {boolean} retainFileStructure
 * @returns {object} - { fileStructure, filesPending, generateFileStructure }
 */

const useFileStructure = ({
  maxDepth,
  filesToExclude = garbageFiles,
  allowFile = () => true,
  fileStructureAdapter = _utilities.defaultFileStructureAdapter,
  hideEmptyFolders = true,
  retainFileStructure = true
} = {}) => {
  const skippedFiles = new Set(filesToExclude);
  const [fileStructure, setFileStructure] = (0, _react.useState)([]);
  const [isPending, setIsPending] = (0, _react.useState)(false);
  const {
    resetFileStructure,
    adaptedFileStructure = {},
    addFile = () => {},
    addFolder = () => {}
  } = fileStructureAdapter();
  const handleDirectory = async itemEntry => {
    if (!(0, _utilities.isDepthAllowed)(maxDepth, itemEntry.fullPath)) {
      return;
    }
    // Recursively scan directory structure
    const directoryReader = itemEntry.createReader();
    const entries = await (0, _utilities.readEntriesAsync)(directoryReader);
    if (!entries?.length && hideEmptyFolders) {
      return;
    }
    addFolder({
      folder: itemEntry,
      path: itemEntry.fullPath
    });
    if (entries?.length) {
      await (0, _utilities.asyncForEach)(entries, async entry => {
        await scanFiles(entry);
      });
    }
  };
  const handleFile = async itemEntry => {
    // Read file content for further processing (uploading)
    const file = await (0, _utilities.getEntryFileAsync)(itemEntry);
    if (!file || allowFile && !allowFile(file)) {
      return; // filter out files
    }
    addFile({
      file,
      path: itemEntry.fullPath
    });
  };
  async function scanFiles(itemEntry) {
    const {
      name,
      isDirectory
    } = itemEntry;

    // Skip unwanted files and restrict number of files
    if (skippedFiles.has(name)) {
      return;
    }
    if (isDirectory) {
      await handleDirectory(itemEntry);
      return;
    }
    await handleFile(itemEntry);
  }
  const getStructureFromItems = async items => {
    // Convert top level dropped items into 'File and Directory Entries API' entries
    // Crucial methods are async, to accommodate that current function is async as well
    const itemList = Array.prototype.slice.call(items).reduce((result, item) => {
      const itemEntry = item.webkitGetAsEntry(); // this gets proper FileSystem entry object
      if (itemEntry) {
        result.push(itemEntry);
      }
      return result;
    }, []);

    // Start scanning provided top level entries
    await (0, _utilities.asyncForEach)(itemList, async item => {
      await scanFiles(item);
    });
  };
  const validateFileByExtension = file => {
    const match = (file.name || '').match(/\.[0-9a-z]+$/i);
    // I couldn't find a reference to skipTypeValidation
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-ignore
    return match && !!match[0] || file.skipTypeValidation;
  };
  const getStructureFromFiles = (fileList = []) => {
    // Fallback to files
    const conformedList = Array.prototype.slice.call(fileList);
    conformedList.forEach(file => {
      if (allowFile && !allowFile(file)) {
        return; // filter out files
      }
      // Rejects files without type (e.g. folders)
      if (file.type || validateFileByExtension(file)) {
        addFile({
          file,
          path: file.name
        });
      }
    });
  };
  const createFileStructure = async ({
    items,
    files
  } = {}) => {
    if (!retainFileStructure && resetFileStructure) {
      resetFileStructure(adaptedFileStructure);
    }
    // Depending on support of techology collect files and directories
    if ((0, _utilities.isItemsFileStructureSupported)(items)) {
      await getStructureFromItems(items);
    } else if (files && files.length) {
      getStructureFromFiles(files);
    }
    return adaptedFileStructure;
  };
  const generateFileStructure = async dataTransfer => {
    // Bootstrap everything to React
    setIsPending(true);
    const collectedFileStructure = await createFileStructure(dataTransfer);
    setFileStructure(collectedFileStructure);
    setIsPending(false);
    return collectedFileStructure;
  };
  return {
    fileStructure,
    filesPending: isPending,
    generateFileStructure,
    createFileStructure
  };
};
exports.useFileStructure = useFileStructure;