local A="\078\101\120\117\115\087\114\097\112\112\101\100\073\110\115\116\097\110\099\101"local b={Frame={BackgroundColor3="\077\097\105\110\066\097\099\107\103\114\111\117\110\100";BorderColor3="\066\111\114\100\101\114",BorderSizePixel=0},TextLabel={BackgroundTransparency=1;TextColor3="\077\097\105\110\084\101\120\116",TextXAlignment="\076\101\102\116",Font="\083\111\117\114\099\101\083\097\110\115",TextSize=14};TextButton={BackgroundColor3="\066\117\116\116\111\110";BorderColor3="\066\117\116\116\111\110\066\111\114\100\101\114",BorderSizePixel=1;TextColor3="\066\117\116\116\111\110\084\101\120\116",Font="\083\111\117\114\099\101\083\097\110\115",TextSize=14},TextBox={BackgroundColor3="\073\110\112\117\116\070\105\101\108\100\066\097\099\107\103\114\111\117\110\100";BorderColor3="\073\110\112\117\116\070\105\101\108\100\066\111\114\100\101\114",BorderSizePixel=1,TextColor3="\077\097\105\110\084\101\120\116",PlaceholderColor3="\068\105\109\109\101\100\084\101\120\116",TextXAlignment="\076\101\102\116";Font="\083\111\117\114\099\101\083\097\110\115",TextSize=14;ClearTextOnFocus=false;ClipsDescendants=true}}local O=(require(script.Parent.Parent:WaitForChild("\078\101\120\117\115\080\108\117\103\105\110\070\114\097\109\101\119\111\114\107\080\114\111\106\101\099\116"))):GetContext(script)local w=O:GetResource("\066\097\115\101\046\078\101\120\117\115\068\105\115\097\098\108\097\098\108\101\067\111\110\116\097\105\110\101\114")local X=O:GetResource("\080\108\117\103\105\110\046\078\101\120\117\115\080\108\117\103\105\110")local D=O:GetResource("\080\108\117\103\105\110\046\078\101\120\117\115\083\101\116\116\105\110\103\115")local E=w:Extend()E:SetClassName(A)O:SetContextResource(E)local N={}local V=D.GetSettings()local F={}setmetatable(F,{__mode="\118"})E.CachedInstances=F local function e(A)if typeof(A)=="\073\110\115\116\097\110\099\101"then return E.GetInstance(A)end if typeof(A)=="\116\097\098\108\101"then for b,O in pairs(A)do A[b]=e(O)end end return A end local function Z(b)if typeof(b)=="\116\097\098\108\101"then if b.IsA and b:IsA(A)then return b:GetWrappedInstance()else for A,O in pairs(b)do b[A]=Z(O)end end end return b end function E.GetInstance(A)local b=F[A]if typeof(A)=="\115\116\114\105\110\103"then b=E.new(A)F[b:GetWrappedInstance()]=b else if not b then b=E.new(A)F[A]=b end end return b end function E.__new(w,O)w:InitializeSuper()local X=false if typeof(O)=="\115\116\114\105\110\103"then O=Instance.new(O)X=true end w.__ReferenceInstance=O w.__ChangeFunctions={}w.__ColorProperties={}w.__IgnoreChangesQueue={}w.__IgnoreReverseChangesQueue={}w.__NoBackwardsReplicationProperties={}w.Name=O.Name if not F[O]then F[O]=w end w:__SetChangedOverride("\072\105\100\100\101\110",function() end)local function D()if not w:IsEnabled()then return Enum.StudioStyleGuideModifier.Disabled elseif w.Selected then return Enum.StudioStyleGuideModifier.Selected else return Enum.StudioStyleGuideModifier.Default end end local function E(A)local b=V:GetSetting("\083\116\117\100\105\111","\084\104\101\109\101")local X=w[A]w.__IgnoreChangesQueue[A]=true if type(X)=="\115\116\114\105\110\103"or typeof(X)=="\069\110\117\109\073\116\101\109"then local w=D()O[A]=b:GetColor(X,w)else O[A]=X end end local function e()for A,b in pairs(w.__ColorProperties)do E(A)end end table.insert(w.__ConnectionsToClear,(settings()).Studio.ThemeChanged:Connect(e))w:__SetChangedOverride("\068\105\115\097\098\108\101\100",e)w:__SetChangedOverride("\083\101\108\101\099\116\101\100",e)local Z=w.__ChangeFunctions local y=w.__ColorProperties local q=w.__IgnoreReverseChangesQueue local v=w.__IgnoreChangesQueue local x=w.__NoBackwardsReplicationProperties local I=w.__rawget w:AddGenericPropertyFinalizer(function(b,w)local X=Z[b]if X then X()return end if q[b]then q[b]=nil return end if string.sub(b,1,2)~="\095\095"then local X=O[b]local D=typeof(X)local N=typeof(w)if D=="\067\111\108\111\114\051"then y[b]=true E(b)elseif(D=="\073\110\115\116\097\110\099\101"or X==nil)and(N=="\116\097\098\108\101"and(w.IsA and w:IsA(A)))then v[b]=true O[b]=w:GetWrappedInstance()else v[b]=true O[b]=w end end end)table.insert(w.__ConnectionsToClear,O.Changed:Connect(function(A)if not N[A]and not x[A]then pcall(function()local b,X=w[A],O[A]if not v[A]or b~=X and typeof(b)==typeof(X)then v[A]=nil q[A]=true if b~=X then w[A]=X else w.Changed:Fire(A);(w:GetPropertyChangedSignal(A)):Fire()end end end)end end))w.Selected=false if X then local A=b[O.ClassName]if A then for A,b in pairs(A)do w[A]=b end end end end function E.__getindex(O,A,b)if b==nil and A~="\095\095\082\101\102\101\114\101\110\099\101\073\110\115\116\097\110\099\101"then local b,w=pcall(function()local b=O.__ReferenceInstance local w=b[A]local X=e(w)if type(w)=="\102\117\110\099\116\105\111\110"then X=function(...)local A={...}A=Z(A)local b={w(unpack(A))}b=e(b)return unpack(b)end end return X end)if b then return w,true end end return E.super:__getindex(A,b)end function E.__PreInitializeClone(A)return E.new((A:GetWrappedInstance()):Clone())end function E.__SetChangedOverride(O,A,b)O.__ChangeFunctions[A]=b end function E.IsA(b,A)return b.ClassName==A or b.super:IsA(A)or(b:GetWrappedInstance()):IsA(A)end function E.GetWrappedInstance(A)return A.__ReferenceInstance end function E.Destroy(A)A.super:Destroy()local b=A:GetWrappedInstance()if b then b:Destroy()end end return E
--[[
TheNexusAvenger

Wraps a Roblox Instance with the NexusContainer API.
--]]

