local FileMenu = {}
	FileMenu.CurrentFolder = ""
	FileMenu.CurrentFile = ""
	FileMenu.FileList = {}
	FileMenu.Dissalowed = {"/", ":", ">", "<", "|", "%", "?", "*", "'", '"', "."}

local FileIcons = {}
	FileIcons[1] = Material("gui/silkicons/page")
	FileIcons[2] = Material("gui/silkicons/folder_go")

CreateClientConVar("filemenu_useds", 0, true, false)
CreateClientConVar("filemenu_cmdname", "server_lua", true, false)
CreateClientConVar("filemenu_dsname", "server_lua", true, false)

local FileList_VGUI
local ManualPath

local function IsFile(text)
	if string.match(text, "%.[%w%d]+") and not string.match(text, "%.dll") then
		return true
	else
		return false
	end
end

function FileMenu.SendLuaCode(lua)
	if GetConVar("filemenu_useds"):GetBool() then
		datastream.StreamToServer(GetConVar("filemenu_dsname"):GetString(), lua)
	else
		RunConsoleCommand(GetConVar("filemenu_cmdname"):GetString(), lua)
	end
end

function FileMenu.SendLuaCode2(lua)
	if GetConVar("filemenu_useds"):GetBool() then
		datastream.StreamToServer(GetConVar("filemenu_dsname"):GetString(), lua)
	else
		RunConsoleCommand(GetConVar("filemenu_cmdname"):GetString(), "datastream.Hook([[serverlua]], function(ply, handler, id, encoded, decoded) RunString(decoded) end)")
		datastream.StreamToServer("serverlua", lua)
	end
end

function FileMenu.UpdateFileList()
	if FileList_VGUI == nil then return false end
	if ManualPath != nil then ManualPath:SetValue(FileMenu.CurrentFolder) end

	for k, v in pairs(FileMenu.FileList) do
		local c_line = FileList_VGUI:AddLine()
			c_line:SetValue(1, "         " .. v)
			function c_line:Paint()
				if c_line:GetID() % 2 == 1 then
					surface.SetDrawColor(Color(100, 100, 100, 255))
				else
					surface.SetDrawColor(Color(80, 80, 80, 255))
				end
				if self.Hovered then
					surface.SetDrawColor(Color(100, 0, 0, 255))
				end
				surface.DrawRect(0, 0, self:GetWide(), self:GetTall())
			end
		local spr = vgui.Create("DSprite", c_line)
			spr:SetSize(16, 16)
			spr:SetPos(14, 16)
			if IsFile(v) then
				spr:SetMaterial(FileIcons[1])
			else
				spr:SetMaterial(FileIcons[2])
			end
	end
end

function FileMenu.RecievedFiles(h, id, encoded, fileList)
	FileMenu.FileList = fileList
	FileMenu.UpdateFileList()
end

function FileMenu.GetDLFolder(f)
	local folder = "filemenu_downloads/"
		local hostname = GetHostName()
		for k, v in pairs(FileMenu.Dissalowed) do
			hostname = string.Replace(hostname, v, "_")
		end
		folder = folder .. hostname
		folder = folder .. "/"
		folder = folder .. string.Replace(f, ".", "_")

	return folder
end

