/// <summary>
            /// Reorders the buffered properties to conform to the required payload order.
            /// </summary>
            /// <remarks>
            /// The required order is: odata.context comes first, odata.removed comes next (for deleted resources),
            /// then comes odata.type, then all odata.* property annotations
            /// and finally, we preserve the relative order of custom annotations and data properties.</remarks>
            internal void Reorder()
            {
                BufferedNode currentNode = this.ObjectStart;

                // Sort the property names preserving the relative order of the properties except for the OData instance annotations.
                IEnumerable <string> sortedPropertyNames = this.SortPropertyNames();

                foreach (string propertyName in sortedPropertyNames)
                {
                    Debug.Assert(this.propertyCache.ContainsKey(propertyName), "Property must be in the cache for its name to be in the list of property names.");
                    object           storedValue    = this.propertyCache[propertyName];
                    BufferedProperty storedProperty = storedValue as BufferedProperty;
                    if (storedProperty != null)
                    {
                        storedProperty.InsertAfter(currentNode);
                        currentNode = storedProperty.EndOfPropertyValueNode;
                    }
                    else
                    {
                        IEnumerable <BufferedProperty> sortedProperties = SortBufferedProperties((IList <BufferedProperty>)storedValue);
                        foreach (BufferedProperty sortedProperty in sortedProperties)
                        {
                            sortedProperty.InsertAfter(currentNode);
                            currentNode = sortedProperty.EndOfPropertyValueNode;
                        }
                    }
                }
            }
            /// <summary>
            /// Adds a new buffered property to the list of buffered properties for this object.
            /// </summary>
            /// <param name="propertyName">The name of the data property (null for instance annotations).</param>
            /// <param name="annotationName">The name of the annotation (null for data properties).</param>
            /// <param name="bufferedProperty">The buffered property to add.</param>
            internal void AddBufferedProperty(string propertyName, string annotationName, BufferedProperty bufferedProperty)
            {
                this.CurrentProperty = bufferedProperty;
                string lookupName = propertyName ?? annotationName;

                // We have to record the relative positions of all properties so we can later on properly sort them.
                // Note that we have to also capture the positions of the property annotations as long as we have not
                // seen a data property for that annotation since the data property might be missing.
                if (propertyName == null)
                {
                    this.propertyNamesWithAnnotations.Add(new KeyValuePair <string, string>(annotationName, null));
                }
                else if (!this.dataProperties.Contains(propertyName))
                {
                    if (annotationName == null)
                    {
                        this.dataProperties.Add(propertyName);
                    }

                    this.propertyNamesWithAnnotations.Add(new KeyValuePair <string, string>(propertyName, annotationName));
                }

                object storedValue;

                if (this.propertyCache.TryGetValue(lookupName, out storedValue))
                {
                    Debug.Assert(storedValue != null, "storedValue != null");
                    List <BufferedProperty> storedProperties;

                    BufferedProperty storedProperty = storedValue as BufferedProperty;
                    if (storedProperty != null)
                    {
                        storedProperties = new List <BufferedProperty>(4);
                        storedProperties.Add(storedProperty);
                        this.propertyCache[lookupName] = storedProperties;
                    }
                    else
                    {
                        storedProperties = (List <BufferedProperty>)storedValue;
                    }

                    storedProperties.Add(bufferedProperty);
                }
                else
                {
                    this.propertyCache.Add(lookupName, bufferedProperty);
                }
            }
            /// <summary>
            /// Sort the data properties and property annotations stored for a particular property name.
            /// </summary>
            /// <param name="bufferedProperties">The list of buffered properties to sort.</param>
            /// <returns>The sorted enumerable of buffered properties.</returns>
            /// <remarks>The sort order is for all odata.* property annotations to come before the data property
            /// but otherwise preserve the relative order of custom property annotations with regard to the position of the data property.</remarks>
            private static IEnumerable <BufferedProperty> SortBufferedProperties(IList <BufferedProperty> bufferedProperties)
            {
                Debug.Assert(bufferedProperties != null && bufferedProperties.Count > 1, "bufferedProperties != null && bufferedProperties.Count > 1");

                // NOTE: we re-order the property annotations so that ...
                //       1) all odata.* property annotations come before the data property.
                //       2) we preserve the relative order of custom property annotations with regard to the data property.
                List <BufferedProperty> delayedProperties = null;

                for (int i = 0; i < bufferedProperties.Count; ++i)
                {
                    BufferedProperty bufferedProperty = bufferedProperties[i];

                    string annotationName = bufferedProperty.PropertyAnnotationName;
                    if (annotationName == null || !IsODataInstanceAnnotation(annotationName))
                    {
                        // This is either the data property or a custom annotation; we have to delay reporting it until we reported all OData.* annotations
                        if (delayedProperties == null)
                        {
                            delayedProperties = new List <BufferedProperty>();
                        }

                        delayedProperties.Add(bufferedProperty);
                    }
                    else
                    {
                        yield return(bufferedProperty);
                    }
                }

                // If we delayed reporting of any property annotations, report them now preserving their relative order.
                if (delayedProperties != null)
                {
                    for (int i = 0; i < delayedProperties.Count; ++i)
                    {
                        yield return(delayedProperties[i]);
                    }
                }
            }
        /// <summary>
        /// Asynchronously called whenever we find a new object value in the payload.
        /// Buffers and re-orders an object value for later consumption by the JsonLight reader.
        /// </summary>
        /// <remarks>
        /// This method is called when the reader is in the buffering mode and can read ahead (buffering) as much as it needs to
        /// once it returns the reader will be returned to the position before the method was called.
        /// The reader is always positioned on a start object when this method is called.
        /// </remarks>
        protected override async Task ProcessObjectValueAsync()
        {
            Debug.Assert(this.currentBufferedNode.NodeType == JsonNodeType.StartObject, "this.currentBufferedNode.NodeType == JsonNodeType.StartObject");
            this.AssertBuffering();

            Stack <BufferedObject> bufferedObjectStack = new Stack <BufferedObject>();

            while (true)
            {
                switch (this.currentBufferedNode.NodeType)
                {
                case JsonNodeType.StartObject:
                {
                    // New object record - add the node to our stack
                    BufferedObject bufferedObject = new BufferedObject {
                        ObjectStart = this.currentBufferedNode
                    };
                    bufferedObjectStack.Push(bufferedObject);

                    // See if it's an in-stream error
                    await base.ProcessObjectValueAsync()
                    .ConfigureAwait(false);

                    this.currentBufferedNode = bufferedObject.ObjectStart;

                    await this.ReadInternalAsync()
                    .ConfigureAwait(false);
                }

                break;

                case JsonNodeType.EndObject:
                {
                    // End of object record
                    // Pop the node from our stack
                    BufferedObject bufferedObject = bufferedObjectStack.Pop();

                    // If there is a previous property record, mark its last value node.
                    if (bufferedObject.CurrentProperty != null)
                    {
                        bufferedObject.CurrentProperty.EndOfPropertyValueNode = this.currentBufferedNode.Previous;
                    }

                    // Now perform the re-ordering on the buffered nodes
                    bufferedObject.Reorder();

                    if (bufferedObjectStack.Count == 0)
                    {
                        // No more objects to process - we're done.
                        return;
                    }

                    await this.ReadInternalAsync()
                    .ConfigureAwait(false);
                }

                break;

                case JsonNodeType.Property:
                {
                    BufferedObject bufferedObject = bufferedObjectStack.Peek();

                    // If there is a current property, mark its last value node.
                    if (bufferedObject.CurrentProperty != null)
                    {
                        bufferedObject.CurrentProperty.EndOfPropertyValueNode = this.currentBufferedNode.Previous;
                    }

                    BufferedProperty bufferedProperty = new BufferedProperty();
                    bufferedProperty.PropertyNameNode = this.currentBufferedNode;

                    string propertyName, annotationName;
                    Tuple <string, string> readPropertyNameResult = await this.ReadPropertyNameAsync()
                                                                    .ConfigureAwait(false);

                    propertyName   = readPropertyNameResult.Item1;
                    annotationName = readPropertyNameResult.Item2;

                    bufferedProperty.PropertyAnnotationName = annotationName;
                    bufferedObject.AddBufferedProperty(propertyName, annotationName, bufferedProperty);

                    if (annotationName != null)
                    {
                        // Instance-level property annotation - no reordering in its value
                        // or instance-level annotation - no reordering in its value either
                        // So skip its value while buffering.
                        await this.BufferValueAsync()
                        .ConfigureAwait(false);
                    }
                }

                break;

                default:
                    // Read over (buffer) everything else
                    await this.ReadInternalAsync()
                    .ConfigureAwait(false);

                    break;
                }
            }
        }
        /// <summary>
        /// Called whenever we find a new object value in the payload.
        /// Buffers and re-orders an object value for later consumption by the JsonLight reader.
        /// </summary>
        /// <remarks>
        /// This method is called when the reader is in the buffering mode and can read ahead (buffering) as much as it needs to
        /// once it returns the reader will be returned to the position before the method was called.
        /// The reader is always positioned on a start object when this method is called.
        /// </remarks>
        protected override void ProcessObjectValue()
        {
            Debug.Assert(this.currentBufferedNode.NodeType == JsonNodeType.StartObject, "this.currentBufferedNode.NodeType == JsonNodeType.StartObject");
            this.AssertBuffering();

            Stack<BufferedObject> bufferedObjectStack = new Stack<BufferedObject>();
            while (true)
            {
                switch (this.currentBufferedNode.NodeType)
                {
                    case JsonNodeType.StartObject:
                        {
                            // New object record - add the node to our stack
                            BufferedObject bufferedObject = new BufferedObject { ObjectStart = this.currentBufferedNode };
                            bufferedObjectStack.Push(bufferedObject);

                            // See if it's an in-stream error
                            base.ProcessObjectValue();
                            this.currentBufferedNode = bufferedObject.ObjectStart;

                            this.ReadInternal();
                        }

                        break;
                    case JsonNodeType.EndObject:
                        {
                            // End of object record
                            // Pop the node from our stack
                            BufferedObject bufferedObject = bufferedObjectStack.Pop();

                            // If there is a previous property record, mark its last value node.
                            if (bufferedObject.CurrentProperty != null)
                            {
                                bufferedObject.CurrentProperty.EndOfPropertyValueNode = this.currentBufferedNode.Previous;
                            }

                            // Now perform the re-ordering on the buffered nodes
                            bufferedObject.Reorder();

                            if (bufferedObjectStack.Count == 0)
                            {
                                // No more objects to process - we're done.
                                return;
                            }

                            this.ReadInternal();
                        }

                        break;
                    case JsonNodeType.Property:
                        {
                            BufferedObject bufferedObject = bufferedObjectStack.Peek();

                            // If there is a current property, mark its last value node.
                            if (bufferedObject.CurrentProperty != null)
                            {
                                bufferedObject.CurrentProperty.EndOfPropertyValueNode = this.currentBufferedNode.Previous;
                            }

                            BufferedProperty bufferedProperty = new BufferedProperty();
                            bufferedProperty.PropertyNameNode = this.currentBufferedNode;

                            string propertyName;
                            string annotationName;
                            this.ReadPropertyName(out propertyName, out annotationName);

                            bufferedProperty.PropertyAnnotationName = annotationName;
                            bufferedObject.AddBufferedProperty(propertyName, annotationName, bufferedProperty);

                            if (annotationName != null)
                            {
                                // Instance-level property annotation - no reordering in its value
                                // or instance-level annotation - no reordering in its value either
                                // So skip its value while buffering.
                                this.BufferValue();
                            }
                        }

                        break;

                    default:
                        // Read over (buffer) everything else
                        this.ReadInternal();
                        break;
                }
            }
        }
            /// <summary>
            /// Adds a new buffered property to the list of buffered properties for this object.
            /// </summary>
            /// <param name="propertyName">The name of the data property (null for instance annotations).</param>
            /// <param name="annotationName">The name of the annotation (null for data properties).</param>
            /// <param name="bufferedProperty">The buffered property to add.</param>
            internal void AddBufferedProperty(string propertyName, string annotationName, BufferedProperty bufferedProperty)
            {
                this.CurrentProperty = bufferedProperty;
                string lookupName = propertyName ?? annotationName;

                // We have to record the relative positions of all properties so we can later on propertly sort them.
                // Note that we have to also capture the positions of the property annotations as long as we have not
                // seen a data property for that annotation since the data property might be missing.
                if (propertyName == null)
                {
                    this.propertyNamesWithAnnotations.Add(new KeyValuePair<string, string>(annotationName, null));
                }
                else if (!this.dataProperties.Contains(propertyName))
                {
                    if (annotationName == null)
                    {
                        this.dataProperties.Add(propertyName);
                    }

                    this.propertyNamesWithAnnotations.Add(new KeyValuePair<string, string>(propertyName, annotationName));
                }

                object storedValue;
                if (this.propertyCache.TryGetValue(lookupName, out storedValue))
                {
                    Debug.Assert(storedValue != null, "storedValue != null");
                    List<BufferedProperty> storedProperties;

                    BufferedProperty storedProperty = storedValue as BufferedProperty;
                    if (storedProperty != null)
                    {
                        storedProperties = new List<BufferedProperty>(4);
                        storedProperties.Add(storedProperty);
                        this.propertyCache[lookupName] = storedProperties;
                    }
                    else
                    {
                        storedProperties = (List<BufferedProperty>)storedValue;
                    }

                    storedProperties.Add(bufferedProperty);
                }
                else
                {
                    this.propertyCache.Add(lookupName, bufferedProperty);
                }
            }