----------------------------------------------------------------
----------------------------------------------------------------
----------------------------------------------------------------
----------------------------------------------------------------
---- Explorer panel

Create(explorerPanel,{
	BackgroundColor3 = GuiColor.Field;
	BorderColor3 = GuiColor.Border;
	Active = true;
})

local SettingsRemote = explorerPanel.Parent:WaitForChild("SettingsPanel"):WaitForChild("GetSetting")
local GetApiRemote = explorerPanel.Parent:WaitForChild("PropertiesFrame"):WaitForChild("GetApi")
local GetAwaitRemote = explorerPanel.Parent:WaitForChild("PropertiesFrame"):WaitForChild("GetAwaiting")
local bindSetAwaiting = explorerPanel.Parent:WaitForChild("PropertiesFrame"):WaitForChild("SetAwaiting")

local CautionWindow = explorerPanel.Parent:WaitForChild("Caution")
local TableCautionWindow = explorerPanel.Parent:WaitForChild("TableCaution")

local RemoteWindow = explorerPanel.Parent:WaitForChild("CallRemote")

local CurrentRemoteWindow

local lastSelectedNode

local listFrame = Create('Frame',{
	Name = "List";
	BackgroundTransparency = 1;
	ClipsDescendants = true;
	Position = UDim2_new(0,0,0,HEADER_SIZE);
	Size = UDim2_new(1,-GUI_SIZE,1,-HEADER_SIZE);
	Parent = explorerPanel;
})

local scrollBar = ScrollBar(false)
scrollBar.PageIncrement = 1
Create(scrollBar.GUI,{
	Position = UDim2_new(1,-GUI_SIZE,0,HEADER_SIZE);
	Size = UDim2_new(0,GUI_SIZE,1,-HEADER_SIZE);
	Parent = explorerPanel;
})

local scrollBarH = ScrollBar(true)
scrollBarH.PageIncrement = GUI_SIZE
Create(scrollBarH.GUI,{
	Position = UDim2_new(0,0,1,-GUI_SIZE);
	Size = UDim2_new(1,-GUI_SIZE,0,GUI_SIZE);
	Visible = false;
	Parent = explorerPanel;
})

local headerFrame = Create('Frame',{
	Name = "Header";
	BackgroundColor3 = GuiColor.Background;
	BorderSizePixel = 0;
	Position = UDim2_new(0,0,0,0);
	Size = UDim2_new(1,0,0,HEADER_SIZE);
	Parent = explorerPanel;
	Create('TextLabel',{
		Text = "Explorer";
		BackgroundTransparency = 1;
		TextColor3 = GuiColor.Text;
		TextXAlignment = 'Left';
		Font = FONT;
		FontSize = FONT_SIZE;
		Position = UDim2_new(0,4,0,0);
		Size = UDim2_new(1,-4,0.5,0);
	});
})

local explorerFilter = 	Create('TextBox',{
	PlaceholderText = "Filter workspace...";
	PlaceholderColor3 = Color3_fromRGB(153, 153, 153);
	Text = "";
	BackgroundTransparency = 0.8;
	TextColor3 = GuiColor.Text;
	TextXAlignment = 'Left';
	Font = FONT;
	FontSize = FONT_SIZE;
	Position = UDim2_new(0,4,0.5,0);
	Size = UDim2_new(1,-8,0.5,-2);
	Create('UIPadding',{
		PaddingLeft = UDim.new(0, 4)
	})
});
explorerFilter.Parent = headerFrame

SetZIndexOnChanged(explorerPanel)

local function CreateColor3(r, g, b) return Color3_new(r/255,g/255,b/255) end

local Styles = {
	Font = Enum.Font.Arial,
	Margin = 5,
	Black = Color3_fromRGB(0,0,5),
	Black2 = Color3_fromRGB(24, 24, 29),
	White = Color3_fromRGB(244,244,249),
	WhiteOver = Color3_fromRGB(200,200,205),
	Hover = Color3_fromRGB(2, 128, 149),
	Hover2 = Color3_fromRGB(5, 102, 146)
}

