<commit_before>using Uno;
using Uno.Collections;
using Uno.UX;

using Fuse.Internal;
using Fuse.Reactive.Internal;

namespace Fuse.Reactive
{
	/* The code that deals primarily with managing the window items */
	public partial class Instantiator
	{
		Node GetLastNodeFromIndex(int windowIndex)
		{
			if (windowIndex >= _windowItems.Count)
				windowIndex = _windowItems.Count - 1;
				
			while (windowIndex >= 0)
			{
				var lastList = _windowItems[windowIndex].Nodes;
				if (lastList != null && lastList.Count != 0)
					return lastList[lastList.Count-1].GetLastNodeInGroup();

				//support an odd case where an each-item doesn't have any children
				windowIndex--;
			}
			
			return this;
		}
		bool _pendingNew;
		
		/** Inserts a new item into the _windowItems. The actual creation of the objects may be deferred. */
		void InsertNew(int dataIndex)
		{
			if (dataIndex < Offset ||
				(HasLimit && (dataIndex - Offset) >= Limit))
				return;
				
			var windowIndex = DataToWindowIndex(dataIndex);
			if ( windowIndex > _windowItems.Count || windowIndex < 0)
				return;		

			var data = GetData(dataIndex);
			InsertNewWindowItem( windowIndex, data );
		}
		
		/** Inserts a new window item associated with the given data */
		void InsertNewWindowItem( int windowIndex, object data )
		{
			var wi = new WindowItem{ Data = data };
			_windowItems.Insert( windowIndex, wi );
			
			if (Defer == InstanceDefer.Immediate)
			{
				CompleteWindowItem(wi, windowIndex);
			}
			else if (!_pendingNew)
			{
				if (Defer == InstanceDefer.Deferred)
					DeferredManager.AddPending(this, float2(DeferredPriority,NodeDepth) );
				else
					UpdateManager.AddDeferredAction(CompleteWindowItemsAction);
				_pendingNew = true;
			}
			
			OnUpdatedWindowItems();
		}
		
		bool IDeferred.Perform()
		{
			_pendingNew = CompleteWindowItems(true);
			return !_pendingNew;
		}
		
		void CompleteWindowItemsAction()
		{
			CompleteWindowItems(false);
			_pendingNew = false;
		}
		
		bool CompleteWindowItems(bool one)
		{
			//in case unrooted somehow in the meantime
			if (!IsRootingStarted)
				return false;
				
			bool first = true;
			for (int i=0; i < _windowItems.Count; ++i)
			{
				var wi = _windowItems[i];
				if (wi.Nodes == null)
				{
					if (!first && one)
						return true;
						
					CompleteWindowItem(wi, i);
					first = false;
				}
			}

			//TODO: this seems like it's in the wrong location
			//remove whatever is leftover
			RemovePendingAvailableItems();
			return false;
		}
		
		struct TemplateMatch
		{
			//if true then all templates used and `Template` is ignored
			public bool All;
			//the specific Template to use
			public Template Template;
			
			public bool Matches(TemplateMatch b) 
			{
				if (All != b.All)
					return false;
				return Template == b.Template;
			}
		}
		
		TemplateMatch GetDataTemplate(object data)
		{
			// Algorithm for picking matching the right template
			Template useTemplate = null;
			Template defaultTemplate = null;
			
			// Priority 1 - If a TemplateSource and TemplateKey is specified
			if (_templateSource != null && TemplateKey != null)
			{
				var t = _templateSource.FindTemplate(TemplateKey);
				if (t != null)
					useTemplate = t;
			}

			// Priority 2 - use the local templates collection and look for a matching key (if set)
			if (useTemplate == null)
			{
				var key = GetDataKey(data, MatchKey) as string;
				//match Order in FindTemplate (latest is preferred)
				for (int i=Templates.Count-1; i>=0; --i) {
					var f = Templates[i];
					if (f.IsDefault) defaultTemplate = f;
					if (key != null && f.Key == key)
						useTemplate = f;
				}
			}

			// Priority 3 - Use the default template or all templates if no match specified
			if (useTemplate == null)
			{
				if (MatchKey != null || defaultTemplate != null)
					useTemplate = defaultTemplate; //may still be null
				else
					return new TemplateMatch{ All = true, Template = null }; //only unspecified can use complete list
			}
				
			return new TemplateMatch{ All = false, Template = useTemplate };
		}
		
		void CompleteWindowItem(WindowItem wi, int windowIndex)
		{
			wi.Id = GetDataId(wi.Data);
			
			var match = GetDataTemplate(wi.Data);
			AddMatchingTemplates(wi, match);
			
			if ( (wi.Template.All && Templates.Count != wi.Nodes.Count) ||
				(wi.Template.Template != null && wi.Nodes.Count != 1))
			{
				Fuse.Diagnostics.InternalError( "inconsistent instance state", this );
			}
			

			//find last node prior to where we want to introduce
			var lastNode = GetLastNodeFromIndex(windowIndex-1);

			Parent.InsertOrMoveNodes( Parent.Children.IndexOf(lastNode) + 1, wi.Nodes.GetEnumerator() );
		}
		
