// readFile :: FileEntry -> IO Text
async function readFile(de) {
  return new Promise((resolve) =>
    de.file((f) => {
      var r = new FileReader();
      r.onloadend = function(c) { resolve(this.result); };
      r.readAsText(f);
    })
  );
};

// getDirectoryConfigs :: DirectoryEntry -> IO (Map Text Text)
async function getDirectoryConfigs(dir) {
  return new Promise(async (resolve) => {
    var r = dir.createReader();
    r.readEntries(async (results) => {
      var res = new Map();
      await Promise.all(results.map(async (de) => {
        if (de.isFile) {
          let contents = await readFile(de);
          res.set(de.name, contents);
        } else if (de.isDirectory) {
          let subConfigs = await getDirectoryConfigs(de);
          // update the subconfigs keys relative to configs path
          let cs = mapKeys((p) => `${de.name}/${p}`, subConfigs);
          // update result with subconfigs
          cs.forEach((v,k) => { res.set(k,v); });
        }
      }));
      resolve(res);
    });
  });
}

// readExtensionConfigs :: IO (Map Text Text)
async function readExtensionConfigs() {
  return new Promise((resolve) => {
    chrome.runtime.getPackageDirectoryEntry((root) => {
      root.getDirectory('config', {create: false}, async (dir) => {
        let configs = await getDirectoryConfigs(dir);
        resolve(Object.fromEntries(configs));
      })
    });
  })
}

// mapKeys :: (k -> k') -> Map k v -> Map k' v
function mapKeys(f, m) {
  let newM = new Map();
  m.forEach((val, key) => {
    newM.set(f(key), val);
  });
  return newM;
}