local Row = {
	Font = Styles.Font,
	FontSize = Enum.FontSize.Size14,
	TextXAlignment = Enum.TextXAlignment.Left,
	TextColor = Styles.White,
	TextColorOver = Styles.WhiteOver,
	TextLockedColor = Color3_fromRGB(155,155,160),
	Height = 24,
	BorderColor = Color3_fromRGB(54,54,55),
	BackgroundColor = Styles.Black2,
	BackgroundColorAlternate = Color3_fromRGB(32, 32, 37),
	BackgroundColorMouseover = Color3_fromRGB(40, 40, 45),
	TitleMarginLeft = 15
}

local DropDown = {
	Font = Styles.Font,
	FontSize = Enum.FontSize.Size14,
	TextColor = Color3_fromRGB(255,255,260),
	TextColorOver = Row.TextColorOver,
	TextXAlignment = Enum.TextXAlignment.Left,
	Height = 20,
	BackColor = Styles.Black2,
	BackColorOver = Styles.Hover2,
	BorderColor = Color3_fromRGB(45,45,50),
	BorderSizePixel = 0,
	ArrowColor = Color3_fromRGB(80,80,83),
	ArrowColorOver = Styles.Hover
}

local BrickColors = {
	BoxSize = 13,
	BorderSizePixel = 0,
	BorderColor = Color3_fromRGB(53,53,55),
	FrameColor = Color3_fromRGB(53,53,55),
	Size = 20,
	Padding = 4,
	ColorsPerRow = 8,
	OuterBorder = 1,
	OuterBorderColor = Styles.Black
}

local currentRightClickMenu
local CurrentInsertObjectWindow
local CurrentFunctionCallerWindow

local RbxApi

function ClassCanCreate(IName)
	local success,err = pcall(function() Instance_new(IName) end)
	if err then
		return false
	else
		return true
	end
end

function GetClasses()
	if RbxApi == nil then return {} end
	local classTable = {}
	for i,v in pairs(RbxApi.Classes) do
		if ClassCanCreate(v.Name) then
			table.insert(classTable,v.Name)
		end
	end
	return classTable
end

local function sortAlphabetic(t, property)
	table.sort(t,
		function(x,y) return x[property] < y[property]
		end)
end

local function FunctionIsHidden(functionData)
	local tags = functionData["Tags"]
	if tags then
		for _,name in pairs(tags) do
			if name == "Deprecated"
				or name == "Hidden"
				or name == "ReadOnly"
				or name == "NotScriptable" then
				return true
			end
		end
	end
	return false
end

local function GetAllFunctions(className)
	local class = RbxApi.Classes[className]
	local functions = {}

	if not class then return functions end

	while class do
		if class.Name == "Instance" then break end
		for _,nextFunction in pairs(class.Members) do
			if nextFunction.MemberType == "Function" and not FunctionIsHidden(nextFunction) then
				table.insert(functions, nextFunction)
			end
		end
		class = RbxApi.Classes[class.Superclass]
	end

	sortAlphabetic(functions, "Name")

	return functions
end

function GetFunctions()
	if RbxApi == nil then return {} end
	local List = SelectionVar():Get()

	if #List == 0 then return end

	local MyObject = List[1]

	local functionTable = {}
	for i,v in pairs(GetAllFunctions(MyObject.ClassName)) do
		table.insert(functionTable,v)
	end
	return functionTable
end

