public AnimationLayerCollection()
        {
            defaultLayer = new AnimationLayer();
            defaultLayer.ClockInvalidated += OnAnimationLayerClockInvalidated;

            layers = new Dictionary<AnimationLayerKey, AnimationLayer>();
        }
        internal static void ApplyAnimationClocksToLayer(
            DependencyObject d,
            DependencyProperty dp,
            IList<AnimationClock> animationClocks,
            HandoffBehavior handoffBehavior,
            Int64 propertyTriggerLayerIndex)
        {
            if( propertyTriggerLayerIndex == 1 )
            {
                // Layer 1 is a special layer, where it gets treated as if there
                //  was no layer specification at all.
                ApplyAnimationClocks( d, dp, animationClocks, handoffBehavior );
                return;
            }

            Debug.Assert(animationClocks != null);
            Debug.Assert(!animationClocks.Contains(null));

            Debug.Assert(HandoffBehaviorEnum.IsDefined(handoffBehavior),
                "Public API caller of this internal method is responsible for validating that the HandoffBehavior value is valid.");

            AnimationStorage storage = GetStorage(d, dp);

            if (storage == null)
            {
                storage = CreateStorage(d, dp);
            }

            SortedList<Int64, AnimationLayer> propertyTriggerLayers = storage._propertyTriggerLayers;

            if (propertyTriggerLayers == null)
            {
                propertyTriggerLayers = new SortedList<Int64, AnimationLayer>(1);
                storage._propertyTriggerLayers = propertyTriggerLayers;
            }

            AnimationLayer layer;

            if (propertyTriggerLayers.ContainsKey(propertyTriggerLayerIndex))
            {
                layer = propertyTriggerLayers[propertyTriggerLayerIndex];
            }
            else
            {
                layer = new AnimationLayer(storage);

                propertyTriggerLayers[propertyTriggerLayerIndex] = layer;
            }

            object defaultDestinationValue = DependencyProperty.UnsetValue;

            if (handoffBehavior == HandoffBehavior.SnapshotAndReplace)
            {
                // 
                defaultDestinationValue = ((IAnimatable)d).GetAnimationBaseValue(dp);

                int count = propertyTriggerLayers.Count;

                if (count > 1)
                {
                    IList<Int64> keys = propertyTriggerLayers.Keys;

                    for (int i = 0; i < count && keys[i] < propertyTriggerLayerIndex; i++)
                    {
                        AnimationLayer currentLayer;

                        propertyTriggerLayers.TryGetValue(keys[i], out currentLayer);

                        defaultDestinationValue = currentLayer.GetCurrentValue(defaultDestinationValue);
                    }
                }
            }

            layer.ApplyAnimationClocks(
                animationClocks,
                handoffBehavior,
                defaultDestinationValue);

            storage.WritePostscript();
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="layer"></param>
        internal void RemoveLayer(AnimationLayer layer)
        {
            Debug.Assert(_propertyTriggerLayers != null);
            Debug.Assert(_propertyTriggerLayers.ContainsValue(layer));

            int index = _propertyTriggerLayers.IndexOfValue(layer);

            Debug.Assert(index >= 0);

            _propertyTriggerLayers.RemoveAt(index);

            if (_propertyTriggerLayers.Count == 0)
            {
                _propertyTriggerLayers = null;
            }
        }
        internal static void ApplyAnimationClocksToLayer(
            DependencyObject d,
            DependencyProperty dp,
            IList <AnimationClock> animationClocks,
            HandoffBehavior handoffBehavior,
            Int64 propertyTriggerLayerIndex)
        {
            if (propertyTriggerLayerIndex == 1)
            {
                // Layer 1 is a special layer, where it gets treated as if there
                //  was no layer specification at all.
                ApplyAnimationClocks(d, dp, animationClocks, handoffBehavior);
                return;
            }

            Debug.Assert(animationClocks != null);
            Debug.Assert(!animationClocks.Contains(null));

            Debug.Assert(HandoffBehaviorEnum.IsDefined(handoffBehavior),
                         "Public API caller of this internal method is responsible for validating that the HandoffBehavior value is valid.");

            AnimationStorage storage = GetStorage(d, dp);

            if (storage == null)
            {
                storage = CreateStorage(d, dp);
            }

            SortedList <Int64, AnimationLayer> propertyTriggerLayers = storage._propertyTriggerLayers;

            if (propertyTriggerLayers == null)
            {
                propertyTriggerLayers          = new SortedList <Int64, AnimationLayer>(1);
                storage._propertyTriggerLayers = propertyTriggerLayers;
            }

            AnimationLayer layer;

            if (propertyTriggerLayers.ContainsKey(propertyTriggerLayerIndex))
            {
                layer = propertyTriggerLayers[propertyTriggerLayerIndex];
            }
            else
            {
                layer = new AnimationLayer(storage);

                propertyTriggerLayers[propertyTriggerLayerIndex] = layer;
            }

            object defaultDestinationValue = DependencyProperty.UnsetValue;

            if (handoffBehavior == HandoffBehavior.SnapshotAndReplace)
            {
                //
                defaultDestinationValue = ((IAnimatable)d).GetAnimationBaseValue(dp);

                int count = propertyTriggerLayers.Count;

                if (count > 1)
                {
                    IList <Int64> keys = propertyTriggerLayers.Keys;

                    for (int i = 0; i < count && keys[i] < propertyTriggerLayerIndex; i++)
                    {
                        AnimationLayer currentLayer;

                        propertyTriggerLayers.TryGetValue(keys[i], out currentLayer);

                        defaultDestinationValue = currentLayer.GetCurrentValue(defaultDestinationValue);
                    }
                }
            }

            layer.ApplyAnimationClocks(
                animationClocks,
                handoffBehavior,
                defaultDestinationValue);

            storage.WritePostscript();
        }
        private AnimationLayer GetAnimationLayer(AnimationLayerKey key)
        {
            if (key == AnimationLayerKey.Default)
            {
                return defaultLayer;
            }

            AnimationLayer layer;

            if (!layers.TryGetValue(key, out layer))
            {
                layer = new AnimationLayer();
                layer.ClockInvalidated += OnAnimationLayerClockInvalidated;

                layers.Add(key, layer);
            }

            return layer;
        }