// -= Helper Functions =- //
function _internal_joinPaths(path1: string, path2: string): string {
  if (path2[0] == "/") {
    return _internal_sanitizePath(path2);
  } else if (path2[0] == "~" && (path2.length == 1 || path2[1] == "/")) {
    return _internal_sanitizePath(HOME_DIR + path2.slice(1));
  } else {
    return _internal_sanitizePath(path1 + "/" + path2);
  }
}

function _internal_sanitizePath(path: string): string {
  while (path.includes("//")) {
    path = path.replaceAll("//", "/");
  }

  while (path[path.length - 1] == "/") {
    path = path.slice(0, path.length - 1);
  }

  let newPath: string[] = []
  for (const dir of path.split("/")) {
    if (dir == ".") {
      //
    } else if (dir == "..") {
      if (newPath.length) {
        newPath = newPath.slice(0, newPath.length - 1);
      }
    } else if (dir) {
      newPath.push(dir);
    }
  }

  return "/" + newPath.join("/");
}

function _internal_getFile(path: string): _file | null {
  function getFile_recursive(files: _files, path: string[]): _file | null {
    console.log(files, path)
    let file: _file = files[path[0]];

    if (!file) {
      return null;
    }

    if (path.length == 1) {
      return file;
    }

    if (file.type == "file") {
      return null;
    }

    return getFile_recursive(file.files, path.slice(1));
  }

  if (path == "/") {
    return {
      type: "directory",
      name: "/",
      files: FILESYSTEM
    };
  }

  let dirs: string[] = path.split("/");

  if (dirs[0] == "") {
    dirs = dirs.slice(1);
  }

  return getFile_recursive(FILESYSTEM, dirs);
}

function _internal_stringifyPath(path: string): string {
  if (path.startsWith(HOME_DIR)) {
    return path.replace(HOME_DIR, "~");
  }

  return path;
}

function _internal_getPS1(winInfo: _tShWinInfo): string {
  return `<b class="green">${winInfo.ps1Override || "trinkey@website"}</b>:<b class="blue">${_internal_stringifyPath(winInfo.PWD)}</b>$&nbsp;`
}

function _internal_getFlags(command: string): {
  flags: string[]
  removed: string
} {
  let flags: string[] = [];
  let newCommand: string[] = [];

  for (const thing of command.split(" ")) {
    if (thing.startsWith("-")) {
      flags.push(...thing.slice(1).split(""))
    } else {
      newCommand.push(thing);
    }
  }

  return {
    flags: flags,
    removed: newCommand.join(" ")
  };
}

function _internal_fileSize(size: number): string {
  let suffix: string = ""
  let amount: number = size;

  const sizes: { suffix: string, amount: number, threshold: number }[] = [
    { suffix: "K", amount: 1024     , threshold: 10_000    },
    { suffix: "M", amount: 1024 ** 2, threshold: 1_000_000 }
  ]

  for (const info of sizes) {
    if (size > info.threshold) {
      suffix = info.suffix;
      amount = Math.round(size / info.amount * 10) / 10;

      if (String(amount).length > 3) {
        amount = Math.round(info.amount);
      }
    }
  }

  return `${amount}${suffix}`.padStart(4, " ");
}

// -= Commands =- //
function cat(path: string, windowID: string): string {
  if (!path) {
    return "<div>cat: You must specify a file</div>";
  }

  path = _internal_joinPaths(windowInformation[windowID].PWD || HOME_DIR, path);
  let file: _file = _internal_getFile(path);

  if (!file) {
    return `<div>cat: ${escapeHTML(path)}: No such file or directory</div>`;
  } else if (file.type == "directory") {
    return `<div>cat: ${escapeHTML(path)}: Is a directory</div>`;
  } else {
    return file.content;
  }
}

function cd(path: string, windowID: string): string {
  if (!path) {
    windowInformation[windowID].PWD = HOME_DIR;
    return "";
  }

  let newPWD: string = _internal_joinPaths(windowInformation[windowID].PWD, path);
  let newFileObj: _file | null = _internal_getFile(newPWD);

  if (newFileObj === null) {
    return `<div>cd: ${escapeHTML(path)}: No such file or directory</div>`;
  } else if (newFileObj.type == "file") {
    return `<div>cd: ${escapeHTML(path)}: Not a directory</div>`;
  }

  windowInformation[windowID].PWD = newPWD;

  return "";
}