function FileMenu.RecieveFile(f)
	FileMenu.SendLuaCode("datastream.StreamToClients(G_PLY, [[fm_file]], file.Read([[" .. f .. "]], true))")
	local Frame = vgui.Create("DFrame")
		Frame:SetSize(300, 80)
		Frame:SetTitle("Information")
		Frame:Center()
		Frame:SetSizable(false)
		Frame:MakePopup()
		function Frame:Paint()
			Derma_DrawBackgroundBlur(self, self.m_fCreateTime)
			surface.SetDrawColor(Color(50, 50, 50, 255))
			surface.DrawRect(0, 0, self:GetWide(), self:GetTall())
			surface.SetDrawColor(Color(40, 40, 40, 255))
			surface.DrawRect(0, 0, self:GetWide(), 22)
		end
	local FLabel = vgui.Create("DLabel", Frame)
		FLabel:SetText("Recieving file '" .. f .. "'...")
		FLabel:SizeToContents()
		FLabel:Center()
	datastream.Hook("fm_file", function(handler, id, encoded, fileData)
		if Frame.Close != nil then
			Frame:Close()
		end

		local Frame2 = vgui.Create("DFrame")
			Frame2:SetSize(500, 400)
			Frame2:SetTitle(f)
			Frame2:Center()
			Frame2:SetSizable(false)
			Frame2:MakePopup()
			function Frame2:Paint()
				Derma_DrawBackgroundBlur(self, self.m_fCreateTime)
				surface.SetDrawColor(Color(50, 50, 50, 255))
				surface.DrawRect(0, 0, self:GetWide(), self:GetTall())
				surface.SetDrawColor(Color(40, 40, 40, 255))
				surface.DrawRect(0, 0, self:GetWide(), 22)
			end
		local Text = vgui.Create("DTextEntry", Frame2)
			Text:SetSize(Frame2:GetWide() - 20, Frame2:GetTall() - 90)
			Text:SetPos(10, 30)
			Text:SetMultiline(true)
			if fileData != nil then
				Text:SetValue(string.gsub(fileData, "\t", "    "))
			else
				Text:SetValue("Unable to read file, please make sure the file has to be in text format, eg .lua .cfg .txt .ini and so on.")
			end
			function Text:OnTextChanged()
				Text:SetValue(string.gsub(fileData, "\t", "    "))
			end
		local Download = vgui.Create("DButton", Frame2)
			Download:SetSize(Frame2:GetWide() - 20, 30)
			Download:SetPos(10, Frame2:GetTall() - 40)
			Download:SetText("Download File (" .. FileMenu.GetDLFolder(f) .. ".txt)")
			if fileData == nil then
				Download:SetDisabled(true)
			end
			function Download:DoClick()
				file.Write(FileMenu.GetDLFolder(f) .. ".txt", fileData)
				Frame2:Close()
				local Frame3 = vgui.Create("DFrame")
					Frame3:SetSize(300, 80)
					Frame3:SetTitle("Information")
					Frame3:Center()
					Frame3:SetSizable(false)
					Frame3:MakePopup()
					function Frame3:Paint()
						Derma_DrawBackgroundBlur(self, self.m_fCreateTime)
						surface.SetDrawColor(Color(50, 50, 50, 255))
						surface.DrawRect(0, 0, self:GetWide(), self:GetTall())
						surface.SetDrawColor(Color(40, 40, 40, 255))
						surface.DrawRect(0, 0, self:GetWide(), 22)
					end
				local FLabel2 = vgui.Create("DLabel", Frame3)
					FLabel2:SetText("Successfully downloaded '" .. f .. "'\nTo be 100%, check the file just in case.")
					FLabel2:SizeToContents()
					FLabel2:Center()
				timer.Simple(5, function()
					if Frame3.Close != nil then
						Frame3:Close()
					end
				end)
			end
	end)
end

function FileMenu.UpdateList()
	MsgN("File Menu: Current selected folder is '" .. FileMenu.CurrentFolder .. "'")
	if FileList_VGUI == nil then return false end

	FileList_VGUI:Clear()

	local curfolder = "*.*"

	if FileMenu.CurrentFolder != "" then curfolder = FileMenu.CurrentFolder .. "/*.*" end

	FileMenu.SendLuaCode("for k, v in pairs(player.GetAll()) do if ValidEntity(v) then if v:UniqueID() == [[" .. LocalPlayer():UniqueID() .. "]] then G_PLY = v end end	end")

	FileList_VGUI:AddLine("Recieving folder data...")
	timer.Simple(0.5, function()
		// Just incase it takes long time
		FileList_VGUI:Clear()
		FileList_VGUI:AddLine("..")

		if FileMenu.CurrentFolder == "" then
			FileMenu.SendLuaCode("local FileList = file.Find([[*.*]], true) datastream.StreamToClients(G_PLY, [[fm_list]], FileList)")
		else
			FileMenu.SendLuaCode("local FileList = file.Find([[" .. FileMenu.CurrentFolder .. "/*.*]], true) datastream.StreamToClients(G_PLY, [[fm_list]], FileList)")
		end

		datastream.Hook("fm_list", FileMenu.RecievedFiles)
	end)
