local terminal = term.current()
local deskIcons = lUtils.asset.load("LevelOS/assets/Desktop_Icons.limg")
local desktop = {}
local idReference = {}
local fc = fs.combine

local function locateEntry(tTable,tEntry)
	if type(tTable) ~= "table" then
		error("Invalid input #1",2)
	end
    for t=1,#tTable do
        if tTable[t] == tEntry then
            return true,t
        end
    end
    return false,0
end

local fileTypes
if fs.exists("LevelOS/data/formats.lconf") then
	fileTypes = lUtils.asset.load("LevelOS/data/formats.lconf")
end

if not fileTypes then
	local copy = lUtils.instantiate
	fileTypes = {
		_VERSION="1.3",
		
		[""] = {
			name="File",
			program="Lua",
			contextMenu={
				{"Execute","Edit"},
				{"Lua","rom/programs/edit.lua"}
			},
			openWith={
				"Lua",
				"rom/programs/edit.lua"
			},
			icon=deskIcons[1]
		},
		
		lua = {
			name="Lua script",
			program="Lua",
			contextMenu={
				{"Execute","Edit"},
				{"Lua","rom/programs/edit.lua"}
			},
			openWith={
				"Lua",
				"rom/programs/edit.lua"
			},
			icon=deskIcons[2],
			emptyFilePreset=""
		},
		
		txt = {
			name="Text file",
			program="LevelOS/notepad.lua",
			contextMenu={
				{"Edit"},
				{"LevelOS/notepad.lua"}
			},
			openWith={
				"LevelOS/notepad.lua",
				"rom/programs/edit.lua"
			},
			icon=deskIcons[5],
			emptyFilePreset=""
		},
		
		lconf = {
			name="Config file",
			program="LevelOS/notepad.lua",
			contextMenu={
				{"Edit"},
				{"LevelOS/notepad.lua"}
			},
			openWith={
				"LevelOS/notepad.lua",
				"rom/programs/edit.lua"
			},
			icon=deskIcons[6],
			emptyFilePreset="{}"
		},

		sgui = {
			name="Shapescape GUI",
			program="Program_Files/Shapescape",
			contextMenu={
				{"Open","Execute"},
				{"Program_Files/Shapescape","Lua"}
			},
			openWith={
				"Lua",
				"Program_Files/Shapescape",
				"rom/programs/edit.lua"
			},
			icon=deskIcons[8],
			emptyFilePreset="return {assets={},slides={{contextMenu=1,objs={},w=51,h=19}}}"
		},

		sml = {
			name="SML Document",
			program="Program_Files/sml",
			contextMenu={
				{"Open","Edit"},
				{"Program_Files/sml","rom/programs/edit.lua"}
			},
			openWith={
				"Program_Files/sml",
				"rom/programs/edit.lua"
			},
			icon=deskIcons[9],
			emptyFilePreset=""
		},

		limg  = {
			name="Image",
			program="LevelOS/imageviewer.lua",
			contextMenu={
				{"View","Edit"},
				{"LevelOS/imageviewer.lua","rom/programs/edit.lua"}
			},
			openWith={
				"LevelOS/imageviewer.lua",
				"rom/programs/edit.lua"
			},
			icon=copy(deskIcons[10])
		},

		bimg  = {
			name="Image",
			program="LevelOS/imageviewer.lua",
			contextMenu={
				{"View","Edit"},
				{"LevelOS/imageviewer.lua","rom/programs/edit.lua"}
			},
			openWith={
				"LevelOS/imageviewer.lua",
				"rom/programs/edit.lua"
			},
			icon=copy(deskIcons[10])
		},

		nfp   = {
			name="NFP Image",
			program="LevelOS/imageviewer.lua",
			contextMenu={
				{"View","Edit"},
				{"LevelOS/imageviewer.lua","rom/programs/fun/advanced/paint.lua"}
			},
			openWith={
				"LevelOS/imageviewer.lua",
				"rom/programs/fun/advanced/paint.lua",
				"rom/programs/edit.lua"
			},
			icon=copy(deskIcons[10]),
			emptyFilePreset=""
		},

		nfg = {
			name="Animation",
			program="LevelOS/imageviewer.lua",
			contextMenu={
				{"View","Edit"},
				{"LevelOS/imageviewer.lua","rom/programs/edit.lua"}
			},
			openWith={
				"LevelOS/imageviewer.lua",
				"rom/programs/edit.lua"
			},
			icon=copy(deskIcons[10])
		},
	}

	lUtils.asset.save(lUtils.instantiate(fileTypes),"LevelOS/data/formats.lconf", false)

end

if fileTypes._VERSION == "1.0" then
	for k,v in pairs(fileTypes) do
		if type(v) == "table" then
			v.name = v.name or v.n
			v.n = nil
			v.program = v.program or v.p
			v.p = nil
			v.icon = v.icon or v.i
			v.i = nil
			v.contextMenu = v.contextMenu or v.c
			v.c = nil
			v.openWith = v.openWith or v.o
			v.o = nil
			v.emptyFilePreset = v.emptyFilePreset or v.e
		end
	end
	fileTypes._VERSION = "1.1"
	fileTypes["llnk"] = {name="Shortcut",program="Lua"}
	lUtils.asset.save(lUtils.instantiate(fileTypes),"LevelOS/data/formats.lconf")
end
if fileTypes._VERSION == "1.1" then
	for k,v in pairs(fileTypes) do
		if type(v) == "table" then
			v._VERSION = nil
		end
	end
	for k,v in pairs(fileTypes.nfp.openWith) do
		if v == "rom/programs/fun/paint.lua" then
			fileTypes.nfp.openWith[k] = "rom/programs/fun/advanced/paint.lua"
		end
	end
	fileTypes._VERSION = "1.2"
	lUtils.asset.save(lUtils.instantiate(fileTypes),"LevelOS/data/formats.lconf",false)
end
if fileTypes._VERSION == "1.2" then
	fileTypes.bimg = {
		name="Image",
		program="LevelOS/imageviewer.lua",
		contextMenu={
			{"View","Edit"},
			{"LevelOS/imageviewer.lua","rom/programs/edit.lua"}
		},
		openWith={
			"LevelOS/imageviewer.lua",
			"rom/programs/edit.lua"
		},
		icon=deskIcons[10]
	}
	fileTypes._VERSION = "1.3"
	lUtils.asset.save(lUtils.instantiate(fileTypes),"LevelOS/data/formats.lconf",false)
end
local dConfig
if not lOS.explorer then lOS.explorer = {} end
lOS.explorer.shortcache = {}
lOS.explorer.imgcache = {}
lOS.explorer.nimgcache = {}
lOS.explorer.desktopBackground = nil
lOS.fClipboard = {}