local CLASS_NAME = "NexusWrappedInstance"

local INSTANCE_CREATION_PRESETS = {
	Frame = {
		BackgroundColor3 = "MainBackground",
		BorderColor3 = "Border",
		BorderSizePixel = 0,
	},
	TextLabel = {
		BackgroundTransparency = 1,
		TextColor3 = "MainText",
		TextXAlignment = "Left",
		Font = "SourceSans",
		TextSize = 14,
	},
	TextButton = {
		BackgroundColor3 = "Button",
		BorderColor3 = "ButtonBorder",
		BorderSizePixel = 1,
		TextColor3 = "ButtonText",
		Font = "SourceSans",
		TextSize = 14,
	},
	TextBox = {
		BackgroundColor3 = "InputFieldBackground",
		BorderColor3 = "InputFieldBorder",
		BorderSizePixel = 1,
		TextColor3 = "MainText",
		PlaceholderColor3 = "DimmedText",
		TextXAlignment = "Left",
		Font = "SourceSans",
		TextSize = 14,
		ClearTextOnFocus = false,
		ClipsDescendants = true,
	}
}



local NexusPluginFramework = require(script.Parent.Parent:WaitForChild("NexusPluginFrameworkProject")):GetContext(script)
local NexusDisablableContainer = NexusPluginFramework:GetResource("Base.NexusDisablableContainer")
local NexusPlugin = NexusPluginFramework:GetResource("Plugin.NexusPlugin")
local NexusSettings = NexusPluginFramework:GetResource("Plugin.NexusSettings")

local NexusWrappedInstance = NexusDisablableContainer:Extend()
NexusWrappedInstance:SetClassName(CLASS_NAME)
NexusPluginFramework:SetContextResource(NexusWrappedInstance)

local ReadOnlyProperties = {}
local Settings = NexusSettings.GetSettings()

local CachedInstances = {}
setmetatable(CachedInstances,{__mode="v"})
NexusWrappedInstance.CachedInstances = CachedInstances



--[[
Replaces an instance or table of instances with 
wrapped instances.
--]]
local function ReplaceInstances(InstanceOrTable)
	--Replace the Instance if it is an instance.
	if typeof(InstanceOrTable) == "Instance" then
		return NexusWrappedInstance.GetInstance(InstanceOrTable)
	end
	
	--Replace parts of the table if it is a table.
	if typeof(InstanceOrTable) == "table" then
		for Key,Value in pairs(InstanceOrTable) do
			InstanceOrTable[Key] = ReplaceInstances(Value)
		end
	end
	
	--Return the original type.
	return InstanceOrTable
end

