using System.Windows.Threading;

using MS.Utility;

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace System.Windows
{
    internal class FrameworkContextData
    {
        public static FrameworkContextData From(Dispatcher context)
        {
            FrameworkContextData data = (FrameworkContextData)context.Reserved2;
        
            if (data == null)
            {
                data = new FrameworkContextData();
                context.Reserved2 = data;
            }

            return data;
        }

        // Enforce never creating except via static constructor above.
        private FrameworkContextData()
        {
        }

        //
        // Property Invalidation of Inheritable Properties
        //
        // At the context level, we need to keep track of all inheritable property invalidations currently
        // in action.  The reason that there can be multiple invalidations going on at the same time is because
        // an invalidation of one property can cause an invalidation of a different property.  The result is that
        // the first invalidation *pauses* while the second invalidation is delivered to the tree.
        //
        // We keep track of these invalidations to be able to optimize a recursion of the same property
        // invalidation from an element to that element's children.  FrameworkElement.InvalidateTree will 
        // check the stack of walkers here and, if it finds a match, will conclude that a new DescendentsWalker
        // need not be spun up.  And there was much rejoicing.
        //

        public void AddWalker(object data, DescendentsWalkerBase walker)
        {
            // push a new walker on the top of the stack
            WalkerEntry walkerEntry = new WalkerEntry();
            walkerEntry.Data = data;
            walkerEntry.Walker = walker;
        
            _currentWalkers.Add(walkerEntry);
        }

        public void RemoveWalker(object data, DescendentsWalkerBase walker)
        {
            // pop the walker off the top of the stack
            int last = _currentWalkers.Count - 1;
#if DEBUG        
            WalkerEntry walkerEntry = _currentWalkers[last];
        
            Debug.Assert((walkerEntry.Data == data) && (walkerEntry.Walker == walker),
                "Inheritance DescendentsWalker tracker removal failed");
#endif        
            _currentWalkers.RemoveAt(last);
        }

        public bool WasNodeVisited(DependencyObject d, object data)
        {
            // check to see if the given property on the given object is going to be visited by the
            // DescendentsWalker on the top of the stack
            if (_currentWalkers.Count > 0)
            {
                int last = _currentWalkers.Count - 1;
            
                WalkerEntry walkerEntry = _currentWalkers[last];
            
                if (walkerEntry.Data == data)
                {
                    return walkerEntry.Walker.WasVisited(d);
                }
            }

            return false;
        }

        private struct WalkerEntry
        {
            public object Data; // either the inheritable DP being invalidated, or the AncestorChangedDelegate, or the ResourceChangedDelegate
            public DescendentsWalkerBase Walker;
        }

        private List<WalkerEntry> _currentWalkers = new List<WalkerEntry>(4);
    }
}