function CreateInsertObjectMenu(choices, currentChoice, readOnly, onClick)
	local mouse = game:GetService("Players").LocalPlayer:GetMouse()
	local totalSize = explorerPanel.Parent.AbsoluteSize.y
	if #choices == 0 then return end

	table.sort(choices, function(a,b) return a < b end)

	local frame = Instance_new("Frame")	
	frame.Name = "InsertObject"
	frame.Size = UDim2_new(0, 200, 1, 0)
	frame.BackgroundTransparency = 1
	frame.Active = true

	local menu = nil
	local arrow = nil
	local expanded = false
	local margin = DropDown.BorderSizePixel;

	--[[
	local button = Instance_new("TextButton")
	button.Font = Row.Font
	button.FontSize = Row.FontSize
	button.TextXAlignment = Row.TextXAlignment
	button.BackgroundTransparency = 1
	button.TextColor3 = Row.TextColor
	if readOnly then
		button.TextColor3 = Row.TextLockedColor
	end
	button.Text = currentChoice
	button.Size = UDim2_new(1, -2 * Styles.Margin, 1, 0)
	button.Position = UDim2_new(0, Styles.Margin, 0, 0)
	button.Parent = frame
	--]]

	local function hideMenu()
		expanded = false
		--showArrow(DropDown.ArrowColor)
		if frame then
			--frame:Destroy()
			CurrentInsertObjectWindow.Visible = false
		end
	end

	local function showMenu()
		expanded = true
		menu = Instance_new("ScrollingFrame")
		menu.Size = UDim2_new(0,200,1,0)
		menu.CanvasSize = UDim2_new(0, 200, 0, #choices * DropDown.Height)
		menu.Position = UDim2_new(0, margin, 0, 0)
		menu.BackgroundTransparency = 0
		menu.BackgroundColor3 = DropDown.BackColor
		menu.BorderColor3 = DropDown.BorderColor
		menu.BorderSizePixel = DropDown.BorderSizePixel
		menu.TopImage = "rbxasset://textures/blackBkg_square.png"
		menu.MidImage = "rbxasset://textures/blackBkg_square.png"
		menu.BottomImage = "rbxasset://textures/blackBkg_square.png"
		menu.Active = true
		menu.ZIndex = 5
		menu.Parent = frame

		--local parentFrameHeight = script.Parent.List.Size.Y.Offset
		--local rowHeight = mouse.Y
		--if (rowHeight + menu.Size.Y.Offset) > parentFrameHeight then
		--	menu.Position = UDim2_new(0, margin, 0, -1 * (#choices * DropDown.Height) - margin)
		--end

		local function choice(name)
			onClick(name)
			hideMenu()
		end

		for i,name in pairs(choices) do
			local option = CreateRightClickMenuItem(name, function()
				choice(name)
			end,1)
			option.Size = UDim2_new(1, 0, 0, 20)
			option.Position = UDim2_new(0, 0, 0, (i - 1) * DropDown.Height)
			option.ZIndex = menu.ZIndex
			option.Parent = menu
		end
	end

	showMenu()

	return frame
end

function CreateFunctionCallerMenu(choices, currentChoice, readOnly, onClick)
	local mouse = game:GetService("Players").LocalPlayer:GetMouse()
	local totalSize = explorerPanel.Parent.AbsoluteSize.y
	if #choices == 0 then return end

	table.sort(choices, function(a,b) return a.Name < b.Name end)

	local frame = Instance_new("Frame")	
	frame.Name = "InsertObject"
	frame.Size = UDim2_new(0, 200, 1, 0)
	frame.BackgroundTransparency = 1
	frame.Active = true

	local menu = nil
	local arrow = nil
	local expanded = false
	local margin = DropDown.BorderSizePixel;

	local function hideMenu()
		expanded = false
		--showArrow(DropDown.ArrowColor)
		if frame then
			--frame:Destroy()
			CurrentInsertObjectWindow.Visible = false
		end
	end

	local function showMenu()
		expanded = true
		menu = Instance_new("ScrollingFrame")
		menu.Size = UDim2_new(0,300,1,0)
		menu.CanvasSize = UDim2_new(0, 300, 0, #choices * DropDown.Height)
		menu.Position = UDim2_new(0, margin, 0, 0)
		menu.BackgroundTransparency = 0
		menu.BackgroundColor3 = DropDown.BackColor
		menu.BorderColor3 = DropDown.BorderColor
		menu.BorderSizePixel = DropDown.BorderSizePixel
		menu.TopImage = "rbxasset://textures/blackBkg_square.png"
		menu.MidImage = "rbxasset://textures/blackBkg_square.png"
		menu.BottomImage = "rbxasset://textures/blackBkg_square.png"
		menu.Active = true
		menu.ZIndex = 5
		menu.Parent = frame

		--local parentFrameHeight = script.Parent.List.Size.Y.Offset
		--local rowHeight = mouse.Y
		--if (rowHeight + menu.Size.Y.Offset) > parentFrameHeight then
		--	menu.Position = UDim2_new(0, margin, 0, -1 * (#choices * DropDown.Height) - margin)
		--end

		local function GetParameters(functionData)
			local paraString = ""
			paraString = paraString.."("
			for i,v in pairs(functionData.Parameters) do
				paraString = paraString..v.Type.Name.." "..v.Name
				if i < #functionData.Parameters then
					paraString = paraString..", "
				end
			end
			paraString = paraString..")"
			return paraString
		end

		local function choice(name)
			onClick(name)
			hideMenu()
		end

		for i,name in pairs(choices) do
			local option = CreateRightClickMenuItem(name.ReturnType.Name.." "..name.Name..GetParameters(name), function()
				choice(name)
			end,2)
			option.Size = UDim2_new(1, 0, 0, 20)
			option.Position = UDim2_new(0, 0, 0, (i - 1) * DropDown.Height)
			option.ZIndex = menu.ZIndex
			option.Parent = menu
		end
	end


	showMenu()


	return frame
end

function CreateInsertObject()
	if not CurrentInsertObjectWindow then return end
	CurrentInsertObjectWindow.Visible = true
	if currentRightClickMenu and CurrentInsertObjectWindow.Visible then
		CurrentInsertObjectWindow.Position = UDim2_new(0,currentRightClickMenu.Position.X.Offset-currentRightClickMenu.Size.X.Offset,0,0)
	end
	if CurrentInsertObjectWindow.Visible then
		CurrentInsertObjectWindow.Parent = explorerPanel.Parent
	end
end

function CreateFunctionCaller(oh)
	if CurrentFunctionCallerWindow then
		CurrentFunctionCallerWindow:Destroy()
		CurrentFunctionCallerWindow = nil
	end
	CurrentFunctionCallerWindow = CreateFunctionCallerMenu(
		GetFunctions(),
		"",
		false,
		function(option)
			CurrentFunctionCallerWindow:Destroy()
			CurrentFunctionCallerWindow = nil
			local list = SelectionVar():Get()
			for i,v in pairs(list) do
				local rets = RemoteEvent:InvokeServer("CallFunction",v,option.Name)
				print(rets)
				pcall(function() print("Function", option.Name, "on", v, ":", unpack(rets)) end)
			end

			DestroyRightClick()
		end
	)
	if currentRightClickMenu and CurrentFunctionCallerWindow then
		CurrentFunctionCallerWindow.Position = UDim2_new(0,currentRightClickMenu.Position.X.Offset-currentRightClickMenu.Size.X.Offset*1.5,0,0)
	end
	if CurrentFunctionCallerWindow then
		CurrentFunctionCallerWindow.Parent = explorerPanel.Parent
	end
end

function CreateRightClickMenuItem(text, onClick, insObj)
	local button = Instance_new("TextButton")
	button.Font = DropDown.Font
	button.FontSize = DropDown.FontSize
	button.TextColor3 = DropDown.TextColor
	button.BackgroundColor3 = DropDown.BackColor
	button.AutoButtonColor = false
	button.BorderSizePixel = 0
	button.TextTransparency = 1
	button.Active = true

	if text then
		local label = Instance_new("TextLabel")
		label.Size = UDim2_new(1, 0, 1, 0)
		label.Font = DropDown.Font
		label.FontSize = Enum.FontSize.Size11
		label.TextColor3 = DropDown.TextColor
		label.TextXAlignment = DropDown.TextXAlignment
		label.BackgroundTransparency = 1
		label.BorderSizePixel = 0
		label.ZIndex = 5

		label.Text = text
		button.Text = text

		label.Parent = button


		if insObj == 2 then
			label.FontSize = Enum.FontSize.Size11
			label.Size = UDim2_new(1, -16, 1, 0)
			label.Position = UDim2_new(0, 16, 0, 0)
		else
			if insObj == 1 or ExplorerIndex[text] then
				if ExplorerIndex[text] then
					local newIcon = Icon(nil,ExplorerIndex[text] or 0)
					newIcon.Position = UDim2_new(0,2,0,2)
					newIcon.Size = UDim2_new(0,16,0,16)
					newIcon.IconMap.ZIndex = 5
					newIcon.Parent = button
				else
					local newIcon = ClassIcon(nil,ClassIndex[text] or 0)
					newIcon.Position = UDim2_new(0,2,0,2)
					newIcon.Size = UDim2_new(0,16,0,16)
					newIcon.IconMap.ZIndex = 5
					newIcon.Parent = button
				end
			end

			label.Size = UDim2_new(1, -32, 1, 0)
			label.Position = UDim2_new(0, 32, 0, 0)
		end


		button.MouseEnter:connect(function()
			button.TextColor3 = DropDown.TextColorOver
			button.BackgroundColor3 = DropDown.BackColorOver
			if not insObj and CurrentInsertObjectWindow then
				if CurrentInsertObjectWindow.Visible == false and button.Text == "Insert Object" then
					CreateInsertObject()
				elseif CurrentInsertObjectWindow.Visible and button.Text ~= "Insert Object" then
					CurrentInsertObjectWindow.Visible = false
				end
			end
			if not insObj then
				if CurrentFunctionCallerWindow and button.Text ~= "Call Function" then
					CurrentFunctionCallerWindow:Destroy()
					CurrentFunctionCallerWindow = nil
				elseif button.Text == "Call Function" then
					CreateFunctionCaller()
				end
			end
		end)
		button.MouseLeave:connect(function()
			button.TextColor3 = DropDown.TextColor
			button.BackgroundColor3 = DropDown.BackColor
		end)
		button.MouseButton1Click:connect(function()
			button.TextColor3 = DropDown.TextColor
			button.BackgroundColor3 = DropDown.BackColor
			onClick(text)
		end)	
	else
		local sep = Instance_new("Frame", button)
		sep.Size = UDim2_new(1, -20, 0, 1)
		sep.Position = UDim2_new(0, 16, 0, 2)
		sep.BackgroundColor3 = DropDown.BorderColor
		sep.BorderSizePixel = 0
		sep.ZIndex = 5
	end

	return button
end

function CreateRightClickMenu(choices, currentChoice, readOnly, onClick)
	local mouse = game:GetService("Players").LocalPlayer:GetMouse()

	local frame = Instance_new("TextButton")	
	frame.Name = "DropDown"
	frame.Size = UDim2_new(0, 200, 0, 0)
	frame.BackgroundTransparency = 1
	frame.AutoButtonColor = false
	frame.Active = false

	local menu = nil
	local arrow = nil
	local expanded = false
	local margin = DropDown.BorderSizePixel;

	local function hideMenu()
		expanded = false
		if frame then
			frame:Destroy()
			DestroyRightClick()
		end
	end

	local function showMenu()
		expanded = true
		menu = Instance_new("Frame")
		menu.Size = UDim2_new(0, 200, 0, 0)

		for i,name in pairs(choices) do
			if name then
				menu.Size = menu.Size + UDim2_new(0, 0, 0, 20)
			else
				menu.Size = menu.Size + UDim2_new(0, 0, 0, 7)
			end		
		end

		frame.Size = menu.Size + UDim2_new(0, 0, 0, 6)

		menu.Position = UDim2_new(0, 0, 0, 0)
		menu.BackgroundTransparency = 0
		menu.BackgroundColor3 = DropDown.BackColor
		menu.BorderColor3 = DropDown.BorderColor
		menu.BorderSizePixel = DropDown.BorderSizePixel
		menu.Active = true
		menu.ZIndex = 5
		menu.Parent = frame

		local function choice(name)
			onClick(name)
			hideMenu()
		end

		local previous		
		for i,name in pairs(choices) do
			local option = CreateRightClickMenuItem(name, function()
				choice(name)
			end)

			if name then
				option.Size = UDim2_new(1, 0, 0, 20)
			else
				option.Size = UDim2_new(1, 0, 0, 7)
			end

			if previous then
				option.Position = UDim2_new(0, 0, 0, previous.Position.Height.Offset + previous.Size.Height.Offset)
			end

			option.ZIndex = menu.ZIndex
			option.Parent = menu

			previous = option			
		end
	end

	showMenu()

	return frame
end

function checkMouseInGui(gui)
	if gui == nil then return false end
	local plrMouse = game:GetService("Players").LocalPlayer:GetMouse()
	local guiPosition = gui.AbsolutePosition
	local guiSize = gui.AbsoluteSize	

	if plrMouse.X >= guiPosition.x and plrMouse.X <= guiPosition.x + guiSize.x and plrMouse.Y >= guiPosition.y and plrMouse.Y <= guiPosition.y + guiSize.y then
		return true
	else
		return false
	end
end

local clipboard = {}
local function delete(o)
	o.Parent = nil
	RemoteEvent:InvokeServer("Delete", o)
end

local getTextWidth do
	local text = Create('TextLabel',{
		Name = "TextWidth";
		TextXAlignment = 'Left';
		TextYAlignment = 'Center';
		Font = FONT;
		FontSize = FONT_SIZE;
		Text = "";
		Position = UDim2_new(0,0,0,0);
		Size = UDim2_new(1,0,1,0);
		Visible = false;
		Parent = explorerPanel;
	})
	function getTextWidth(s)
		text.Text = s
		return text.TextBounds.x
	end
end

local nameScanned = false