function clear(path: string, windowID: string): string {
  WINDOWS[windowID].element.querySelector(".window").innerHTML = "";
  return "";
}

function exit(path: string, windowID: string): string {
  setTimeout((): void => {
    (WINDOWS[windowID].element.querySelector(".close") as HTMLElement).click();
  }, 1);
  return "";
}

function help(path: string, windowID: string): string {
  return helpText;
}

function ls(path: string, windowID: string): string {
  let { flags, removed } = _internal_getFlags(path);

  path = _internal_joinPaths(windowInformation[windowID].PWD || HOME_DIR, removed);

  let file: _file = _internal_getFile(path);
  let files: _files;

  if (!file) {
    return `<div>ls: ${escapeHTML(path)}: No such file or directory</div>`;
  } else if (file.type == "file") {
    files = { [file.name]: file };
  } else {
    files = file.files;
  }

  let directories: _file[] = [];
  let hidden: boolean = flags.includes("a") || flags.includes("A");
  let long: boolean = flags.includes("l");
  let out: string = flags.includes("a") ? (long ? "<div>drwxrwxr-x trinkey trinkey 4096 <span class=\"blue\">.</span></div><div>drwxr-xr-x trinkey trinkey 4096 <span class=\"blue\">..</span></div>" : "<span class=\"blue\">.</span> &nbsp;<span class=\"blue\">..</span> &nbsp;") : "";

  for (const file of Object.keys(files).sort((a: string, b: string): number => (
    ({ true: 1, false: -1 })[String(flags.includes("r") ? a < b : a > b)]
  ))) {
    if (file.startsWith(".") && !hidden) {
      continue;
    }

    let fObj: _file = files[file];
    if (long) {
      if (fObj.type == "directory") {
        directories.push(fObj);
        out += `<div>drwxrwxr-x trinkey trinkey 4096 <span class=\"blue\">${escapeHTML(file)}</span></div>`;
      } else {
        out += `<div>-rw-rw-r-- trinkey trinkey ${_internal_fileSize(fObj.content.length).replaceAll(" ", "&nbsp;")} ${escapeHTML(file)}</div>`;
      }
    } else {
      if (fObj.type == "directory") {
        directories.push(fObj);
        out += `<span class=\"blue\">${escapeHTML(file)}</span> &nbsp;`;
      } else {
        out += `${escapeHTML(file)} &nbsp;`;
      }
    }
  }

  if (!long) {
    out = out.slice(0, out.length - 7);
  }

  if (flags.includes("R")) {
    for (const dir of directories) {
      out += `<div><br>${escapeHTML(_internal_stringifyPath(_internal_joinPaths(path, dir.name)))}:</div>${ls(`${_internal_joinPaths(path, dir.name)} -${flags.join("")}`, windowID)}`;
    }
  }

  return out;
}

function _internal_set_ps1(args: string, windowID: string): string {
  windowInformation[windowID].ps1Override = args.split("|")[0];
  WINDOWS[windowID].element.querySelector(".window [data-type-area]").innerHTML = args.split("|")[1];
  return "";
}

function _internal_neofetch(args: string, windowID: string): string {
  WINDOWS[windowID].element.querySelector(".window [data-type-area]").innerHTML = "neofetch";
  return _internal_neofetchOutputs[args];
}

const _internal_commands: { [key: string]: (args: string, windowID: string) => string } = {
  cat: cat,
  cd: cd,
  clear: clear,
  help: help, // NEEDS UPDATING
  ls: ls,
  exit: exit,
  _internal_set_ps1: _internal_set_ps1,
  _internal_neofetch: _internal_neofetch
};