--[[
Unwraps a NexusContainer or table of NexusContainers with 
unwrapped instances.
--]]
local function UnwrapInstances(ContainerOrTable)
	--Replace parts of the table if it is a table or unwrap the instance if it is a container.
	if typeof(ContainerOrTable) == "table" then
		if ContainerOrTable.IsA and ContainerOrTable:IsA(CLASS_NAME) then
			return ContainerOrTable:GetWrappedInstance()
		else
			for Key,Value in pairs(ContainerOrTable) do
				ContainerOrTable[Key] = UnwrapInstances(Value)
			end
		end
	end
	
	--Return the original type.
	return ContainerOrTable
end



--[[
Gets a Nexus Wrapped Instance.
--]]
function NexusWrappedInstance.GetInstance(ExistingInstance)
	--Create the string instance or create the cached instance if needed.
	local CachedInstance = CachedInstances[ExistingInstance]
	if typeof(ExistingInstance) == "string" then
		CachedInstance = NexusWrappedInstance.new(ExistingInstance)
		CachedInstances[CachedInstance:GetWrappedInstance()] = CachedInstance
	else
		if not CachedInstance then
			CachedInstance = NexusWrappedInstance.new(ExistingInstance)
			CachedInstances[ExistingInstance] = CachedInstance
		end
	end
	
	--Return the cached entry.
	return CachedInstance
end



--[[
Creates a Nexus Wrapped Instance object.
--]]
function NexusWrappedInstance:__new(ExistingInstance)
	self:InitializeSuper()
	
	--Convert the ExistingInstance if it is a string.
	local AddDefaults = false
	if typeof(ExistingInstance) == "string" then
		ExistingInstance = Instance.new(ExistingInstance)
		AddDefaults = true
	end
	
	--Initialize the class.
	self.__ReferenceInstance = ExistingInstance
	self.__ChangeFunctions = {}
	self.__ColorProperties = {}
	self.__IgnoreChangesQueue = {}
	self.__IgnoreReverseChangesQueue = {}
	self.__NoBackwardsReplicationProperties = {}
	self.Name = ExistingInstance.Name
	
	--Register the wrapped instance.
	if not CachedInstances[ExistingInstance] then
		CachedInstances[ExistingInstance] = self
	end
	
	--Set up changes to Hidden not affecting anything.
	self:__SetChangedOverride("Hidden",function() end)
	
	--[[
	Returns the current color modifier.
	--]]
	local function GetColorModifier()
		if not self:IsEnabled() then
			return Enum.StudioStyleGuideModifier.Disabled
		elseif self.Selected then
			return Enum.StudioStyleGuideModifier.Selected
		else
			return Enum.StudioStyleGuideModifier.Default
		end
	end
	
	--[[
	Updates a color property.
	--]]
	local function UpdateColorProperty(PropertyName)
		local Theme = Settings:GetSetting("Studio","Theme")
		local Color = self[PropertyName]
		
		--Set the color.
		self.__IgnoreChangesQueue[PropertyName] = true
		if type(Color) == "string" or typeof(Color) == "EnumItem" then
			local ColorModifier = GetColorModifier()
			ExistingInstance[PropertyName] = Theme:GetColor(Color,ColorModifier)
		else
			ExistingInstance[PropertyName] = Color
		end
	end
	
	--[[
	Updates all of the color properties.
	--]]
	local function UpdateAllColorProperties()
		for ColorPropertyName,_ in pairs(self.__ColorProperties) do
			UpdateColorProperty(ColorPropertyName)
		end
	end
	
	--Set up changing the colors when the setting changes.
	table.insert(self.__ConnectionsToClear,settings()["Studio"].ThemeChanged:Connect(UpdateAllColorProperties))
	
	--Set up changing colors when enabled/disabled and selected/deselected.
	self:__SetChangedOverride("Disabled",UpdateAllColorProperties)
	self:__SetChangedOverride("Selected",UpdateAllColorProperties)
	
	--Mirror changes to the wrapped object.
	local ChangedFunctions = self.__ChangeFunctions
	local ColorProperties = self.__ColorProperties
	local IgnoreReverseChangesQueue = self.__IgnoreReverseChangesQueue
	local IgnoreChangesQueue = self.__IgnoreChangesQueue
	local NoBackwardsReplicationProperties = self.__NoBackwardsReplicationProperties
	local RawGet = self.__rawget
	self:AddGenericPropertyFinalizer(function(PropertyName,NewProperty)
		--If an overriden change function exists, call it.
		local ChangedFunction = ChangedFunctions[PropertyName]
		if ChangedFunction then
			ChangedFunction()
			return
		end
		
		--If a property was replicated to here, return.
		if IgnoreReverseChangesQueue[PropertyName] then
			IgnoreReverseChangesQueue[PropertyName] = nil
			return
		end
		
		--Mirror the property.
		if string.sub(PropertyName,1,2) ~= "__" then
			local ExistingProperty = ExistingInstance[PropertyName]
			local ExistingPropertyType = typeof(ExistingProperty)
			local NewPropertyType = typeof(NewProperty)
			
			if ExistingPropertyType == "Color3" then
				ColorProperties[PropertyName] = true
				UpdateColorProperty(PropertyName)
			elseif (ExistingPropertyType == "Instance" or ExistingProperty == nil) and (NewPropertyType == "table" and NewProperty.IsA and NewProperty:IsA(CLASS_NAME)) then
				IgnoreChangesQueue[PropertyName] = true
				ExistingInstance[PropertyName] = NewProperty:GetWrappedInstance()
			else
				IgnoreChangesQueue[PropertyName] = true
				ExistingInstance[PropertyName] = NewProperty
			end
		end
	end)
	
	--Mirror changes from the instance.
	table.insert(self.__ConnectionsToClear,ExistingInstance.Changed:Connect(function(PropertyName)
		if not ReadOnlyProperties[PropertyName] and not NoBackwardsReplicationProperties[PropertyName] then
			--Wrap the error.
			pcall(function()
				--Set the changed property or fire a changed signal.
				local ExistingValue,NewValue = self[PropertyName],ExistingInstance[PropertyName]
				if not IgnoreChangesQueue[PropertyName] or (ExistingValue ~= NewValue and typeof(ExistingValue) == typeof(NewValue)) then
					IgnoreChangesQueue[PropertyName] = nil
					IgnoreReverseChangesQueue[PropertyName] = true
					
					--Change the property or fire the changed signals if there is no changes.
					if ExistingValue ~= NewValue then
						self[PropertyName] = NewValue
					else
						self.Changed:Fire(PropertyName)
						self:GetPropertyChangedSignal(PropertyName):Fire()
					end
				end
			end)
		end
	end))
	
	--Set the selected property to be false.
	self.Selected = false
	
	--Set the defaults.
	if AddDefaults then
		local Defaults = INSTANCE_CREATION_PRESETS[ExistingInstance.ClassName]
		if Defaults then
			for Key,Property in pairs(Defaults) do
				self[Key] = Property
			end
		end
	end