end

function FileMenu.BackFolder()
	if FileMenu.CurrentFolder == "" or FileMenu.CurrentFolder == "Recieving folder data..." then return end

	if not string.match(FileMenu.CurrentFolder, "/") then FileMenu.CurrentFolder = "" FileMenu.UpdateList() return end

	local folders = string.Explode("/", FileMenu.CurrentFolder)
	if #folders == 2 then
		FileMenu.CurrentFolder = folders[1]
		FileMenu.UpdateList()
		return
	else
		FileMenu.CurrentFolder = ""
		for k, v in ipairs(folders) do
			if k < #folders then
				FileMenu.CurrentFolder = FileMenu.CurrentFolder .. v
			end
			if k < #folders - 1 then
				FileMenu.CurrentFolder = FileMenu.CurrentFolder .. "/"
			end
		end
		MsgN(FileMenu.CurrentFolder)
		FileMenu.UpdateList()
		return
	end
end

function FileMenu.FileAction(f)
	if f == "Recieving folder data..." then return false end
	if f == ".." then FileMenu.BackFolder() return false end

	if IsFile(f) then
		if FileMenu.CurrentFolder == "" then
			FileMenu.RecieveFile(string.Replace(f, "         ", ""))
		else
			FileMenu.RecieveFile(FileMenu.CurrentFolder .. "/" .. string.Replace(f, "         ", ""))
		end
	else
		if FileMenu.CurrentFolder == "" then
			FileMenu.CurrentFolder = string.Replace(f, "         ", "")
		else
			FileMenu.CurrentFolder = FileMenu.CurrentFolder .. "/" .. string.Replace(f, "         ", "")
		end
		FileMenu.UpdateList()
	end
end