// -= Variables + Other =- //
const _internal_defaultFiles: StringDict = {
  about: `<div><b>hi there! i'm trinkey!</b></div>
    <div>--------------------</div>
    <div>i'm a silly little kitty cat who lives in the usa.</div>
    <div>i'm <span class="blue">t</span><span class="pink">r</span>a<span class="pink">n</span><span class="blue">s</span> (she/her, they/them and it/its are also fine).</div>
    <div>i'm not actively in a relationship, however i'm also not looking to get into one either.</div>
    <div>--------------------</div>
    <div>i like to code stuff (mostly websites)! some of my programs can be found on the <a href="javascript:windowPreset('projects')">projects page</a>. i know a few languages, those being python, javascript/typescript, html/css (if you count those), and a little bit of java.</div>
    <div>--------------------</div>
    <div>well, that's about it! i hope you like my website!</div>`,
  socials: `<div>- fedi - <b>@trinkey@trinkey.com</b> (or @trinkey@is.trinkey.com)</div>
    <div>- forgejo - <a href="https://git.trinkey.com/trinkey/" target="_blank"><b>trinkey</b></a></div>
    <div>- github - <a href="https://github.com/trinkey/" target="_blank"><b>trinkey</b></a></div>
    <div>- git.gay - <a href="https://git.gay/trinkey/" target="_blank"><b>trinkey</b></a> (inactive)</div>
    <div>- smiggins - <a href="https://smiggins.trinkey.com/u/trinkey/" target="_blank"><b>trinkey</b></a></div>
    <div>- signal - <b>@trinkey.01</b></div>
    <div>- email - <b>trinkey [at] proton [dot] me</b></div>
    <div>- youtube - <a href="https://youtube.com/@trinkey" target="_blank"><b>@trinkey</b></a> (inactive)</div>`,
  buttons: `<div><b>my button:</b> (click to copy html)</div>
    <div><img style="cursor: pointer;" src="img/88x31.png" alt="trinkey's 88x31. image of her cat on the right with the word 'trinkey' taking up the rest of the button." title="trinkey's 88x31. image of her cat on the right with the word 'trinkey' taking up the rest of the button." onclick="copyButton()"></div>
    <div>--------------------</div>
    <div><b>cool people:</b></div>
    <div class="buttons-88x31">
      <a href="https://notfire.cc"      target="_blank"><img src="https://notfire.cc/design/images/buttons/notfire-cc-88x31-af.gif" alt="notfire.cc" title="notfire.cc"></a>
      <a href="https://micro.niko.lgbt" target="_blank"><img src="https://micro.niko.lgbt/static/button_2.png" alt="a non-spinning demigirl blobcat angled slightly with a black border to the left of &quot;Micro&quot;" title="a non-spinning demigirl blobcat angled slightly with a black border to the left of &quot;Micro&quot;"></a>
      <a href="https://w.on-t.work"     target="_blank"><img src="https://w.on-t.work/assets/88x31.png" alt="kopper's button" title="kopper's button"></a>
      <a href="https://synth.download"  target="_blank"><img src="https://synth.download/assets/buttons/sneexy.svg" alt="Sneexy" title="Sneexy"></a>
      <a href="https://beepi.ng" target="_blank"><img src="https://beepi.ng/88x31.png" alt="unnick" title="unnick"></a>
    </div>`,
  testimonials: `<div>"warning: this user is trinkey"</div>
    <div>- <a href="https://booping.synth.download/@breaadyboy" target="_blank">bread</a></div><br>
    <div>"This user is only slightly crazy once was I. 10/10 would recommend"</div>
    <div>- <a href="https://lea.pet/@subroutine" target="_blank">subroutine</a></div><br>
    <div>"the f slur but repeated 36 times"</div>
    <div>- <a href="https://oomfie.city/@cornfields74">corn fields seventy four</a></div>`,
  webrings: `<div>
      <a href="https://ctp-webr.ing/trinkey/previous">&larr;</a>
      <a href="https://ctp-webr.ing/">catppuccin webring</a>
      <a href="https://ctp-webr.ing/trinkey/next">&rarr;</a>
    </div>
    <div>
      <a href="https://fediring.net/previous?host=trinkey.com">&larr;</a>
      <a href="https://fediring.net/">fediring</a>
      <a href="https://fediring.net/next?host=trinkey.com">&rarr;</a>
    </div>`,
  projects: `<div><b>projects</b> - the things i made</div>
    <div>- <a href="https://github.com/jerimiah-smiggins/smiggins/" target="_blank"><b>smiggins</b></a> (<a href="https://smiggins.trinkey.com/" target="_blank">website</a>) - a social media platform i made</div>
    <div>- <a href="https://git.trinkey.com/trinkey/website/" target="_blank"><b>this website</b></a> - check out the code</div>
    <div>- <a href="https://git.gay/trinkey/dotindex/" target="_blank"><b>dotindex</b></a> (<a href="https://pypi.org/project/DotIndex/" target="_blank">pypi</a>) - a python library that lets you access dicts using the dot notation (dict.key) instead of whatever python does (dict["key"])</div>
    <div>- <a href="https://git.gay/trinkey/infopage/" target="_blank"><b>infopage</b></a> (<a href="https://infpg.pythonanywhere.com/" target="_blank">website</a>) - my very own pronouns.page clone</div>
    <div>- <a href="https://git.trinkey.com/t" target="_blank"><b>tSuite</b></a> (<a href="https://auth.trinkey.com/" target="_blank">website</a>) - a collection of services that are all interconnected</div><br>
    <div>i'll likely add more in the future, these are just the ones i'm most proud of at the moment.</div>`,
  directory: `<div>there's a lot that goes into this website. here are some links for your usage to help you navigate this hellhole</div><br>
    <div><b><a href="https://trinkey.com/">trinkey.com</a>:</b></div>
    <div>this is where you are right now</div><br>
    <div>*<b><a href="https://akkofe.trinkey.com/">akkofe.trinkey.com</a>:</b></div>
    <div>the frontend i use for <a href="https://fediverse.info/" target="_blank">fedi</a></div><br>
    <div><b><a href="https://auth.trinkey.com/">auth.trinkey.com</a>:</b></div>
    <div>authentication manager for tSuite</div><br>
    <div><b><a href="https://blog.trinkey.com/">blog.trinkey.com</a>:</b></div>
    <div>tBlog, from tSuite</div><br>
    <div><b><a href="https://everyone.trinkey.com/">everyone.trinkey.com</a>:</b></div>
    <div>frontend to a fedi bot that anyone can post to (@everyonebot@is.trinkey.com)</div><br>
    <div>*<b><a href="https://git.trinkey.com/">git.trinkey.com</a>:</b></div>
    <div>holds some of my git projects (older ones on <a href="https://github.com/trinkey/" target="_blank">github</a> or <a href="https://git.gay/trinkey/" target="_blank">git.gay</a>)</div><br>
    <div>*<b><a href="https://is.trinkey.com/">is.trinkey.com</a>:</b></div>
    <div>hosts <a href="https://iceshrimp.dev/iceshrimp/iceshrimp.net" target="_blank">iceshrimp.net</a>, which is the fedi backend i use</div><br>
    <div><b><a href="https://message.trinkey.com/">message.trinkey.com</a>:</b></div>
    <div>tMessage, from tSuite</div><br>
    <div><b><a href="https://music.trinkey.com/">music.trinkey.com</a>:</b></div>
    <div>has some music. i haven't actually updated the site in a while but i've been meaning to do rewrite it at some point. 100% legal i pinky promise</div><br>
    <div><b><a href="https://smiggins.trinkey.com/">smiggins.trinkey.com</a>:</b></div>
    <div>official jerimiah smiggins instance, that being my own social media platform</div><br>
    <div>(asterisk (*) means i haven't written the code for it)</div><br>`
};