		/**
			Replaces the data for the current item if it has an id and template match.
		
			@return true if the replacement was successful, false otherwise
		*/
		bool TryUpdateAt(int dataIndex, object newData)
		{
			if (Identity == InstanceIdentity.None)
				return false;
			
			var windowIndex = DataToWindowIndex(dataIndex);
			if (windowIndex < 0 || windowIndex >= _windowItems.Count)
				return false;
				
			var wi = _windowItems[windowIndex];
			var newId = GetDataId(newData);
			if (wi.Id == null || !Object.Equals(wi.Id, newId))
				return false;
				
			var tpl = GetDataTemplate(newData);
			if (!wi.Template.Matches(tpl))
				return false;

				
			var oldData = wi.CurrentData;
			wi.Data = newData;
			UpdateData(wi, oldData);
			return true;
		}

		/* `null` for the template indicates to use all templates, otherwise a specific one will be used. */
		void AddMatchingTemplates(WindowItem item, TemplateMatch f)
 		{
			object oldData = null;
			var av = GetAvailableNodes(f, item.Id);
			if (av != null)
			{
				item.Nodes = av.Nodes;
				oldData = av.CurrentData;
				av.Nodes = null;
			}
			else if (f.All)
			{
				item.Nodes = new List<Node>();
				for (int i=0; i < Templates.Count; ++i) 
					AddTemplate(item, Templates[i]);
			}
			else if (f.Template == null)
			{
				//needed to indicate we've generated the nodes, there just aren't any.
				item.Nodes = new List<Node>();
			}
			else
			{
				item.Nodes = new List<Node>();
				AddTemplate(item, f.Template);
			}

			UpdateData(item, oldData);
 			item.Template = f;
 		}
 		
 		void AddTemplate(WindowItem item, Template f)
 		{
			var elm = f.New() as Node;
			if (elm == null)
			{
				Fuse.Diagnostics.InternalError( "Template contains a non-Node", this );
				return;
			}
			item.Nodes.Add(elm);
 		}
 		<commit_msg>optmize call to InsertNodes or InsertOrMoveNodes<commit_after>using Uno;
using Uno.Collections;
using Uno.UX;

using Fuse.Internal;
using Fuse.Reactive.Internal;

namespace Fuse.Reactive
{
	/* The code that deals primarily with managing the window items */
	public partial class Instantiator
	{
		Node GetLastNodeFromIndex(int windowIndex)
		{
			if (windowIndex >= _windowItems.Count)
				windowIndex = _windowItems.Count - 1;
				
			while (windowIndex >= 0)
			{
				var lastList = _windowItems[windowIndex].Nodes;
				if (lastList != null && lastList.Count != 0)
					return lastList[lastList.Count-1].GetLastNodeInGroup();

				//support an odd case where an each-item doesn't have any children
				windowIndex--;
			}
			
			return this;
		}
		bool _pendingNew;
		
		/** Inserts a new item into the _windowItems. The actual creation of the objects may be deferred. */
		void InsertNew(int dataIndex)
		{
			if (dataIndex < Offset ||
				(HasLimit && (dataIndex - Offset) >= Limit))
				return;
				
			var windowIndex = DataToWindowIndex(dataIndex);
			if ( windowIndex > _windowItems.Count || windowIndex < 0)
				return;		

			var data = GetData(dataIndex);
			InsertNewWindowItem( windowIndex, data );
		}
		
		/** Inserts a new window item associated with the given data */
		void InsertNewWindowItem( int windowIndex, object data )
		{
			var wi = new WindowItem{ Data = data };
			_windowItems.Insert( windowIndex, wi );
			
			if (Defer == InstanceDefer.Immediate)
			{
				CompleteWindowItem(wi, windowIndex);
			}
			else if (!_pendingNew)
			{
				if (Defer == InstanceDefer.Deferred)
					DeferredManager.AddPending(this, float2(DeferredPriority,NodeDepth) );
				else
					UpdateManager.AddDeferredAction(CompleteWindowItemsAction);
				_pendingNew = true;
			}
			
			OnUpdatedWindowItems();
		}
		
		bool IDeferred.Perform()
		{
			_pendingNew = CompleteWindowItems(true);
			return !_pendingNew;
		}
		
		void CompleteWindowItemsAction()
		{
			CompleteWindowItems(false);
			_pendingNew = false;
		}
		
		bool CompleteWindowItems(bool one)
		{
			//in case unrooted somehow in the meantime
			if (!IsRootingStarted)
				return false;
				
			bool first = true;
			for (int i=0; i < _windowItems.Count; ++i)
			{
				var wi = _windowItems[i];
				if (wi.Nodes == null)
				{
					if (!first && one)
						return true;
						
					CompleteWindowItem(wi, i);
					first = false;
				}
			}

			//TODO: this seems like it's in the wrong location
			//remove whatever is leftover
			RemovePendingAvailableItems();
			return false;
		}
		