local disks = {}
lOS.explorer.disks = disks
local function reloadDisks()
	for k,v in pairs(disks) do
		disks[k] = nil
	end
	local ndisks = {peripheral.find("drive",function(name,object) return object.hasData() end)}
	for t=1,#ndisks do
		ndisks[ndisks[t].getMountPath()] = ndisks[t]
	end
	for k,v in pairs(ndisks) do
		disks[k] = v
	end
end
reloadDisks()

local function getName(path)
	local isDisk = false
	if disks[path] and disks[path].getDiskLabel() then
		str = disks[path].getDiskLabel().." ("..string.gsub(path,"_"," ")..")"
		isDisk = true
	elseif path == "" then
		str = "Local disk"
	else
		str = string.gsub(fs.getName(path),"_"," ")
		if lUtils.getFileType(str) == ".llnk" then
			str = str:sub(1,#str-5)
		end
	end
	return str,isDisk
end

lOS.explorer.getName = getName

local symbols = {
	["User/Cloud"]     = {symbol="",color=colors.blue},
	[""]               = {symbol="",color=colors.lightGray},
	["rom"]            = {symbol="",color=colors.red},
	["User"]           = {symbol="",color=colors.lightBlue},
	["User/Desktop"]   = {symbol="",color=colors.lightBlue},
	["User/Documents"] = {symbol="",color=colors.lightGray},
	["User/Downloads"] = {symbol="",color=colors.blue},
	["User/Images"]    = {symbol="",color=colors.lightBlue},
	["User/Scripts"]   = {symbol="",color=colors.cyan},
	["User/Games"]     = {symbol="",color=colors.lightGray},
	["User/Music"]     = {symbol="",color=colors.blue},
}

lOS.explorer.getIcon = function(path)
	local disks = {peripheral.find("drive",function(name,object) return object.hasData() end)}
	for t=1,#disks do
		disks[disks[t].getMountPath()] = disks[t]
	end
	if symbols[path] then
		return symbols[path].symbol, symbols[path].color
	elseif disks[path] then
		return "", colors.blue
	elseif fs.isDir(path) then
		return "\143", colors.yellow
	else
		return "\143", colors.white
	end
end

local function genFile(f)
	if not fs.exists(f) then
		error(f.." does not exist",2)
	end
	local file = {path=f,name=fs.getName(f),type=lUtils.getFileType(f):sub(2),readOnly=fs.isReadOnly(f),isDir=fs.isDir(f)}
	if not ((file.isDir and file.readOnly) or disks[file.path]) then
		local a = fs.attributes(f)
		for k,v in pairs(a) do
			file[k] = v
		end
	end
	return file
end

local function uFP(filepath2) -- unique filepath
	if fs.exists(filepath2) == true then
		t = 1
		while fs.exists(string.sub(filepath2,1,string.len(filepath2)-string.len(lUtils.getFileType(filepath2))).."_("..t..")"..lUtils.getFileType(filepath2)) == true do
			t = t+1
		end
		filepath2 = string.sub(filepath2,1,string.len(filepath2)-string.len(lUtils.getFileType(filepath2))).."_("..t..")"..lUtils.getFileType(filepath2)
	end
	return filepath2
end
lOS.explorer.uFP = uFP

function lOS.genIco(path)
	local name = getName(path)
	if fs.isDir(path) and fs.exists(fs.combine(path,"main.lua")) then
		path = fs.combine(path,"main.lua")
	end
	local pth = fs.combine("User/Desktop",name..".llnk")
	lUtils.asset.save({path},pth)
	os.queueEvent("explorer_reload")
end

local presetIcons = {
	["User"] = deskIcons[12],
	["User/Desktop"] = deskIcons[13],
	["User/Documents"] = deskIcons[14],
	["User/Downloads"] = deskIcons[15],
	["User/Games"] = deskIcons[16],
	["User/Images"] = deskIcons[17],
	["User/Music"] = deskIcons[18],
	["User/Scripts"] = deskIcons[19],
	["User/Cloud"] = deskIcons[20],
	["rom"] = deskIcons[21],
}
function lOS.explorer.drawIcon(path,fx,fy,onlyIcon,transparent,maxLines,shortcutIcon)
	--local file = {path=path,type=lUtils.getFileType(path):sub(2)}
	local ok,file = pcall(genFile,path)
	if not ok then
		lUtils.renderImg(deskIcons[11],fx+2,fy+1,nil,transparent)
		return
	end
	local bg = term.getBackgroundColor()
	local fg = term.getTextColor()
	local cTerm = term.current()
	local isCut = false
	if lOS.fCut then
		isCut = locateEntry(lOS.fCut,file.path)
	end
	local shortcache = lOS.explorer.shortcache
	local imgcache = lOS.explorer.imgcache
	local nimgcache = lOS.explorer.nimgcache
	local fc = fs.combine
	local rPath = path
	local rType = file.type
	local isShort = false
	local lines = lUtils.wordwrap(lUtils.getFileName(file.path),7)
	local lineH = math.min(#lines,4)
	local fw,fh = 7,5
	if #lines > lineH then
		lines[4] = lines[4]:sub(1,5)..".."
	end
	fh = math.max(4+lineH,fh)
	if not transparent then
		lOS.boxClear(fx,fy,fx+7-1,fy+5-1+lineH-1)
	end
	if shortcache[file.path] then
		isShort = true
		rPath = shortcache[file.path][1]
		rType = lUtils.getFileType(rPath):sub(2)
	elseif file.type == "llnk" then
		local info = lUtils.asset.load(file.path)
		if info and type(info[1]) == "string" then
			isShort = true
			rPath = info[1]
			if not fs.exists(rPath) then
				imgcache[file.path] = {}
				for i=0,15 do
					imgcache[file.path][i] = deskIcons[4]
				end
			else
				rType = lUtils.getFileType(info[1]):sub(2)
				imgcache[file.path] = {}
				for i=0,15 do
					imgcache[file.path][i] = info.icon
				end
			end
			shortcache[file.path] = info
		end
	end
	local pFolder = fs.getDir(rPath)
	if not isCut then
		if not fs.exists(rPath) then
			lUtils.renderImg(deskIcons[4],fx+2,fy+1,nil,transparent)
		elseif presetIcons[rPath] then
			lUtils.renderImg(presetIcons[rPath],fx+2,fy+1,nil,transparent)
		elseif imgcache[file.path] and imgcache[file.path][bg] then
			local win = imgcache[file.path][bg]
			if win.reposition then
				for t=1,3 do
					term.setCursorPos(fx+2,fy+t)
					term.blit(win.getLine(t))
				end
			else
				lUtils.renderImg(win,fx+2,fy+1,nil,transparent)
			end
		elseif fs.getName(rPath) == "main.lua" --[[and fs.exists(fc(pFolder,"icon.limg"))]] then
			if not nimgcache[file.path] and (fs.exists(fc(pFolder,"icon.limg")) or fs.exists(fc(pFolder,"icon.bimg"))) then
				local img
				if fs.exists(fc(pFolder,"icon.limg")) then
					img = lUtils.asset.load(fc(pFolder,"icon.limg"))
				else
					img = lUtils.asset.load(fc(pFolder,"icon.bimg"))
				end
				img = img[1]
				local iw = #img[1][1]
				local ih = #img
				if iw <= 3 and ih <= 3 then
					--[[local tWin = window.create(cTerm,fx+2,fy+1,iw,ih,true)
					term.redirect(tWin)
					lUtils.renderImg(img,1,1)
					term.redirect(cTerm)
					imgcache[file.path] = tWin]]
					if not imgcache[file.path] then
						imgcache[file.path] = {}
					end
					imgcache[file.path][bg] = img
					lUtils.renderImg(img,fx+2,fy+1,nil,transparent)
				else
					nimgcache[file.path] = true
				end
			else
				lUtils.renderImg(deskIcons[3],fx+2,fy+1,nil,transparent)
			end
		elseif fs.isDir(rPath) then
			if not nimgcache[file.path] and (fs.exists(fc(rPath,"icon.limg")) or fs.exists(fc(rPath,"icon.bimg"))) and fs.exists(fc(rPath,"main.lua")) then
				local img
				if fs.exists(fc(rPath,"icon.limg")) then
					img = lUtils.asset.load(fc(rPath,"icon.limg"))
				else
					img = lUtils.asset.load(fc(rPath,"icon.bimg"))
				end
				img = img[1]
				local iw = #img[1][1]
				local ih = #img
				if iw <= 3 and ih <= 3 then
					local tWin = window.create(cTerm,fx+2,fy+1,iw,ih,true)
					term.redirect(tWin)
					if transparent then
						for y=1,2 do
							local line = {cTerm.getLine(fy+y)}
							for t=1,3 do
								line[t] = line[t]:sub(fx+2,fx+4)
							end
							term.setCursorPos(1,y)
							term.blit(unpack(line))
						end
					else
						term.setBackgroundColor(bg)
						term.clear()
					end
					lUtils.renderImg(img,1,1,nil,transparent)
					term.setBackgroundColor(colors.yellow)
					term.setCursorPos(1,3)
					term.write("   ")
					term.redirect(cTerm)
					if not imgcache[file.path] then
						imgcache[file.path] = {}
					end
					imgcache[file.path][bg] = tWin
				else
					nimgcache[file.path] = true
				end
			else
				lUtils.renderImg(deskIcons[7],fx+2,fy+1,nil,transparent)
			end
		elseif ((rType == "limg" or file.type == "bimg") and lUtils.asset.load(rPath)) or rType == "nfp" then
			local iw,ih
			local img
			if rType == "nfp" then
				img = lUtils.fread(rPath)
				ih = 0
				iw = 0
				for line in img:gmatch("([^\n]*)\n?") do
					iw = math.max(iw,#line)
					ih = ih+1
				end
			else
				img = lUtils.asset.load(rPath)
				img = img[1]
				iw = #img[1][1]
				ih = #img
			end
			local tWin = window.create(cTerm,1,1,iw,ih,false)
			term.redirect(tWin)
			term.setBackgroundColor(bg)
			term.clear()
			lUtils.renderImg(img,1,1)
			term.redirect(cTerm)
			if not imgcache[file.path] then
				imgcache[file.path] = {}
			end
			if iw <= 3 and ih <= 3 then
				imgcache[file.path][bg] = img
				lUtils.renderImg(img,fx+2,fy+1,nil,transparent)
			else
				local lWin = lUtils.littlewin(tWin,6,math.floor(9*(ih/iw)+0.5))
				local fWin = window.create(cTerm,fx+2,fy+1,3,3,true)
				--_G.debuglwin[file.path] = {lWin=lWin,tWin=tWin,img=img}
				term.redirect(fWin)
				local win = blittle.createWindow(fWin,1,1,3,3,true)
				term.redirect(win)
				if transparent then
					for y=1,3 do
						local line = {cTerm.getLine(fy+y)}
						for t=1,3 do
							line[t] = line[t]:sub(fx+2,fx+4)
						end
						term.setCursorPos(1,y)
						term.blit(unpack(line))
					end
				else
					term.setBackgroundColor(bg)
					term.clear()
				end
				lWin.render(1,1)
				term.redirect(fWin)
				win.redraw()
				term.redirect(cTerm)
				fWin.redraw()
				imgcache[file.path][bg] = fWin
			end
		elseif fileTypes[rType] and fileTypes[rType].icon then
			lUtils.renderImg(fileTypes[rType].icon,fx+2,fy+1,nil,transparent)
		else
			lUtils.renderImg(deskIcons[4],fx+2,fy+1,nil,transparent)
		end
		if shortcutIcon then
			if isShort and not onlyIcon then
				term.setCursorPos(fx+2,fy+3)
				term.blit(unpack(shortcutIcon))
			elseif lOS.cloud and lOS.cloud.lastSync and lOS.cloud.files and lOS.cloud.files[file.path] then
				term.setCursorPos(fx+2,fy+3)
				local pix = {lUtils.getPixel(term.current(),fx+2,fy+3)}
				term.setBackgroundColor(lUtils.toColor(pix[3]))
				if lOS.cloud.conflicts[file.path] then
					term.setTextColor(colors.red)
					term.write("×")
				elseif file.modification > lOS.cloud.lastSync then
					term.setTextColor(colors.blue)
					term.write("\24")
				else
					term.setTextColor(colors.lime)
					term.write("\7")
				end
			end
		end
	end
	term.setBackgroundColor(bg)
	term.setTextColor(fg)
	if not onlyIcon then
		if maxLines then
			lineH = math.min(maxLines,lineH)
		end
		for l=1,lineH do
			local line = lines[l]:gsub("%s+$","")
			term.setCursorPos(fx+math.floor(fw/2-#line/2),fy+3+l)
			if transparent then
				lUtils.transWrite(line,(not dConfig.textColor))
			else
				term.write(line)
			end
		end
	end
	return fh
end

dConfig = {_VERSION=1,files={},sizes={},shortcutIcon=true,background={color=colors.white}}
if fs.exists("LevelOS/data/desktop.lconf") then
	dConfig = lUtils.asset.load("LevelOS/data/desktop.lconf")
end

if not dConfig._VERSION then
	-- backup n shit
	if fs.exists("LevelOS/data/olddesktop.lconf") then
		fs.delete("LevelOS/data/olddesktop.lconf")
	end
	fs.move("LevelOS/data/desktop.lconf","LevelOS/data/olddesktop.lconf")
	dConfig = {_VERSION=1,files={},sizes={},shortcutIcon=true,background={color=colors.white}}
end

lOS.explorer.desktopConfig = dConfig

function lOS.save()
	lUtils.asset.save(dConfig,"LevelOS/data/desktop.lconf")
	lUtils.fwrite("LevelOS/data/settings.lconf",textutils.serialize(lOS.settings))
	return true
end

if not fs.exists("User/Desktop") then
	fs.makeDir("User/Desktop")
	-- my PC
	lUtils.asset.save(
		{
			"Program_Files/LevelOS/Explorer/main.lua",
			icon = {
				{
					"",
					"ff ",
					"  f",
				},
				{
					"",
					"f f",
					" f ",
				},
				{
					"",
					"fff",
					"   ",
				}
			},
		},
		"User/Desktop/My_PC.llnk"
	)
	-- shell
	lUtils.asset.save(
		{
			"rom/programs/shell.lua",
			icon = {
				{
					"",
					"   ",
					"fff",
				},
				{
					"",
					"f44",
					"4ff",
				},
				{
					"",
					"fff",
					"   ",
				}
			},
		},
		"User/Desktop/Shell.llnk"
	)
	local function makeShortcuts(folder)
		local ls = fs.list(folder)
		for i,f in ipairs(ls) do
			local path = fc(folder,f)
			if fs.isDir(path) then
				if fs.exists(fc(path,"main.lua")) then
					lUtils.asset.save({fc(path,"main.lua")},fc("User/Desktop",fs.getName(f))..".llnk")
				else
					makeShortcuts(path)
				end
			end
		end
	end
	makeShortcuts("Program_Files")
end


-- dConfig should be loaded after this
local currentID = 1
if not dConfig.files then dConfig.files = {} end
for id,path in pairs(dConfig.files) do
	if id >= currentID then
		currentID = id+1
	end
	idReference[path] = id
end

local desktopMap = setmetatable({}, {
  __index = function(self, id)
    local default = {}
    self[id] = default
    return default
  end
})
_G.debugdesktopmap = desktopMap

local function clearDesktopMap()
	for k,v in pairs(desktopMap) do
		desktopMap[k] = nil
	end
end

local function getDesktopSize()
	local w,h = term.getSize()
	if lOS.tbSize then
		h = h - lOS.tbSize
	end
	local deskW,deskH = math.floor((w+1)/8),math.floor(h/5)
	return deskW,deskH
end

local currentSize
do
	local desktopWidth,desktopHeight = getDesktopSize()
	currentSize = desktopWidth..","..desktopHeight
end
if not dConfig.sizes[currentSize] then
	dConfig.sizes[currentSize] = {}
end

local function reloadDesktop()

	if not fs.exists("User/Desktop") then
		fs.makeDir("User/Desktop")
	end

	local desktopFiles = fs.list("User/Desktop")
	local changed = false
	for f=1,#desktopFiles do
		local name = desktopFiles[f]

		if not idReference[name] then
			idReference[name] = currentID
			dConfig.files[currentID] = name
			currentID = currentID+1
			changed = true
		end

	end
	
	if changed then
		lUtils.asset.save(dConfig,"LevelOS/data/desktop.lconf")
	end
	-- i only need to store position, but if i store them based on names everything gets messed up if a file gets renamed...
	-- iterate through IDs too to see if theres a file there that doesnt exist anymore wait nah just do in the thing actually wait hmm

end

reloadDesktop()

local function drawBackground(background)
	for i=0,15 do
		term.setPaletteColor(2^i,term.nativePaletteColor(2^i))
	end
	if not background then
		term.setBackgroundColor(colors.white)
		term.clear()
	elseif background.path and fs.exists(background.path) then
		local col = background.color or colors.white
		local tw,th = term.getSize()
		local rImg
		local img
		local w,h
		local t = lUtils.getFileType(background.path)
		if t == ".bimg" or t == ".limg" or t == ".nfg" then
			img = lUtils.asset.load(background.path)
			rImg = img[1]
			w = #rImg[1][1]
			h = #rImg
		elseif t == ".nfp" then
			rImg = lUtils.fread(background.path)
			h = 0
			w = 0
			local emptyLine = false
			for line in rImg:gmatch("([^\n]*)\n?") do
				w = math.max(w,#line)
				h = h+1
				if line == "" then
					emptyLine = true
				else
					emptyLine = false -- only if emptyLine is at end itll be true, very good
				end
			end
			if emptyLine then -- fking craftos pc man
				h = h-1
			end
		end
		if background.resize == "stretch" then
			local tWin = window.create(term.current(),1,1,w,h,false)
			local oterm = term.current()
			term.redirect(tWin)
			term.setBackgroundColor(col)
			term.clear()
			lUtils.renderImg(rImg,1,1)
			term.redirect(oterm)
			if h/w > th/tw then -- height should overflow, width equals screen width
				local iw,ih=tw,math.floor(tw*(h/w)+0.5)
				local lWin = lUtils.littlewin(tWin,iw,ih)
				lWin.render(1,math.floor(th/2-ih/2)+1)
			else
				local iw,ih=math.floor(th*(w/h)+0.5),th
				local lWin = lUtils.littlewin(tWin,iw,ih)
				lWin.render(math.floor(tw/2-iw/2)+1,1)
			end
		elseif background.resize == "center" then
			lUtils.renderImg(rImg,math.floor(tw/2-w/2)+1,math.floor(th/2-h/2)+1,nil,true)
		elseif background.resize == "repeat" or true then
			local rw,rh = math.ceil(tw/w),math.ceil(th/h)
			local frame = 1
			for ry=0,rh-1 do
				for rx=0,rw-1 do
					if img then
						lUtils.renderImg(img[frame],1+rx*w,1+ry*h,nil,true)
						frame = frame+1
						if frame > #img then
							frame = 1
						end
					else
						lUtils.renderImg(rImg,1+rx*w,1+ry*h,nil,true)
					end
				end
			end
		end
	elseif background.color then
		term.setBackgroundColor(background.color)
		term.clear()
	end
end
local selected = {}
local drag
local oldWidth,oldHeight = getDesktopSize()
local function render(dodebug)
	term.redirect(terminal)
	-- if not position gen position
	-- make order table with IDs, then sort that table and iterate through
	local dolog


	if lOS.explorer.desktopBackground then
		local dw,dh = lOS.explorer.desktopBackground.getSize()
		local tw,th = term.getSize()
		if dh ~= th-lOS.tbSize then
			lOS.explorer.desktopBackground = nil
		else
			lOS.explorer.desktopBackground.setVisible(true)
			lOS.explorer.desktopBackground.setVisible(false)
		end
	end
	if not lOS.explorer.desktopBackground then
		local col = dConfig.background.color or colors.white
		local tw,th = term.getSize()
		th = th-lOS.tbSize
		local cTerm = term.current()
		local bWin = window.create(term.current(),1,1,tw,th,true)
		term.redirect(bWin)
		term.setBackgroundColor(col)
		term.clear()
		if dConfig.background and dConfig.background[1] and type(dConfig.background[1]) == "table" then
			for t=1,#dConfig.background do
				drawBackground(dConfig.background[t])
			end
		else
			drawBackground(dConfig.background)
		end
		term.redirect(cTerm)
		lOS.explorer.desktopBackground = bWin
		lOS.explorer.desktopBackground.setVisible(false)
	end

	term.setTextColor(dConfig.textColor or colors.black)
	local newWidth,newHeight = getDesktopSize()
	if oldWidth ~= newWidth or oldHeight ~= newHeight then
		currentSize = newWidth..","..newHeight
		oldWidth = newWidth
		oldHeight = newHeight
		if not dConfig.sizes[currentSize] then
			dConfig.sizes[currentSize] = {}
		end
		clearDesktopMap()
	end
	local order = {}
	for path,id in pairs(idReference) do
		local absolutePath = fc("User/Desktop",path)
		if not fs.exists(absolutePath) then
			if dConfig.sizes[currentSize][id] then
				local self = dConfig.sizes[currentSize][id]
				if desktopMap[self.x] then
					desktopMap[self.x][self.y] = nil
				end
				dConfig.sizes[currentSize][id] = nil
			end
			idReference[path] = nil
			dConfig.files[id] = nil
		else
			table.insert(order,id)
		end
	end
	table.sort(order)
	local icons = dConfig.sizes[currentSize]
	for i=1,#order do
		local id = order[i]
		if not icons[id] then
			icons[id] = {}
		end
		if not icons[id].x or not icons[id].y then
			local x,y = 1,1
			local success = true
			while desktopMap[x][y] do
				y = y+1
				if y > newHeight then
					y = 1
					x = x+1
					if x > newWidth then
						success = false
						break
					end
				end
			end
			if success then
				icons[id].x,icons[id].y = x,y
				desktopMap[x][y] = id
			end
		end
		if icons[id].x and icons[id].y and not selected[id] then
			local x,y = icons[id].x,icons[id].y
			desktopMap[x][y] = id
			local path = fc("User/Desktop",dConfig.files[id])
			local maxLines = 1
			term.setBackgroundColor(colors.white)
			lOS.explorer.drawIcon(path,1+(x-1)*8,1+(y-1)*5,false,true,maxLines,{"\24","0","8"})
		end
		--os.sleep(0.5)
	end
	for id,v in pairs(selected) do
		if not icons[id] then
			selected[id] = nil
		else
			local x,y = icons[id].x,icons[id].y
			local path = fc("User/Desktop",dConfig.files[id])
			local maxLines = 4
			term.setBackgroundColor(colors.lightBlue)
			lOS.explorer.drawIcon(path,1+(x-1)*8,1+(y-1)*5,false,false,maxLines,{"\24","0","8"})
		end
	end
	if drag and drag.moved then
		lOS.explorer.drawIcon(fc("User/Desktop",dConfig.files[drag.id]),drag.x-drag.ox,drag.y-drag.oy,false,true,1,{"\24","0","8"})
	end
end


-- CONTEXT MENU FUNCTIONS

local fTypes = fileTypes
local function fExec(obj)
	local f = obj.file
	--[[local num = obj.num
	local p = fTypes[f.type].c[2][num]]
	local p = obj.p
	if p == "Lua" then
		lOS.execute(f.path)
	else
		lOS.execute(p.." "..f.path)
	end
end
lOS.explorer.fExec = fExec

local function fOpenWin(obj)
	local f = obj.file
	lOS.execute("Program_Files/LevelOS/Explorer "..f.path)
end
lOS.explorer.fOpenWin = fOpenWin

function lOS.explorer.fRename(obj,s,sl,render,LevelOS,isDesktop)
	if type(obj) == "string" then
		if isDesktop then
			for i,v in pairs(dConfig.sizes[currentSize]) do
				_G.debugcompare = {}
				if obj == fs.combine("User/Desktop",dConfig.files[i]) then
					local f = genFile(obj)
					local x,y = v.x,v.y
					f.x1,f.y1 = 1+(x-1)*8,1+(y-1)*5
					local lineH = math.min(#lUtils.wordwrap(lUtils.getFileName(f.path),7),4)
					f.x2,f.y2 = f.x1+6,f.y1+3+lineH
					obj = {file=f}
					break
				end
				table.insert(debugcompare,{obj,fs.combine("User/Desktop",dConfig.files[i])})
			end
			if type(obj) == "string" then
				error("not found")
			end
		else
			for k,v in ipairs(sl.files) do
				if v.path == obj then
					obj = {file=v}
					break
				end
			end
		end
	end
	LevelOS.overlay = nil
	local f = obj.file
	sl.renaming = f.path
	if isDesktop then
		term.setBackgroundColor(colors.white)
		term.setTextColor(colors.black)
	else
		term.setBackgroundColor(colors.pink)
		opink = {s.win.getPaletteColor(colors.pink)}
		sl.opink = opink
		s.win.setPaletteColor(colors.pink,0.15,0.15,0.15)
		term.setTextColor(colors.white)
	end
	local fname
	local isShortcut = false
	if lUtils.getFileType(f.path) == ".llnk" then
		fname = lUtils.getFileName(f.path,false)
		isShortcut = true
	else
		fname = lUtils.getFileName(f.path,true)
	end
	fname = fname:gsub(" ","_")
	local w,h = term.getSize()
	if sl.rMode == 1 then
		sl.renamebox = lUtils.input(sl.NAME.x+2,f.y2,sl.NAME.x+sl.NAME.width-2,f.y2,{overflowX="scroll",overflowY="none",text=fname,selectColor=colors.blue})
		sl.renamebox.x2 = math.min(math.max(sl.NAME.width,#sl.renamebox.txt+5),w)
	else
		sl.renamebox = lUtils.input(f.x1,f.y1+4,f.x2,f.y2,{overflowX="scroll",overflowY="none",text=fname,selectColor=colors.blue}) -- ah fuck ah FCK shit fuck
		if isDesktop then
			sl.renamebox.opt.selectTxtColor = colors.white
		end
		-- put renamebox in sl or something i guess FUCK why did i make it this way
	end
	local renamebox = sl.renamebox
	renamebox.isShortcut = isShortcut
	renamebox.scrollX = 0
	renamebox.state = true
	local ext = lUtils.getFileType(f.path)
	if ext == ".llnk" then
		ext = ""
	end
	renamebox.select = {1,#fname-#ext}
	renamebox.cursor.a = 1+#fname-#ext
	renamebox.cursor.x = renamebox.cursor.a
	renamebox.update("timer")
	local ok,err = pcall(function() render(true) end)
	if not ok then
		lOS.bsod(err)
	end
	renamebox.render()
	os.queueEvent("renamebox")
end

local function fInvShort(obj,updateFiles,render)
	local o = {lUtils.popup("Problem with shortcut","The item '"..obj.file.sName.."' that this shortcut refers to has been changed or moved, so this shortcut will no longer work properly.\n\nDo you want to delete this shortcut?",37,13,{"Yes","No"})}
	if o[1] and o[3] == "Yes" then
		fs.delete(obj.file.path)
		updateFiles()
	end
	term.setTextColor(colors.white)
	render()
end
lOS.explorer.fInvShort = fInvShort

local function genContextMenu(f,s,sl,selected,updateFiles,render,LevelOS,isDesktop)
	local shortcache = lOS.explorer.shortcache
	local winObj = term.current()

	local function fInvShortInternal(obj)
		term.redirect(winObj)
		LevelOS.overlay = nil
		lOS.noEvents = false
		LevelOS.self.window.events = nil
		fInvShort(obj,updateFiles,render)
		term.setTextColor(colors.white)
	end

	local function fDelete(obj)
		for k,v in pairs(selected) do
			fs.delete(k)
		end
		selected = {}
		updateFiles()
	end

	local function fOpen(obj)
		local f = obj.file
		selected = {}
		sl.folder = f.path
		updateFiles()
		scrollY = 0
	end

	local function fCut(obj)
		lOS.fClipboard = {}
		for k,v in pairs(selected) do
			table.insert(lOS.fClipboard,k)
		end
		lOS.fCut = lUtils.instantiate(lOS.fClipboard)
		selected = {}
	end

	local function fCopy(obj)
		lOS.fClipboard = {}
		lOS.fCut = {}
		for k,v in pairs(selected) do
			table.insert(lOS.fClipboard,k)
		end
	end

	local function fPaste(obj)
		local tFolder = sl.folder
		for c=1,#lOS.fClipboard do
			if fs.exists(lOS.fClipboard[c]) == true then
				fs.copy(lOS.fClipboard[c],uFP(fs.combine(tFolder,fs.getName(lOS.fClipboard[c]))))
			end
			if locateEntry(lOS.fCut,lOS.fClipboard[c]) == true then
				fs.delete(lOS.fClipboard[c])
				table.remove(lOS.fCut,({locateEntry(lOS.fCut,lOS.fClipboard[c])})[2])
			end
		end
		lOS.fClipboard = {}
		lOS.fCut = {}
		updateFiles()
	end

	local opink
	local function fRename(obj)
		lOS.explorer.fRename(obj,s,sl,render,LevelOS,isDesktop)
		if isDesktop then
			local renamebox = sl.renamebox
			term.redirect(terminal)
			render()
			renamebox.render()
			lOS.noEvents = false
			while true do
				local e = {os.pullEventRaw()}
				if e[1] == "char" and e[2] == " " then
					e[2] = "_"
				end
				if e[1] == "key" and e[2] == keys.enter then
					renamebox.state = false
					--sl.renaming = nil
				else
					renamebox.update(unpack(e))
					--render()
					renamebox.render()
				end
				if not renamebox.state then
					local pth = fs.combine("User/Desktop",renamebox.txt)
					if renamebox.isShortcut then
						pth = pth..".llnk"
					end
					if pth == sl.renaming or fs.combine(pth,"") == "User/Desktop" then
						-- nothing
					elseif fs.exists(pth) then
						local newPth = uFP(pth)
						local r = {lUtils.popup("Rename File","Do you want to rename \""..fs.getName(sl.renaming):gsub("_"," ").."\" to \""..fs.getName(newPth):gsub("_"," ").."\"?\n\nThere is already a file with the same name in this location.",41,11,{"Yes","No"})}
						if r[1] and r[3] == "Yes" then
							fs.move(sl.renaming,newPth)
						end
					else
						fs.move(sl.renaming,pth)
					end
					renamebox = nil
					sl.renamebox = nil
					sl.renaming = nil
					term.setCursorBlink(false)
					updateFiles()
					render()
					break
				end
			end
		end
	end

	local function fNew(obj)
		local pth = uFP(fs.combine(sl.folder,"New_"..obj.txt:gsub(" ","_").."."..obj.format))
		lUtils.fwrite(pth,obj.preset)
		term.redirect(winObj)
		updateFiles()
		render()
		fRename(pth)
		-- rename
	end

	local function fNewFolder(obj)
		local pth = uFP(fs.combine(sl.folder,"New_Folder"))
		fs.makeDir(pth)
		term.redirect(winObj)
		updateFiles()
		render()
		fRename(pth)
		-- rename
	end

	local function fOpenWith(obj)
		if LevelOS and LevelOS.self and LevelOS.self.window then
			LevelOS.self.window.events = nil
		end
		LevelOS.overlay = nil
		lOS.noEvents = false
		local p = sl.openWith(obj.file)
		if p then
			p = p.path
			local f = obj.file
			if p == "Lua" then
				lOS.execute(f.path)
			else
				lOS.execute(p.." "..f.path)
			end
		end
	end

	local function fPin(obj)
		table.insert(sl.config.quickaccess,obj.file.path)
		sl.saveConfig()
		sl.reloadQuickAccess()
	end

	local function fUnpin(obj)
		local s,i = locateEntry(sl.config.quickaccess,obj.file.path)
		if s then
			table.remove(sl.config.quickaccess,i)
			sl.saveConfig()
			sl.reloadQuickAccess()
		end
	end

	local function fShortcut(obj)
		local pth = uFP(fs.combine(obj.folder,obj.name:gsub(" ","_").."_-_Shortcut.llnk"))
		lUtils.asset.save({obj.file.path},pth)
		updateFiles()
		render()
	end

	local function fDesktopShortcut(obj)
		lOS.genIco(obj.file.path)
		--[[local pth = uFP(fs.combine(obj.folder,obj.name:gsub(" ","_")..".llnk"))
		lUtils.asset.save({obj.file.path},pth)
		os.queueEvent("explorer_reload")]]
	end

	local function fBackground(obj)
		lOS.explorer.desktopConfig.background = {path=obj.file.path,resize=obj.txt:lower()}
		os.queueEvent("explorer_reload")
	end

	local function fAddToBackground(obj)
		local dConfig = lOS.explorer.desktopConfig
		if not dConfig.background[1] then
			local obg = dConfig.background
			dConfig.background = {color=obg.color,obg}
		end
		table.insert(dConfig.background,{path=obj.file.path,resize=obj.txt:lower()})
		os.queueEvent("explorer_reload")
		lOS.explorer.desktopBackground = nil
	end

	local function fCopyPath(obj)
		ccemux.setClipboard(obj.file.path)
	end

	if isDesktop then
		fOpen = fOpenWin
	end

	local options
	if not f then
		local newfiles = {}
		for k,v in pairs(fTypes) do
			if type(v) == "table" and type(v.emptyFilePreset) == "string" then
				table.insert(newfiles,{txt=v.name,preset=v.emptyFilePreset,action=fNew,format=k})
			end
		end
		table.insert(newfiles,{txt="bImg Icon",preset='{{{"   ","   ","   "},{"   ","   ","   "},{"   ","   ","   "}}}',action=fNew,format="bimg"})
		local opt = {
			{{txt="Refresh",action=updateFiles}},
			{{txt="Paste",action=fPaste,disabled=(#lOS.fClipboard == 0 or fs.isReadOnly(sl.folder))}},
			{{txt="New",disabled=(fs.isReadOnly(sl.folder)),action={{txt="Folder",action=fNewFolder},newfiles}}} -- import from formats.lconf
		}
		if isDesktop then
			local txtcolors = {}
			for k,v in pairs(colors) do
				if type(v) == "number" then
					table.insert(txtcolors,k)
				end
			end
			table.sort(txtcolors)
			local txtcoloroptions = {}
			for c=1,#txtcolors do
				local col = colors[txtcolors[c]]
				local name = txtcolors[c]:sub(1,1):upper()..txtcolors[c]:sub(2)
				local b = lUtils.toBlit(col)
				if dConfig.textColor == col then
					table.insert(txtcoloroptions,{txt={" \7  "..name,nil,string.rep(b,3)}})
					if col == colors.white then
						txtcoloroptions[#txtcoloroptions].txt[2] = "fff"
					end
				else
					table.insert(txtcoloroptions,{txt={"    "..name,nil,string.rep(b,3)},action=function() dConfig.textColor = col updateFiles() render() end})
				end
			end
			if not dConfig.textColor then
				table.insert(txtcoloroptions,1,{txt=" \7  Automatic"})
			else
				table.insert(txtcoloroptions,1,{txt="    Automatic",action=function() dConfig.textColor = nil updateFiles() render() end})
			end
			table.insert(opt[1],1,{txt="View",action={
				{txt="Text color",action={txtcoloroptions}}
			}})
		end
		if ccemux then 
			table.insert(opt,{{txt="Open External Explorer",action=function() ccemux.openDataDir() end}})
		end
		options = opt
	else
		if type(f) == "string" then
			f = genFile(f)
		end
		local file = f.path
		local nf = f
		local invalidShort
		if shortcache[file] then
			f.sPath = shortcache[file][1]
			f.sName = fs.getName(f.sPath)
			if fs.exists(f.sPath) then
				nf = genFile(f.sPath)
			else
				invalidShort = true
			end
		end
		options = {
			{

			},
			{
				{txt="Cut",action=fCut},
				{txt="Copy",action=fCopy}
			},
			{
				{txt="Delete",action=fDelete},
				{txt="Rename",action=fRename,file=f,sl=sl}
			}
		}
		local createshortcut = {txt="Create shortcut",file=nf,folder=sl.folder,name=nf.name,action=fShortcut}
		local createshortcut2 = {txt="Create shortcut on desktop",file=nf,folder="User/Desktop",name=nf.name,action=fDesktopShortcut}
		if fs.getName(nf.path) == "main.lua" then
			createshortcut.name = fs.getName(fs.getDir(nf.path))
			createshortcut2.name = fs.getName(fs.getDir(nf.path))
		end
		if invalidShort then
			createshortcut.action = fInvShortInternal
			createshortcut2.action = fInvShortInternal
		end
		if not isDesktop then
			table.insert(options[3],1,createshortcut2)
			table.insert(options[3],1,createshortcut)
		end
		local disabled = {}
		if f.readOnly == true then
			disabled = {Edit=true,Cut=true,Delete=true,Rename=true}
		elseif disks[file] ~= nil then
			disabled = {Edit=true,Cut=true,Delete=true,Rename=true}
			disabled["Create Shortcut"] = true
		end
		local fc = fs.combine
		if ccemux then
			table.insert(options[3],{txt="Copy path",file=f,action=fCopyPath})
		end
		local fOpen = fOpen
		local fOpenWin = fOpenWin
		local fOpenWith = fOpenWith
		local fExec = fExec
		local fUnpin = fUnpin
		local fPin = fPin
		if invalidShort then
			fOpen = fInvShortInternal
			fOpenWin = fInvShortInternal
			fOpenWith = fInvShortInternal
			fExec = fInvShortInternal
			fUnpin = fInvShortInternal
			fPin = fInvShortInternal
		end
		if nf.isDir then
			local etxt = ""
			local isProgram = false
			if fs.exists(fc(nf.path,"main.lua")) then
				isProgram = true
				etxt = "folder "
			end
			options[1] = {{txt="Open "..etxt,action=fOpen,file=nf}}
			if not isDesktop then
				table.insert(options[1],{txt="Open "..etxt.."in new window",action=fOpenWin,file=nf})
			end
			if isProgram then
				table.insert(options[1],{txt="Execute",action=fExec,p="Lua",file=nf})
				createshortcut.action = {{txt="To program",file=genFile(fc(nf.path,"main.lua")),folder=sl.folder,name=nf.name,action=fShortcut},{txt="To folder",file=nf,folder=sl.folder,name=nf.name,action=fShortcut}}
			end
			if not isDesktop then
				if locateEntry(sl.config.quickaccess,nf.path) then
					table.insert(options[1],{txt="Unpin from Quick access",action=fUnpin,file=nf})
				else
					table.insert(options[1],{txt="Pin to Quick access",action=fPin,file=nf})
				end
			end
		elseif fTypes[nf.type] and fTypes[nf.type].contextMenu and not invalidShort then
			local tbl = {}
			for k,v in ipairs(fTypes[nf.type].contextMenu[1]) do
				table.insert(tbl,{txt=v,file=nf,p=fTypes[nf.type].contextMenu[2][k],action=fExec})
			end
			if nf.type == "bimg" or nf.type == "limg" or nf.type == "nfp" then
				table.insert(tbl,{txt="Set as desktop background",action={{{txt="Stretch",file=nf,action=fBackground},{txt="Repeat",file=nf,action=fBackground},{txt="Center",file=nf,action=fBackground}}}})
				table.insert(tbl,{txt="Add to desktop background",action={{{txt="Repeat",file=nf,action=fAddToBackground},{txt="Center",file=nf,action=fAddToBackground}}},disabled=(not lOS.explorer.desktopConfig.background)})
			end
			options[1] = tbl
		else
			options[1] = {{txt="Edit",action=fExec,p="rom/programs/edit.lua",file=nf}}
		end
		if shortcache[file] then
			if invalidShort then
				table.insert(options[1],2,{txt="Open file location",disabled=true})
			else
				table.insert(options[1],2,{txt="Open file location",action=fOpen,file=genFile(fs.getDir(nf.path))})
			end
		end
		local ow
		if fTypes[nf.type] and fTypes[nf.type].openWith and not nf.isDir then
			local owtbl = {}
			for k,v in ipairs(fTypes[nf.type].openWith) do
				table.insert(owtbl,{txt=lUtils.getFileName(v),file=nf,p=v,action=fExec})
			end
			ow = {txt="Open with",action={owtbl,{txt="Choose another app",action=fOpenWith,file=nf,disabled=isDesktop}}}
			if invalidShort then
				ow.disabled = true
			end
			table.insert(options[1],ow)
		end
		if nf.readOnly == true --[[and locateEntry(options[1],"Edit") == true]] then
			for k,v in ipairs(options[1]) do
				if type(v) == "table" and v.txt == "Edit" then
					v.txt = "View"
				end
			end
			--options[1][({locateEntry(options[1],"Edit")})[2]] = "View"
		end
		for _,cat in ipairs(options) do
			for k,v in ipairs(cat) do
				if type(v) == "string" and disabled[v] then
					cat[k] = {txt=v,disabled=true}
				elseif type(v) == "table" and disabled[v.txt] then
					v.disabled = true
				end
			end
		end
	end
	return options
end

lOS.explorer.genContextMenu = genContextMenu

local function cMenu(f, x, y)
	local sel = {}
	for k,v in pairs(selected) do
		local path = fc("User/Desktop",dConfig.files[k])
		sel[path] = true
	end
	local options = genContextMenu(f,{win=term.current()},{folder="User/Desktop"},sel,reloadDesktop,render,LevelOS,true)
	local output = {lOS.contextmenu(x,y,30,options,nil,true)}
	return unpack(output)
end

render()
os.sleep(0.05)
render()
local lastUpdate = os.epoch("utc")
local tID = os.startTimer(10)
while true do
	local e = {os.pullEvent()}
	if e[1] == "explorer_full_reload" then
		lOS.explorer.shortcache = {}
		lOS.explorer.imgcache = {}
		lOS.explorer.nimgcache = {}
		lOS.explorer.desktopBackground = nil
		reloadDesktop()
		render()
	elseif e[1] == "term_resize" or e[1] == "explorer_reload" then
		lOS.explorer.desktopBackground = nil
		reloadDesktop()
		render()
	elseif e[1]:find("mouse") and e[3] and e[4] then
		local x,y = math.ceil(e[3]/8),math.ceil(e[4]/5)
		if e[1] == "mouse_click" then
			lOS.focusWin = lOS.wins[0]
		end
		if e[1] == "mouse_drag" and drag then
			drag.x,drag.y = e[3],e[4]
			drag.moved = true
			render()
		elseif e[1] == "mouse_up" and drag then
			if not desktopMap[x][y] then
				desktopMap[x][y] = drag.id
				local icon = dConfig.sizes[currentSize][drag.id]
				desktopMap[icon.x][icon.y] = nil
				icon.x,icon.y = x,y
				lUtils.asset.save(dConfig,"LevelOS/data/desktop.lconf")
			end
			drag = nil
			render()
		elseif e[3]%8 ~= 0 and desktopMap[x][y] then
			if e[1] == "mouse_click" then
				local id = desktopMap[x][y]
				if selected[id] and os.epoch("utc") < selected[id]+500 and e[2] == 1 then
					local path = fc("User/Desktop",dConfig.files[id])
					local rPath = path
					local cmd = path
					local shortcache = lOS.explorer.shortcache
					local exec = false
					local invalidShort = false
					local f = genFile(path)
					if shortcache[path] then
						cmd = shortcache[path][1]
						rPath = cmd
						f.sName = rPath
						if not fs.exists(rPath) then
							invalidShort = true
						end
						if shortcache[path].args and #shortcache[path].args > 0 then
							cmd = cmd.." "..table.concat(shortcache[path].args)
						end
						if shortcache[path].program then
							if shortcache[path].program ~= "Lua" then
								cmd = shortcache[path].program.." "..cmd
							end
							exec = true
						end
					end
					if invalidShort then
						fInvShort({file=f},reloadDesktop,render)
					else
						local fType = lUtils.getFileType(rPath):sub(2)
						if exec then
							lOS.execute(cmd)
						elseif fs.isDir(rPath) then
							lOS.execute("Program_Files/LevelOS/Explorer "..cmd)
						elseif fileTypes[fType] and fileTypes[fType].program then
							local p = fileTypes[fType].program
							if p == "Lua" then
								lOS.execute(cmd)
							else
								lOS.execute(p.." "..cmd)
							end
						elseif fType == "" then
							lOS.execute(cmd)
						end
					end
					selected = {}
				else
					if not (lUtils.isHolding(keys.leftCtrl) or lUtils.isHolding(keys.leftShift)) then
						selected = {}
					end
					if e[2] == 1 then
						selected[id] = os.epoch("utc")
						drag = {id=id,ox=(e[3]-1)%8,oy=(e[4]-1)%5,x=e[3],y=e[4],moved=false}
					else
						selected[id] = 0
					end
				end
				render()
			elseif e[1] == "mouse_up" and e[2] == 2 then
				local id = desktopMap[x][y]
				local path = fc("User/Desktop",dConfig.files[id])
				--[[local rPath = path
				local cmd = path
				local shortcache = lOS.explorer.shortcache
				local exec = false]]
				local f = genFile(path)
				f.x1,f.y1 = 1+(x-1)*8,1+(y-1)*5
				local lineH = math.min(#lUtils.wordwrap(lUtils.getFileName(f.path),7),4)
				f.x2,f.y2 = f.x1+6,f.y1+3+lineH
				cMenu(f,e[3],e[4])
			end
		elseif e[1] == "mouse_click" and not (lUtils.isHolding(keys.leftCtrl) or lUtils.isHolding(keys.leftShift)) then
			selected = {}
			render()
			if e[2] == 2 then
				cMenu(nil, e[3], e[4])
			end
		end
	elseif (e[1] == "timer" and e[2] == tID) or os.epoch("utc")-10000 > lastUpdate then
		lastUpdate = os.epoch("utc")
		if not (e[1] == "timer" and e[2] == tID) then
			os.cancelTimer(tID)
		end
		tID = os.startTimer(10)
		reloadDesktop()
		render()
	end
	if e[1] == "mouse_up" then
		drag = nil
	end
end