const _internal_neofetchOutputs: StringDict = {
  desktop: `<pre>             <b>...-:::::-...</b>                 <b class="green">trinkey</b>@<b class="green">desktop</b>
          <b>.-MMMMMMMMMMMMMMM-.</b>              ---------------
      <b>.-MMMM<span class="green">\`..-:::::::-..\`</span>MMMM-.</b>          <b class="green">OS</b>: Linux Mint 21.3 x86_64
    <b>.:MMMM<span class="green">.:MMMMMMMMMMMMMMM:.</span>MMMM:.</b>        <b class="green">Host</b>: MS-7E27 1.0
   <b>-MMM<span class="green">-M---MMMMMMMMMMMMMMMMMMM.</span>MMM-</b>       <b class="green">Resolution</b>: 1680x1050, 2560x1440
 <b>\`:MMM<span class="green">:MM\`  :MMMM:....::-...-MMMM:</span>MMM:\`</b>    <b class="green">DE</b>: Cinnamon 6.0.4
 <b>:MMM<span class="green">:MMM\`  :MM:\`  \`\`    \`\`  \`:MMM:</span>MMM:</b>    <b class="green">WM</b>: Mutter (Muffin)
<b>.MMM<span class="green">.MMMM\`  :MM.  -MM.  .MM-  \`MMMM.</span>MMM.</b>   <b class="green">CPU</b>: AMD Ryzen 9 7950X (32) @ 5.881GHz
<b>:MMM<span class="green">:MMMM\`  :MM.  -MM-  .MM:  \`MMMM-</span>MMM:</b>   <b class="green">GPU</b>: AMD ATI 03:00.0 Device 747e
<b>:MMM<span class="green">:MMMM\`  :MM.  -MM-  .MM:  \`MMMM:</span>MMM:</b>   <b class="green">GPU</b>: AMD ATI 11:00.0 Device 164e
<b>:MMM<span class="green">:MMMM\`  :MM.  -MM-  .MM:  \`MMMM-</span>MMM:</b>   <b class="green">Memory</b>: 1MiB / 127901MiB
<b>.MMM<span class="green">.MMMM\`  :MM:--:MM:--:MM:  \`MMMM.</span>MMM.</b>
 <b>:MMM<span class="green">:MMM-  \`-MMMMMMMMMMMM-\`  -MMM-</span>MMM:</b>
  <b>:MMM<span class="green">:MMM:\`                \`:MMM:</span>MMM:</b>
   <b>.MMM<span class="green">.MMMM:--------------:MMMM.</span>MMM.</b>
     <b>'-MMMM<span class="green">.-MMMMMMMMMMMMMMM-.</span>MMMM-'</b>
       <b>'.-MMMM<span class="green">\`\`--:::::--\`\`</span>MMMM-.'</b>
            <b>'-MMMMMMMMMMMMM-'</b>
               <b>\`\`-:::::-\`\`</b></pre>`,
  laptop: `<pre>             <b>...-:::::-...</b>                 <b class="green">trinkey</b>@<b class="green">laptop</b>
          <b>.-MMMMMMMMMMMMMMM-.</b>              ---------------
      <b>.-MMMM<span class="green">\`..-:::::::-..\`</span>MMMM-.</b>          <b class="green">OS</b>: Linux Mint 21.2 x86_64
    <b>.:MMMM<span class="green">.:MMMMMMMMMMMMMMM:.</span>MMMM:.</b>        <b class="green">Host</b>: Dell G15 5510
   <b>-MMM<span class="green">-M---MMMMMMMMMMMMMMMMMMM.</span>MMM-</b>       <b class="green">Resolution</b>: 2560x1440, 1920x1080, 1680x1050
 <b>\`:MMM<span class="green">:MM\`  :MMMM:....::-...-MMMM:</span>MMM:\`</b>    <b class="green">DE</b>: Cinnamon 5.8.4
 <b>:MMM<span class="green">:MMM\`  :MM:\`  \`\`    \`\`  \`:MMM:</span>MMM:</b>    <b class="green">WM</b>: Mutter (Muffin)
<b>.MMM<span class="green">.MMMM\`  :MM.  -MM.  .MM-  \`MMMM.</span>MMM.</b>   <b class="green">CPU</b>: Intel i5-10500H (12) @ 4.500GHz
<b>:MMM<span class="green">:MMMM\`  :MM.  -MM-  .MM:  \`MMMM-</span>MMM:</b>   <b class="green">GPU</b>: NVIDIA GeForce RTX 3050 Ti Mobile
<b>:MMM<span class="green">:MMMM\`  :MM.  -MM-  .MM:  \`MMMM:</span>MMM:</b>   <b class="green">GPU</b>: Intel CometLake-H GT2 [UHD Graphics]
<b>:MMM<span class="green">:MMMM\`  :MM.  -MM-  .MM:  \`MMMM-</span>MMM:</b>   <b class="green">Memory</b>: 2001MiB / 15765MiB
<b>.MMM<span class="green">.MMMM\`  :MM:--:MM:--:MM:  \`MMMM.</span>MMM.</b>
 <b>:MMM<span class="green">:MMM-  \`-MMMMMMMMMMMM-\`  -MMM-</span>MMM:</b>
  <b>:MMM<span class="green">:MMM:\`                \`:MMM:</span>MMM:</b>
   <b>.MMM<span class="green">.MMMM:--------------:MMMM.</span>MMM.</b>
     <b>'-MMMM<span class="green">.-MMMMMMMMMMMMMMM-.</span>MMMM-'</b>
       <b>'.-MMMM<span class="green">\`\`--:::::--\`\`</span>MMMM-.'</b>
            <b>'-MMMMMMMMMMMMM-'</b>
               <b>\`\`-:::::-\`\`</b></pre>`,
  server: `<pre>             <b>...-:::::-...</b>                 <b class="green">trinkey</b>@<b class="green">server</b>
          <b>.-MMMMMMMMMMMMMMM-.</b>              ---------------
      <b>.-MMMM<span class="green">\`..-:::::::-..\`</span>MMMM-.</b>          <b class="green">OS</b>: Linux Mint 21.2 x86_64
    <b>.:MMMM<span class="green">.:MMMMMMMMMMMMMMM:.</span>MMMM:.</b>        <b class="green">Host</b>: Macmini7,1 1.0
   <b>-MMM<span class="green">-M---MMMMMMMMMMMMMMMMMMM.</span>MMM-</b>       <b class="green">CPU</b>: Intel i5-4278U (4) @ 3.100GHz
 <b>\`:MMM<span class="green">:MM\`  :MMMM:....::-...-MMMM:</span>MMM:\`</b>    <b class="green">GPU</b>: Intel Haswell-ULT
 <b>:MMM<span class="green">:MMM\`  :MM:\`  \`\`    \`\`  \`:MMM:</span>MMM:</b>    <b class="green">Memory</b>: 9011MiB / 15866MiB
<b>.MMM<span class="green">.MMMM\`  :MM.  -MM.  .MM-  \`MMMM.</span>MMM.</b>
<b>:MMM<span class="green">:MMMM\`  :MM.  -MM-  .MM:  \`MMMM-</span>MMM:</b>
<b>:MMM<span class="green">:MMMM\`  :MM.  -MM-  .MM:  \`MMMM:</span>MMM:</b>
<b>:MMM<span class="green">:MMMM\`  :MM.  -MM-  .MM:  \`MMMM-</span>MMM:</b>
<b>.MMM<span class="green">.MMMM\`  :MM:--:MM:--:MM:  \`MMMM.</span>MMM.</b>
 <b>:MMM<span class="green">:MMM-  \`-MMMMMMMMMMMM-\`  -MMM-</span>MMM:</b>
  <b>:MMM<span class="green">:MMM:\`                \`:MMM:</span>MMM:</b>
   <b>.MMM<span class="green">.MMMM:--------------:MMMM.</span>MMM.</b>
     <b>'-MMMM<span class="green">.-MMMMMMMMMMMMMMM-.</span>MMMM-'</b>
       <b>'.-MMMM<span class="green">\`\`--:::::--\`\`</span>MMMM-.'</b>
            <b>'-MMMMMMMMMMMMM-'</b>
               <b>\`\`-:::::-\`\`</b></pre>`
};

