var JSXCommands;
(function (JSXCommands) {
    /**
    * Echoes the given arguments
    */
    class Echo {
        create(terminal, stdio, args) {
            if (args.filter((a) => { return a != ""; }).length == 0) {
                stdio.println("Nothing echoes... nothing");
                terminal.closeProgram(this);
                return;
            }
            stdio.println(args.join(" "));
            terminal.closeProgram(this);
        }
        enable() { }
        disable() { }
        onClose() { return true; }
        getManual() {
            return "Echoes the given arguments" +
                "\n\nUsage: echo [anything to echo]";
        }
    }
    JSXCommands.Echo = Echo;
    /**
    * Lists all files in the given directory or this directory, if path not specified.
    */
    class List {
        constructor(jsx) {
            this.jsx = jsx;
        }
        create(terminal, stdio, args) {
            let folder = this.jsx.currentFolder;
            if (args.length > 0) {
                let pathStr = args.slice(-1)[0];
                let path = this.jsx.findPath(pathStr);
                if (path instanceof JavaScriptX.Folder) {
                    args.splice(-1);
                    folder = path;
                }
            }
            let argObj = parseArgsToObject(args);
            let a = "a" in argObj;
            if (a) {
                stdio.println(".", "blue");
                if (folder.parentFolder != null) {
                    stdio.println("..", "blue");
                }
            }
            let files = folder.files.filter(f => (!f.hidden || a));
            for (let i = 0; i < files.length; i++) {
                let f = files[i];
                stdio.println(JavaScriptX.formatToLength(f.name, 20), ((f.hidden) ? "blue" : (f instanceof JavaScriptX.Folder) ? "red" : "yellow"));
                stdio.print("   " +
                    ((f instanceof JavaScriptX.Folder) ? "DIR" : ((f instanceof JavaScriptX.BinaryFile) ? "BIN" : "TXT")));
                stdio.print("   " + new Date(f.created).toLocaleString());
            }
            terminal.closeProgram(this);
        }
        enable() { }
        disable() { }
        onClose() { return true; }
        getManual() {
            return "Lists all files in the given directory\nor this directory, if path not specified." +
                "\n\nUsage: ls [options] [path]" +
                "\n\nOptions:\n " + JavaScriptX.formatToLength("-a", 10) + "List all files (incl. hidden)";
        }
    }
    JSXCommands.List = List;
    /**
    * Changes directory to the specified directory.
    */
    class ChangeDirectory {
        constructor(jsx) {
            this.jsx = jsx;
        }
        create(terminal, stdio, args) {
            if (args.length == 0) {
                stdio.println("Insufficent parameters, usage:");
                stdio.println("cd [path]");
                terminal.closeProgram(this);
                return;
            }
            let path = this.jsx.findPath(args[0]);
            let folder = false;
            if (path) {
                if (path instanceof JavaScriptX.Folder) {
                    folder = true;
                }
                else {
                    stdio.println(`'${args[0]}' is not a folder.`);
                }
            }
            else {
                stdio.println(`'${args[0]}' not found.`);
            }
            if (folder && path instanceof JavaScriptX.Folder) {
                this.jsx.currentFolder = path;
            }
            terminal.closeProgram(this);
        }
        enable() { }
        disable() { }
        onClose() { return true; }
        getManual() {
            return "Changes directory to the specified directory." +
                "\n\nUsage: cd [path]";
        }
    }
    JSXCommands.ChangeDirectory = ChangeDirectory;
    /**
    * Creates a directory at specified location.
    */
    class MakeDirectory {
        constructor(jsx) {
            this.jsx = jsx;
        }
        create(terminal, stdio, args) {
            if (args.length == 0) {
                stdio.println("Insufficent parameters, usage:");
                stdio.println("mkdir [path]");
                terminal.closeProgram(this);
                return;
            }
            let pathArg = args.splice(-1)[0];
            let argObj = parseArgsToObject(args);
            let h = "h" in argObj;
            let origPathpieces = pathArg.split("/");
            let curr = [origPathpieces[0]];
            let i = 0;
            let createFolder = false;
            do {
                let path = this.jsx.findPath(curr.join("/"));
                if (!path) {
                    if (origPathpieces.length == curr.length) {
                        createFolder = true;
                    }
                    else {
                        stdio.println(`${curr.join("/")} not found!`);
                    }
                    break;
                }
                else if (path && origPathpieces.length == curr.length) {
                    stdio.println(`${curr.join("/")} already exists!`);
                }
                else if (!(path instanceof JavaScriptX.Folder)) {
                    stdio.println(`${curr.join("/")} is not a folder!`);
                }
                if (i < origPathpieces.length) {
                    i += 1;
                    curr.push(origPathpieces[i]);
                }
            } while (curr.length < origPathpieces.length + 1);
            if (createFolder) {
                let path = origPathpieces.slice(0, -1).join("/");
                let name = origPathpieces.slice(-1)[0];
                let relative = this.jsx.findPath(path);
                if (relative instanceof JavaScriptX.Folder) {
                    relative.addFile(new JavaScriptX.Folder(name, h));
                }
                else {
                    stdio.println("An error occoured creating the folder.");
                }
            }
            terminal.closeProgram(this);
        }
        enable() { }
        disable() { }
        onClose() { return true; }
        getManual() {
            return "Creates a directory at specified location." +
                "\n\nUsage: mkdir [options] [path]" +
                "\n\nOptions:\n " + JavaScriptX.formatToLength("-h", 10) + "Makes the folder hidden.";
        }
    }
    JSXCommands.MakeDirectory = MakeDirectory;
    /**
    * The Woman in the JSX equivalent to the UNIX Man.
    * It's called Woman (not Man) because of the funny wording,
    * where 'man' sounds like the gender 'man'
    */
    class Woman {
        constructor(jsx) {
            this.jsx = jsx;
        }
        create(terminal, stdio, args) {
            if (args.length == 0) {
                this.readManual(stdio, this);
                terminal.closeProgram(this);
                return;
            }
            let filePath = args.slice(-1)[0];
            for (let env in this.jsx.environmentVariables) {
                if (filePath == env) {
                    filePath = env;
                    break;
                }
                let envFolder = this.jsx.findPath(this.jsx.environmentVariables[env]);
                if (envFolder instanceof JavaScriptX.Folder) {
                    for (let i = 0; i < envFolder.files.length; i++) {
                        if (envFolder.files[i].name == filePath) {
                            filePath = envFolder.files[i].getPath();
                            break;
                        }
                    }
                }
            }
            let f = this.jsx.findPath(filePath);
            if (f && f instanceof JavaScriptX.BinaryFile && manualGuard(f.program)) {
                this.readManual(stdio, f.program);
            }
            else {
                stdio.println("Nothing to womansplain.");
            }
            terminal.closeProgram(this);
        }
        enable() { }
        disable() { }
        onClose() { return true; }
        getManual() {
            return "The Woman in the JSX equivalent to the UNIX Man. " +
                "It's called Woman (not Man) because of the funny wording, " +
                "where 'man' sounds like the gender 'man'" +
                "\n\nUsage: woman [path]";
        }
        readManual(stdio, manual) {
            stdio.println(manual.getManual());
        }
    }
    JSXCommands.Woman = Woman;
    class Caternate {
        constructor(jsx) {
            this.jsx = jsx;
        }
        create(terminal, stdio, args) {
            if (args.length == 0) {
                stdio.println("Insufficent arguments.");
                stdio.println("\nUsage: cat [path]");
                terminal.closeProgram(this);
                return;
            }
            let path = args.splice(-1)[0];
            let file = this.jsx.findPath(path);
            if (file instanceof JavaScriptX.BinaryFile) {
                stdio.println("Unable to read binary files (yet).");
            }
            else if (file instanceof JavaScriptX.Folder) {
                stdio.println(file.name, "blue");
                stdio.print(" is a DIRectory containing ");
                stdio.print(file.files.length + "", "red");
                stdio.print(" files.");
            }
            else if (file instanceof JavaScriptX.TextFile) {
                let contents = file.readContent();
                stdio.println(contents);
            }
            terminal.closeProgram(this);
        }
        enable() { }
        disable() { }
        onClose() { return true; }
        getManual() {
            return "[cat]ernate reads data from given file and outputs it." +
                "\n\nUsage: cat [path]";
        }
        readManual(stdio, manual) {
            stdio.println(manual.getManual());
        }
    }
    JSXCommands.Caternate = Caternate;
    class Touch {
        constructor(jsx) {
            this.jsx = jsx;
        }
        create(terminal, stdio, args) {
            if (args.length == 0) {
                stdio.println("Insufficent arguments.");
                stdio.println("\nUsage: touch [path]");
                terminal.closeProgram(this);
                return;
            }
            let path = args.splice(-1)[0];
            let file = this.jsx.findPath(path);
            if (file) {
                file.created = new Date().getTime();
            }
            else {
                let origPathparts = path.split("/");
                let curr = [origPathparts[0]];
                for (let i = 1; i < origPathparts.length; i++) {
                    let currFile = this.jsx.findPath(curr.join("/"));
                    if (!currFile) {
                        stdio.println(`${curr.join("/")} not found.`);
                        terminal.closeProgram(this);
                        return;
                    }
                    curr.push(origPathparts[i]);
                }
                let filename = curr.splice(-1);
                let folder = this.jsx.findPath(curr.join("/"));
                if (folder instanceof JavaScriptX.Folder) {
                    folder.addFile(new JavaScriptX.TextFile(filename[0]));
                }
                else {
                    stdio.println(`${curr.join("/")} is not a folder.`);
                }
            }
            terminal.closeProgram(this);
        }
        enable() { }
        disable() { }
        onClose() { return true; }
        getManual() {
            return "Touch touches the file specified updating it's timestamp. If the file doesn't exist, it's created." +
                "\n\nUsage: touch [path]";
        }
        readManual(stdio, manual) {
            stdio.println(manual.getManual());
        }
    }
    JSXCommands.Touch = Touch;
    class JEdi {
        constructor(jsx) {
            this.text = [""];
            this.row = 0;
            this.jsx = jsx;
        }
        create(terminal, stdio, args) {
            this.stdio = stdio;
            this.terminal = terminal;
            this.doCommand();
        }
        enable() { }
        disable() { }
        onClose() { return true; }
        getManual() {
            return "(J)avascript (Edi)tor is a custom version of the UNIX editor 'ed'." +
                "\nIt's quite simpler in the way that all of it's commands are whole words" +
                "\n\nUsage: jedi [(optional) path]";
        }
        readManual(stdio, manual) {
            stdio.println(manual.getManual());
        }
        doCommand() {
            let readline = this.stdio.readline({
                callback: c => this.exec(c),
                prefix: "\n> ",
                printAfterDone: true
            });
        }
        exec(command) {
            if (command == "exit" || command == "quit") {
                this.terminal.closeProgram(this);
                return;
            }
            else if (command.split(" ")[0] == "append") {
                let appended = command.split(" ").slice(1).join(" ");
                debugger;
                console.log(appended);
                let rows = appended.split("\n");
                console.log(rows);
                for (let i = 0; i < rows.length; i++) {
                    if (this.text.length <= (this.row + i)) {
                        this.text.push("");
                    }
                    this.text[this.row + i] += rows[i];
                }
                this.row += rows.length - 1;
                this.stdio.println(`${this.text[this.row]}`);
            }
            this.doCommand();
        }
    }
    JSXCommands.JEdi = JEdi;
    /**
    * Parses all given args from '--arg val' into format {arg: val}
    */
    function parseArgsToObject(args, defaults = {}) {
        let returned = {};
        for (let key in defaults) {
            returned[key] = defaults[key];
        }
        let currArg = null;
        args.forEach(arg => {
            if (arg.startsWith("-")) {
                if (arg.startsWith("--")) {
                    if (currArg) {
                        returned[currArg] = null;
                    }
                    ;
                    currArg = arg.substr(2);
                    return;
                }
                if (currArg) {
                    returned[currArg] = null;
                }
                ;
                currArg = arg.substr(1);
            }
            else {
                if (currArg) {
                    returned[currArg] = arg;
                    currArg = null;
                }
            }
        });
        if (currArg) {
            returned[currArg] = null;
        }
        ;
        return returned;
    }
    function manualGuard(arg) {
        return arg.getManual !== undefined;
    }
})(JSXCommands || (JSXCommands = {}));