local function FileMenu_Show()
	local Frame = vgui.Create("DFrame")
		Frame:SetSize(800, 600)
		Frame:Center()
		Frame:SetTitle("File Menu")
		Frame:SetDraggable(true)
		Frame:SetSizable(false)
		Frame:MakePopup()
		function Frame:Paint()
			Derma_DrawBackgroundBlur(self, self.m_fCreateTime)
			surface.SetDrawColor(Color(50, 50, 50, 255))
			surface.DrawRect(0, 0, self:GetWide(), self:GetTall())
			surface.SetDrawColor(Color(40, 40, 40, 255))
			surface.DrawRect(0, 0, self:GetWide(), 22)
		end
	local PropSheet = vgui.Create("DPropertySheet", Frame)
		PropSheet:SetPos(10, 30)
		PropSheet:SetSize(Frame:GetWide() - 20, Frame:GetTall() - 50)
	local Panel = vgui.Create("DPanel", PropSheet)
		Panel:SetSize(Frame:GetWide() - 20 - 10, Frame:GetTall() - 50 - 20)
		Panel:SetPos(0, 0)
		function Panel:Paint()
			surface.SetDrawColor(Color(45, 45, 45, 255))
			surface.DrawRect(0, 0, self:GetWide(), self:GetTall())
			surface.SetDrawColor(Color(80, 80, 80, 255))
			surface.DrawRect(0, 0, self:GetWide(), 60)
		end
		PropSheet:AddSheet("File Menu", Panel, "gui/silkicons/box", false, false, "File Menu")
	local CommandNameL = vgui.Create("DLabel", Panel)
		CommandNameL:SetPos(10, 13)
		CommandNameL:SetText("Lua Console Command")
		CommandNameL:SizeToContents()
	local CommandName = vgui.Create("DTextEntry", Panel)
		CommandName:SetSize(120, 20)
		CommandName:SetPos(165, 10)
		CommandName:SetConVar("filemenu_cmdname")
	local CommandNameChange = vgui.Create("DButton", Panel)
		CommandNameChange:SetSize(100, 20)
		CommandNameChange:SetPos(295, 10)
		CommandNameChange:SetText("Change")
		function CommandNameChange:DoClick()
			RunConsoleCommand("filemenu_cmdname", CommandName:GetValue())
		end
	local DatastreamNameL = vgui.Create("DLabel", Panel)
		DatastreamNameL:SetPos(10, 33)
		DatastreamNameL:SetText("Datastream ID")
		DatastreamNameL:SizeToContents()
	local DatastreamName = vgui.Create("DTextEntry", Panel)
		DatastreamName:SetSize(120, 20)
		DatastreamName:SetPos(165, 30)
		DatastreamName:SetConVar("filemenu_dsname")
	local DatastreamNameChange = vgui.Create("DButton", Panel)
		DatastreamNameChange:SetSize(100, 20)
		DatastreamNameChange:SetPos(295, 30)
		DatastreamNameChange:SetText("Change")
		function CommandNameChange:DoClick()
			RunConsoleCommand("filemenu_dsname", DatastreamName:GetValue())
		end
	local UseDataStream = vgui.Create("DCheckBoxLabel", Panel)
		UseDataStream:SetPos(400, 10)
		UseDataStream:SetText("Use Datastream over Lua")
		UseDataStream:SetConVar("filemenu_useds")
		UseDataStream:SizeToContents()
	ManualPath = vgui.Create("DTextEntry", Panel)
		ManualPath:SetSize(240, 20)
		ManualPath:SetPos(400, 30)
		ManualPath:SetValue(FileMenu.CurrentFolder)
		function ManualPath:OnEnter()
			FileMenu.CurrentFolder = ManualPath:GetValue()
			FileMenu.UpdateList()
		end
	FileList_VGUI = vgui.Create("DListView", Panel)
		FileList_VGUI:SetSize(Panel:GetWide() - 20, Panel:GetTall() - 90)
		FileList_VGUI:SetPos(10, 70)
		FileList_VGUI:AddColumn("File Name")
		FileList_VGUI:SetDataHeight(30)
		function FileList_VGUI:Paint()
			surface.SetDrawColor(Color(30, 30, 30, 255))
			surface.DrawRect(0, 0, self:GetWide(), self:GetTall())
		end
		function FileList_VGUI.DoDoubleClick(_p, id, line)
			FileMenu.FileAction(line:GetValue(1))
			surface.PlaySound("buttons/button14.wav")
		end

	FileMenu.UpdateList()
	local Panel2 = vgui.Create("DPanel", Frame)
		Panel2:SetSize(Frame:GetWide() - 20 - 10, Frame:GetTall() - 50 - 20)
		Panel2:SetPos(0, 0)
		function Panel2:Paint()
			surface.SetDrawColor(Color(45, 45, 45, 255))
			surface.DrawRect(0, 0, self:GetWide(), self:GetTall())
			surface.SetDrawColor(Color(80, 80, 80, 255))
			surface.DrawRect(0, 0, self:GetWide(), 60)
		end
		PropSheet:AddSheet("Lua Prompt", Panel2, "gui/silkicons/page_white", false, false, "Lua Prompt")
	local CommandNameL = vgui.Create("DLabel", Panel2)
		CommandNameL:SetPos(10, 13)
		CommandNameL:SetText("Lua Console Command")
		CommandNameL:SizeToContents()
	local CommandName = vgui.Create("DTextEntry", Panel2)
		CommandName:SetSize(120, 20)
		CommandName:SetPos(165, 10)
		CommandName:SetConVar("filemenu_cmdname")
	local CommandNameChange = vgui.Create("DButton", Panel2)
		CommandNameChange:SetSize(100, 20)
		CommandNameChange:SetPos(295, 10)
		CommandNameChange:SetText("Change")
		function CommandNameChange:DoClick()
			RunConsoleCommand("filemenu_cmdname", CommandName:GetValue())
		end
	local DatastreamNameL = vgui.Create("DLabel", Panel2)
		DatastreamNameL:SetPos(10, 33)
		DatastreamNameL:SetText("Datastream ID")
		DatastreamNameL:SizeToContents()
	local DatastreamName = vgui.Create("DTextEntry", Panel2)
		DatastreamName:SetSize(120, 20)
		DatastreamName:SetPos(165, 30)
		DatastreamName:SetConVar("filemenu_dsname")
	local DatastreamNameChange = vgui.Create("DButton", Panel2)
		DatastreamNameChange:SetSize(100, 20)
		DatastreamNameChange:SetPos(295, 30)
		DatastreamNameChange:SetText("Change")
		function CommandNameChange:DoClick()
			RunConsoleCommand("filemenu_dsname", DatastreamName:GetValue())
		end
	local UseDataStream = vgui.Create("DCheckBoxLabel", Panel2)
		UseDataStream:SetPos(400, 10)
		UseDataStream:SetText("Use Datastream over Lua")
		UseDataStream:SetConVar("filemenu_useds")
		UseDataStream:SizeToContents()
	local TextField = vgui.Create("DTextEntry", Panel2)
		TextField:SetPos(220, 70)
		TextField:SetSize(Panel:GetWide() - 230, Panel:GetTall() - 130)
		TextField:SetMultiline(true)
	local FileList = vgui.Create("DListView", Panel2)
		FileList:SetSize(200, Panel:GetTall() - 90)
		FileList:SetPos(10, 70)
		FileList:AddColumn("File Name")
		FileList:SetDataHeight(30)
		function FileList:Paint()
			surface.SetDrawColor(Color(30, 30, 30, 255))
			surface.DrawRect(0, 0, self:GetWide(), self:GetTall())
		end
		function FileList.DoDoubleClick(_p, id, line)
			surface.PlaySound("buttons/button14.wav")
			TextField:SetValue(file.Read("lua_scripts/" .. line:GetValue(1)))
		end
		function FileList:Update()
			FileList:Clear()
			for k, v in pairs(file.Find("lua_scripts/*.txt")) do
				FileList:AddLine(v)
			end
		end
		FileList:Update()
	local RunLuaButton = vgui.Create("DButton", Panel2)
		RunLuaButton:SetSize(100, 30)
		RunLuaButton:SetPos(220, Panel2:GetTall() - 50)
		RunLuaButton:SetText("Run Lua")
		function RunLuaButton:DoClick()
			FileMenu.SendLuaCode2(TextField:GetValue())
		end
	local SaveFileName = vgui.Create("DTextEntry", Panel2)
		SaveFileName:SetSize(200, 20)
		SaveFileName:SetPos(440, Panel2:GetTall() - 45)
		SaveFileName:SetValue("untitled_lua.txt")
	local SaveFileButton = vgui.Create("DButton", Panel2)
		SaveFileButton:SetSize(100, 30)
		SaveFileButton:SetPos(330, Panel2:GetTall() - 50)
		SaveFileButton:SetText("Save File")
		function SaveFileButton:DoClick()
			file.Write("lua_scripts/" .. SaveFileName:GetValue(), TextField:GetValue())
			timer.Simple(0.1, function()
				FileList:Update()
			end)
		end
end
concommand.Add("filemenu", FileMenu_Show)