const helpText: string = `<div>&nbsp;-=== <b class="pink">tSh help</b> ===-</div>
<div>--------------------</div>
<div>-= <b class="green">cat</b> =-</div>
<div>Displays the contents of a file.</div>
<div>-= <b class="green">cd</b> =-</div>
<div>Changes the working directory.</div>
<div>-= <b class="green">clear</b> =-</div>
<div>Clears the terminal output.</div>
<div>-= <b class="green">help</b> =-</div>
<div>Shows this help menu.</div>
<div>-= <b class="green">ls</b> =-</div>
<div>Lists all files in a directory.</div>
<div>&nbsp; -l - displays more information about each file</div>
<div>&nbsp; -a - displays all files</div>
<div>&nbsp; -A - displays all files except implied . and ..</div>
<div>&nbsp; -r - reverses the order of the files</div>
<div>&nbsp; -R - recurse through all subdirectories</div>
<div>-= <b class="green">exit</b> =-</div>
<div>Closes the terminal.</div>`;

const HOME_DIR: string = "/home/trinkey";

let FILESYSTEM: _files = {
  home: {
    type: "directory",
    name: "home",
    files: {
      trinkey: {
        type: "directory",
        name: "trinkey",
        files: {
          people: { type: "directory", name: "people", files: {
            "88x31.txt": { type: "file", name: "88x31.txt", content: _internal_defaultFiles.buttons },
            "testimonials.txt": { type: "file", name: "testimonials.txt", content: _internal_defaultFiles.testimonials },
            "webrings.txt": { type: "file", name: "webrings.txt", content: _internal_defaultFiles.webrings }
          }},
          "about-me.txt": { type: "file", name: "about-me.txt", content: _internal_defaultFiles.about },
          "socials.txt": { type: "file", name: "socials.txt", content: _internal_defaultFiles.socials },
          "projects.txt": { type: "file", name: "projects.txt", content: _internal_defaultFiles.projects },
          "subdomains.txt": { type: "file", name: "subdomains.txt", content: _internal_defaultFiles.directory }
        }
      }
    }
  },
  bin: {
    type: "directory",
    name: "bin",
    files: {
      cat:      { type: "file", name: "cat",       content: "<div>function cat(file: string): string { ... }</div>" },
      cd:       { type: "file", name: "cd",        content: "<div>function cd(directory: string): void { ... }</div>" },
      clear:    { type: "file", name: "clear",     content: "<div>function clear(): void { ... }</div>" },
      help:     { type: "file", name: "help",      content: "<div>function help(): string { ... }</div>" },
      ls:       { type: "file", name: "ls",        content: "<div>function ls(directory: string): string { ... }</div>" },
      neofetch: { type: "file", name: "neofetch",  content: "<div>function neofetch(): string { ... }</div>" }
    }
  },
  ".secret-file": { type: "file", name: ".secret-file", content: "<div>meow :3</div>" }
};