end

--[[
Returns the value for a custom index. If the second
value returned is true, it will force return the
returned value, even if it is nil. If not, regular
indexing will be used.
--]]
function NexusWrappedInstance:__getindex(IndexName,OriginalReturn)
	--Return a passed-through property.
	if OriginalReturn == nil and IndexName ~= "__ReferenceInstance" then
		local Worked,Return = pcall(function()
			local ReferenceInstance = self.__ReferenceInstance
			local Return = ReferenceInstance[IndexName]
			local NewReturn = ReplaceInstances(Return)
			
			--Modify the return if it is a function or a Roblox Instance.
			if type(Return) == "function" then
				NewReturn = function(...)
					--Unwrap the instances.
					local Arguments = {...}
					Arguments = UnwrapInstances(Arguments)
					
					--Run the method and replace the instances.
					local MethodReturn = {Return(unpack(Arguments))}
					MethodReturn = ReplaceInstances(MethodReturn)
					
					--Unpack the return.
					return unpack(MethodReturn)
				end
			end
			
			--Return the Instance return.
			return NewReturn
		end)
		
		--Return the result if there was no error (was able to index the Instance).
		if Worked then
			return Return,true
		end
	end
	
	--Return the parent.
	return NexusWrappedInstance.super:__getindex(IndexName,OriginalReturn)
end

--[[
Returns a pre-initialized clone. Only the constructor
should be run with all properties added afterwards
except those starting with "__".
--]]
function NexusWrappedInstance:__PreInitializeClone()
	return NexusWrappedInstance.new(self:GetWrappedInstance():Clone())
end

--[[
Adds an change overrider that prevents mirroring to
the wrapped instance.
--]]
function NexusWrappedInstance:__SetChangedOverride(PropertyName,Function)
	self.__ChangeFunctions[PropertyName] = Function
end

--[[
Returns if the instance is or inherits from a class of that name.
--]]
function NexusWrappedInstance:IsA(ClassName)
	return self.ClassName == ClassName or self.super:IsA(ClassName) or self:GetWrappedInstance():IsA(ClassName)
end

--[[
Returns the wrapped instance.
--]]
function NexusWrappedInstance:GetWrappedInstance()
	return self.__ReferenceInstance
end

--[[
Sets the NexusContainer.Parent property to nil,
locks the NexusContainer.Parent property,
and calls Destroy on all children.
--]]
function NexusWrappedInstance:Destroy()
	self.super:Destroy()
	
	local Ins = self:GetWrappedInstance()
	if Ins then
		Ins:Destroy()
	end
end



return NexusWrappedInstance