local function printUsage()
    local programName = fs.getName(shell.getRunningProgram())
    print("Usages:")
    print(programName .. " put <path> <project name>")
    print(programName .. " get <project name> <path>")
    print(programName .. " run <project name> <arguments>")
end

local tArgs = { ... }
if #tArgs < 2 then
    printUsage()
    return
end

if not http then
    printError("LevelStore requires the http API")
    printError("Set http.enabled to true in CC: Tweaked's config")
    return
end

local function fread(file)
    local f = fs.open(file,"r")
    local o = f.readAll()
    f.close()
    return o
end

local function fwrite(file,content)
    local f = fs.open(file,"w")
    f.write(content)
    f.close()
    return true
end

--local hpost = function(...) print(...) return http.post(...) end
local hpost = http.post

local function getField(thing,fieldname)
    if string.find(thing,"<"..fieldname..">",1,true) ~= nil and string.find(thing,"</"..fieldname..">",1,true) ~= nil then
        begin = nil
        ending = nil
        trash,begin = string.find(thing,"<"..fieldname..">",1,true)
        ending,ending2 = string.find(thing,"</"..fieldname..">",begin+1,true)
        if begin ~= nil and ending ~= nil then
            return string.sub(thing,begin+1,ending-1),string.sub(thing,1,trash-1)..string.sub(thing,ending2+1,string.len(thing))
        end
    end
    return nil
end

local rType

local function download(name,pth,saveto,run)
    local f = hpost("https://level.eu5.net/sGet.php","path="..textutils.urlEncode(pth).."&"..rType.."="..textutils.urlEncode(name)).readAll()
    if f and f ~= "409" and f ~= "403" and f ~= "401" then
    	if run then
    		return f
    	else
        	fwrite(saveto,f)
        	return true
        end
    else
        return false
    end
end


local function get(name)

    write("Connecting to LevelStore... ")

    rType = "code"
    local response, err = hpost("https://level.eu5.net/sGet.php","path="..textutils.urlEncode("").."&code="..textutils.urlEncode(name))

    if not response then
    	rType = "name"
    	response, err = hpost("https://level.eu5.net/sGet.php","path="..textutils.urlEncode("").."&name="..textutils.urlEncode(name))
    end

    if response then
    	local tree = {}
	    local folders = {}
	    local function searchFolder(folder)
	        --print("Searching folder root/"..folder)
	        local f = hpost("https://level.eu5.net/sGet.php","path="..textutils.urlEncode(folder).."&"..rType.."="..textutils.urlEncode(name)).readAll()
	        --print(f)
	        local f2 = f
	        while true do
	            local file = nil
	            file,f = getField(f,"file")
	            if not file then
	                break
	            else
	                local name = getField(file,"name")
	                tree[#tree+1] = fs.combine(folder,name)
	                --print("Found "..fs.combine(folder,name))
	            end
	        end
	        f = f2
	        while true do
	            local file = nil
	            file,f = getField(f,"folder")
	            if not file then
	                break
	            else
	                local name = getField(file,"name")
	                --if not fs.exists(fs.combine(folder,name)) then
	                    --fs.makeDir(fs.combine(folder,name))
	                --end
	                folders[#folders+1] = fs.combine(folder,name)
	                searchFolder(fs.combine(folder,name))
	            end
	        end
	        return true
	    end
	    searchFolder("")
        print("Success.")

        return tree,folders
    else
        write("Failed.\n")
        print(err)
    end
end

local sCommand = tArgs[1]
if sCommand == "put" then
	if #tArgs < 3 then
		printUsage()
		return
	end
	if not lOS.userID then
		print("Not logged in")
		print("Please have an active instance of LevelCloud running")
		return
	end


    local sFile = tArgs[2]
    local sPath = shell.resolve(fs.combine("User/Cloud",sFile))
    if not fs.exists(sPath) or not string.find(sPath,"User/Cloud") then
        print("Path not found")
        print("Note: provide a relative path to a file or folder starting from cloud")
        return
    end

    local sName = string.gsub(tArgs[3]," ","_")

    write("Connecting to LevelStore... ")
    local response = http.post(
        "https://level.eu5.net/sProject.php",
        "path="..textutils.urlEncode(tArgs[2])..
        "&title="..textutils.urlEncode(sName)..
        "&timestamp="..textutils.urlEncode(tostring(os.epoch("utc")))..
        "&direct="..textutils.urlEncode("false"),
        {
        	Cookie = lOS.userID
        }
    )

    if response then
        print("Success.")

        local sResponse = response.readAll()
        response.close()

        print("Uploaded as " .. sResponse)
        print("Run \"lStore get " .. sName .. "\" or \"lStore get " .. sResponse .. "\" to download anywhere")

    else
        print("Failed.")
    end

elseif sCommand == "get" then

    if #tArgs < 3 then
        printUsage()
        return
    end

    -- Determine file to download
    local sCode = tArgs[2]
    local sFile = tArgs[3]
    local sPath = shell.resolve(sFile)
    if fs.exists(sPath) then
        print("Path already exists")
        return
    end

    local tree,folders = get(sCode)
    term.write("Downloading... ")
    local x,y = term.getCursorPos()
    term.write("0%")
    if #tree > 1 or #folders > 0 then
    	fs.makeDir(sPath)
    	for f=1,#folders do
    		fs.makeDir(fs.combine(sPath,folders[f]))
    	end
    	for f=1,#tree do
    		download(sCode,tree[f],fs.combine(sPath,tree[f]))
    		term.setCursorPos(x,y)
    		term.write(math.ceil((f/#tree)*100+0.5).."%")
    	end
    else
    	download(sCode,tree[1],sPath)
    end
    term.setCursorPos(x,y)
    print("100%")
    print("Downloaded as " .. sFile)
elseif sCommand == "run" then
    local sCode = tArgs[2]
    local res
    local tree,folders = get(sCode)
    if #tree > 1 or #folders > 0 then
    	print("This project must be downloaded to run.")
    	return
    else
    	--print(textutils.serialize(tree))
    	res = download(sCode,tree[1],"",true)
    end
    if res then
        local func, err = load(res, sCode, "t", _ENV)
        if not func then
            printError(err)
            return
        end
        local success, msg = pcall(func, select(3, ...))
        if not success then
            printError(msg)
        end
    end
else
    printUsage()
    return
end