		struct TemplateMatch
		{
			//if true then all templates used and `Template` is ignored
			public bool All;
			//the specific Template to use
			public Template Template;
			
			public bool Matches(TemplateMatch b) 
			{
				if (All != b.All)
					return false;
				return Template == b.Template;
			}
		}
		
		TemplateMatch GetDataTemplate(object data)
		{
			// Algorithm for picking matching the right template
			Template useTemplate = null;
			Template defaultTemplate = null;
			
			// Priority 1 - If a TemplateSource and TemplateKey is specified
			if (_templateSource != null && TemplateKey != null)
			{
				var t = _templateSource.FindTemplate(TemplateKey);
				if (t != null)
					useTemplate = t;
			}

			// Priority 2 - use the local templates collection and look for a matching key (if set)
			if (useTemplate == null)
			{
				var key = GetDataKey(data, MatchKey) as string;
				//match Order in FindTemplate (latest is preferred)
				for (int i=Templates.Count-1; i>=0; --i) {
					var f = Templates[i];
					if (f.IsDefault) defaultTemplate = f;
					if (key != null && f.Key == key)
						useTemplate = f;
				}
			}

			// Priority 3 - Use the default template or all templates if no match specified
			if (useTemplate == null)
			{
				if (MatchKey != null || defaultTemplate != null)
					useTemplate = defaultTemplate; //may still be null
				else
					return new TemplateMatch{ All = true, Template = null }; //only unspecified can use complete list
			}
				
			return new TemplateMatch{ All = false, Template = useTemplate };
		}
		
		void CompleteWindowItem(WindowItem wi, int windowIndex)
		{
			wi.Id = GetDataId(wi.Data);
			
			var match = GetDataTemplate(wi.Data);
			var reuse = AddMatchingTemplates(wi, match);
			
			if ( (wi.Template.All && Templates.Count != wi.Nodes.Count) ||
				(wi.Template.Template != null && wi.Nodes.Count != 1))
			{
				Fuse.Diagnostics.InternalError( "inconsistent instance state", this );
			}
			

			//find last node prior to where we want to introduce
			var lastNode = GetLastNodeFromIndex(windowIndex-1);

			//InsertOrMove is slower than Insert, thus optimize if we can 
			if (reuse)
				Parent.InsertOrMoveNodes( Parent.Children.IndexOf(lastNode) + 1, wi.Nodes.GetEnumerator() );
			else
				Parent.InsertNodes( Parent.Children.IndexOf(lastNode) + 1, wi.Nodes.GetEnumerator() );
		}
		
		/**
			Replaces the data for the current item if it has an id and template match.
		
			@return true if the replacement was successful, false otherwise
		*/
		bool TryUpdateAt(int dataIndex, object newData)
		{
			if (Identity == InstanceIdentity.None)
				return false;
			
			var windowIndex = DataToWindowIndex(dataIndex);
			if (windowIndex < 0 || windowIndex >= _windowItems.Count)
				return false;
				
			var wi = _windowItems[windowIndex];
			var newId = GetDataId(newData);
			if (wi.Id == null || !Object.Equals(wi.Id, newId))
				return false;
				
			var tpl = GetDataTemplate(newData);
			if (!wi.Template.Matches(tpl))
				return false;

				
			var oldData = wi.CurrentData;
			wi.Data = newData;
			UpdateData(wi, oldData);
			return true;
		}

		/* `null` for the template indicates to use all templates, otherwise a specific one will be used. 
			
			@return true if reusing existing nodes, false if new nodes
		*/
		bool AddMatchingTemplates(WindowItem item, TemplateMatch f)
 		{
			bool reuse = false;
			object oldData = null;
			var av = GetAvailableNodes(f, item.Id);
			if (av != null)
			{
				item.Nodes = av.Nodes;
				oldData = av.CurrentData;
				av.Nodes = null;
				reuse = true;
			}
			else if (f.All)
			{
				item.Nodes = new List<Node>();
				for (int i=0; i < Templates.Count; ++i) 
					AddTemplate(item, Templates[i]);
			}
			else if (f.Template == null)
			{
				//needed to indicate we've generated the nodes, there just aren't any.
				item.Nodes = new List<Node>();
			}
			else
			{
				item.Nodes = new List<Node>();
				AddTemplate(item, f.Template);
			}

			UpdateData(item, oldData);
 			item.Template = f;
 			return reuse;
 		}
 		
 		void AddTemplate(WindowItem item, Template f)
 		{
			var elm = f.New() as Node;
			if (elm == null)
			{
				Fuse.Diagnostics.InternalError( "Template contains a non-Node", this );
				return;
			}
			item.Nodes.Add(elm);
 		}
 		
{'fraction_non_alphanumeric': 0.10515649628462058, 'fraction_numerical': 0.0026270359528634693, 'mean_word_length': 2.828735632183908, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4735869', 'n_tokens_mistral': 5273, 'n_tokens_neox': 4095, 'n_words': 1241}