/// <summary>Initializes a new <see cref="JsonSerializer"/> for the specified stream.</summary>
        /// <param name="requestStream">Input stream from which JSON content must be read.</param>
        /// <param name="encoding">Encoding to use for the stream.</param>
        /// <param name="update">indicates whether this is a update operation or not</param>
        /// <param name="dataService">Data service for which the deserializer will act.</param>
        /// <param name="tracker">Tracker to use for modifications.</param>
        internal JsonDeserializer(Stream requestStream, Encoding encoding, bool update, IDataService dataService, UpdateTracker tracker)
            : base(update, dataService, tracker)
        {
            Debug.Assert(requestStream != null, "requestStream != null");

            // JsonReader is using StreamReader.Peek() method. However if the underlying stream does not support seeking 
            // StreamReader.Peek() will always return -1 what causes the JsonReader to think that all data has already been 
            // read and the Json payload is invalid. We need to wrap non-seekable stream with BufferedStream to make it seekable.
            
            // Since in batch cases, we use our own implementation of Stream to read the batch content, we do not want to use BufferedStream in
            // that case, since Peek just works fine in that case. Also, if we use BufferedStream, we get wierd behaviour since BufferedStream
            // tries to read few characters than the batchBoundary and our batch stream implementation does not handle that case well.
            bool useGivenStream = requestStream.CanSeek || BatchStream.IsBatchStream(requestStream);            
            this.jsonReader = new JsonReader(new StreamReader(useGivenStream ? requestStream : new BufferedStream(requestStream), encoding));
        }
        /// <summary>
        /// Populate the properties of the given resource
        /// </summary>
        /// <param name="jsonObject">JsonObjectRecords containing property name and values</param>
        /// <param name="resource">instance of the resource whose properties needs to be populated</param>
        /// <param name="parentResourceSet">resource set where <paramref name="resource"/> belongs to</param>
        /// <param name="parentResourceType">resource type whose properties needs to be populated</param>
        /// <returns>true if any properties were set; false otherwise.</returns>
        private bool PopulateProperties(JsonReader.JsonObjectRecords jsonObject, object resource, ResourceSetWrapper parentResourceSet, ResourceType parentResourceType)
        {
            // Update all the properties specified in the payload. 
            // Don't touch the properties which are not specified. Its upto the provider to interpret
            // the meaning of things which are not specified
            bool changed = false;
            List<ResourceProperty> navProperties = new List<ResourceProperty>();
            List<object> navPropertyValues = new List<object>();

            #region Handle Non-Nav Properties
            foreach (string propertyName in jsonObject.OrderedKeys)
            {
                // Ignore the metadata property
                if (propertyName == XmlConstants.JsonMetadataString)
                {
                    continue;
                }

                // Check if the property exists and try and set the value
                ResourceProperty resourceProperty = parentResourceType.TryResolvePropertyName(propertyName);
                if (resourceProperty == null && parentResourceType.IsOpenType == false)
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidPropertyNameSpecified(propertyName, parentResourceType.FullName));
                }

                // Get the property value, set it appropriately, and mark the object as changed.
                object propertyValue = jsonObject.Entries[propertyName];
                bool existingRelationship;

                // If its a open property
                if (resourceProperty == null)
                {
                    this.HandleOpenTypeProperties(resource, propertyName, propertyValue);
                    changed = true;
                }
                else if (resourceProperty.TypeKind == ResourceTypeKind.ComplexType)
                {
                    SegmentInfo segmentInfo = CreateSegment(resourceProperty, resourceProperty.Name, null, true /* singleResult */);
                    segmentInfo.TargetKind = RequestTargetKind.ComplexObject;
                    propertyValue = this.CreateObject(propertyValue, segmentInfo, false /*topLevel*/, out existingRelationship);
                    SetPropertyValue(resourceProperty, resource, propertyValue, ContentFormat.Json, this.Service);
                    changed = true;
                }
                else if (resourceProperty.TypeKind == ResourceTypeKind.Primitive)
                {
                    // Ignoring the value of key properties in PUT payload
                    if (!this.Update || !resourceProperty.IsOfKind(ResourcePropertyKind.Key))
                    {
                        SetPropertyValue(resourceProperty, resource, propertyValue, ContentFormat.Json, this.Service);
                    }

                    changed = true;
                }
                else
                {
                    Debug.Assert(ResourceTypeKind.EntityType == resourceProperty.TypeKind, "only expecting nav properties");

                    if (IsDeferredElement(propertyValue))
                    {
                        // Skip the deferred element
                        continue;
                    }
                    else
                    {
                        navProperties.Add(resourceProperty);
                        navPropertyValues.Add(propertyValue);
                    }
                }
            }

            #endregion Non-Navigation Properties

            #region Handle Navigation Properties

            Debug.Assert(navProperties.Count == navPropertyValues.Count, "nav properties and nav property values count must be the same");
            
            // The reason why we need to do this is so that we can gaurantee that the nav properties are getting set at the end.
            // This is nice, since we already do this in the atom deserializer. Hence its consistent. Second, we wanted to
            // give a gaurantee that when FK and nav properties are specified in the payload, nav properties always win.
            for (int i = 0; i < navProperties.Count; i++)
            {
                this.HandleNavigationProperty(parentResourceSet, parentResourceType, resource, navProperties[i], navPropertyValues[i]);
                changed = true;
            }            
            
            #endregion Handle Navigation Properties

            return changed;
        }
        /// <summary>
        /// Returns true if the payload is correct for the top level non-entity target.
        /// </summary>
        /// <param name="jsonObject">json object representing the data in the payload.</param>
        /// <param name="segment">information about the last segment in the request uri.</param>
        /// <param name="resource">resource object as specified in the payload.</param>
        /// <returns>returns true if the payload is correct for non-entity resource.</returns>
        private static bool HandleTopLevelNonEntityProperty(JsonReader.JsonObjectRecords jsonObject, SegmentInfo segment, out object resource)
        {
            Debug.Assert(jsonObject != null, "jsonObject != null");
            Debug.Assert(segment != null, "segment != null");
            resource = null;

            if (segment.TargetKind == RequestTargetKind.Primitive ||
                segment.TargetKind == RequestTargetKind.OpenProperty ||
                segment.TargetKind == RequestTargetKind.ComplexObject)
            {
                if (jsonObject.Count == 1 && jsonObject.Entries.TryGetValue(segment.Identifier, out resource))
                {
                    // For open property, assume it to be a primitive or complex payload.
                    // If its targeting an entity, then the type must be specified
                    return true;
                }
                else if (segment.TargetKind != RequestTargetKind.OpenProperty)
                {
                    throw DataServiceException.CreateBadRequestError(Strings.BadRequestStream_InvalidResourceEntity);
                }
            }

            // its an entity resource payload
            return false;
        }