local cloptions = {
    a = false,
    h = false,
    l = false,
    help = false,
}

local inpArgs = {...}
local args = {}
local name = syscall.getTask(syscall.getpid()).name

local optToSet = false
for _, v in pairs(inpArgs) do
    if optToSet then
        cloptions[optToSet] = v
        optToSet = false
    elseif v:sub(1, 2) == "--" then
        local opt = v:sub(3)
        if cloptions[opt] == nil then
            print(name..": unrecognized option '"..v.."'.")
            if cloptions.help ~= nil then
                print("try '"..name.." --help' for more information.")
            end
            return
        elseif cloptions[opt] == false then
            cloptions[opt] = true
        else
            optToSet = opt
        end
    elseif v:sub(1, 1) == "-" then
        for i = 2, #v do
            local opt = v:sub(i, i)
            if cloptions[opt] == nil then
                print(name..": invalid option '-"..opt.."'.")
                if cloptions.help ~= nil then
                    print("try '"..name.." --help' for more information.")
                end
                return
            else
                cloptions[opt] = true
            end
        end
    else
        table.insert(args, v)
    end
end

if cloptions.help then
    print("Usage: "..name.." [OPTION]... [DIR]")
    print("List all entries in the specified DIRectory, or cwd if not specified")
    print("\nOptions:")
    print(" -a                 Do not ignore entries starting with .")
    print(" -h                 with -l, print sizes in a human readble format")
    print(" -l                 Use a long listing format")
    print(" --help         Display this help and exit")
    return
end

local fs = require("sys.fs")
local dir = (args[1] or "")
if dir:sub(1, 1) ~= "/" then
    dir = syscall.getcwd().."/"..dir
end

if dir:sub(#dir, #dir) ~= "/" then
    dir = dir.."/"
end

if not fs.isDir(dir) then
    print(name..": Cannot access '"..args[1].."': No such directory.")
    return
end


local screenSizeStr = syscall.devctl(1, "size")
local sizeX = tonumber(screenSizeStr:sub(1, screenSizeStr:find(";")-1))
local sizeY = tonumber(screenSizeStr:sub(screenSizeStr:find(";")+1))

local list = fs.list(dir)
if not cloptions.a then
    for i = #list, 1, -1 do
        if list[i]:sub(1, 1) == "." then
            table.remove(list, i)
        end
    end
end

local colWidth = 0
local numCols = 1
if not cloptions.l then
    for _, item in pairs(list) do
        if #item + 2 > colWidth then
            colWidth = #item + 2
        end
    end
    numCols = math.floor(sizeX / colWidth)
end

local sizePrefixes = {"K", "M", "G"}

for i,v in ipairs(list) do
    local fileStats = syscall.stat(dir..v)
    local isDir = fs.isDir(dir..v)
    if cloptions.l then
        if isDir then
            printInline("d")
        else
            printInline("-")
        end
        printInline("------ ")
        printInline(fileStats.owner.." ")
        printInline(fileStats.group.." ")
        local size = fileStats.size
        if cloptions.h then
            local scale = 0
            while size > 1024 do
                size = size / 1024
                scale = scale + 1
            end
            if scale > 0 then
                if size < 10 then
                    size = math.floor(size).."."..math.floor((size * 10) % 10)..sizePrefixes[scale]
                else
                    size = math.floor(size)..sizePrefixes[scale]
                end
            end
        end
        printInline(size.." ")
        printInline(math.floor(fileStats.modified / 1000).." ")
    end
    if isDir then
        syscall.devctl(1,"sfgc",4)
    else
        syscall.devctl(1,"sfgc",1)
    end
    printInline(v)
    printInline((" "):rep(colWidth - #v))
    syscall.devctl(1,"sfgc",1)
    if i % numCols == 0 then
        print("")
    end
end
if #list % numCols ~= 0 then
    print("")
end