let windowInformation: { [key: string]: _tShWinInfo } = {};

function commandManager(windowID: string, command: string): void {
  if (!windowInformation[windowID]) {
    windowInformation[windowID] = {
      PWD: HOME_DIR
    };
  }

  let out: string;
  if (_internal_commands[command.split(" ")[0]]) {
    out = _internal_commands[command.split(" ")[0]](command.split(" ").slice(1).join(" ").trim(), windowID);
  } else if (command == "") {
    out = ""
  } else {
    out = `<div class="red">Unknown command '${escapeHTML(command.split(" ")[0])}'.</div><div>Type 'help' for a list of commands</div>`;
  }

  let el: HTMLDivElement = document.createElement("div");
  el.innerHTML = out;
  WINDOWS[windowID].element.querySelector(".window").append(el);

  let dTE: HTMLElement = WINDOWS[windowID].element.querySelector("[data-type-area]");
  if (dTE) {
    dTE.removeAttribute("data-type-area");
    if (dTE.querySelector("i.cursor")) {
      dTE.querySelector("i.cursor").remove();
    } else if (dTE.querySelector(".cursor")) {
      dTE.querySelector(".cursor").classList.remove("cursor");
    }
  }

  (WINDOWS[windowID].element.querySelector(".window-header-title") as HTMLElement).innerText = `${_internal_stringifyPath(windowInformation[windowID].PWD)} - tSh`;

  let ps1: HTMLDivElement = document.createElement("div");
  ps1.innerHTML = _internal_getPS1(windowInformation[windowID]);

  let typeArea: HTMLSpanElement = document.createElement("span");
  typeArea.dataset.typeArea = "";
  typeArea.innerHTML = "<i class=\"cursor\">&nbsp;</i>";

  ps1.append(typeArea)
  WINDOWS[windowID].element.querySelector(".window").append(ps1);
}