/// <summary>
        /// Creates a navigation link info for a projected navigation link that is missing from the payload.
        /// </summary>
        /// <param name="navigationProperty">The navigation property for which the link will be reported.</param>
        /// <returns>The navigation link info created.</returns>
        internal static ODataJsonLightReaderNavigationLinkInfo CreateProjectedNavigationLinkInfo(IEdmNavigationProperty navigationProperty)
        {
            Debug.Assert(navigationProperty != null, "navigationProperty != null");

            ODataNavigationLink navigationLink = new ODataNavigationLink {
                Name = navigationProperty.Name, IsCollection = navigationProperty.Type.IsCollection()
            };
            ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ false);

            return(navigationLinkInfo);
        }
        /// <summary>
        /// Creates a navigation link info for an expanded entry link.
        /// </summary>
        /// <param name="navigationLink">The navigation link to report.</param>
        /// <param name="navigationProperty">The navigation property for which the link will be reported.</param>
        /// <returns>The navigation link info created.</returns>
        internal static ODataJsonLightReaderNavigationLinkInfo CreateExpandedEntryLinkInfo(
            ODataNavigationLink navigationLink,
            IEdmNavigationProperty navigationProperty)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(navigationLink.IsCollection == false, "Expanded entry can only be reported for a singleton navigation link.");

            ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ true);

            return(navigationLinkInfo);
        }
        /// <summary>
        /// Creates a navigation link info for an expanded feed link.
        /// </summary>
        /// <param name="navigationLink">The navigation link to report.</param>
        /// <param name="navigationProperty">The navigation property for which the link will be reported.</param>
        /// <param name="expandedFeed">The expanded feed for the navigation link to report.</param>
        /// <returns>The navigation link info created.</returns>
        internal static ODataJsonLightReaderNavigationLinkInfo CreateExpandedFeedLinkInfo(
            ODataNavigationLink navigationLink,
            IEdmNavigationProperty navigationProperty,
            ODataFeed expandedFeed)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(navigationLink.IsCollection == true, "Expanded feeds can only be reported for collection navigation links.");
            Debug.Assert(expandedFeed != null, "expandedFeed != null");

            ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ true);

            navigationLinkInfo.expandedFeed = expandedFeed;
            return(navigationLinkInfo);
        }
        /// <summary>
        /// Creates a navigation link info for a collection of entity reference links.
        /// </summary>
        /// <param name="navigationLink">The navigation link to report.</param>
        /// <param name="navigationProperty">The navigation property for which the link will be reported.</param>
        /// <param name="entityReferenceLinks">The entity reference links for the navigation link to report.</param>
        /// <param name="isExpanded">true if the navigation link is expanded.</param>
        /// <returns>The navigation link info created.</returns>
        internal static ODataJsonLightReaderNavigationLinkInfo CreateCollectionEntityReferenceLinksInfo(
            ODataNavigationLink navigationLink,
            IEdmNavigationProperty navigationProperty,
            LinkedList <ODataEntityReferenceLink> entityReferenceLinks,
            bool isExpanded)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(navigationLink.IsCollection == true, "Collection entity reference can only be reported for a collection navigation links.");
            Debug.Assert(navigationProperty != null, "navigationProperty != null");
            Debug.Assert(entityReferenceLinks == null || entityReferenceLinks.Count > 0, "entityReferenceLinks == null || entityReferenceLinks.Count > 0");

            ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, isExpanded);

            navigationLinkInfo.entityReferenceLinks = entityReferenceLinks;
            return(navigationLinkInfo);
        }
        /// <summary>
        /// Creates a navigation link info for a singleton entity reference link.
        /// </summary>
        /// <param name="navigationLink">The navigation link to report.</param>
        /// <param name="navigationProperty">The navigation property for which the link will be reported.</param>
        /// <param name="entityReferenceLink">The entity reference link for the navigation link to report.</param>
        /// <param name="isExpanded">true if the navigation link is expanded.</param>
        /// <returns>The navigation link info created.</returns>
        internal static ODataJsonLightReaderNavigationLinkInfo CreateSingletonEntityReferenceLinkInfo(
            ODataNavigationLink navigationLink,
            IEdmNavigationProperty navigationProperty,
            ODataEntityReferenceLink entityReferenceLink,
            bool isExpanded)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(navigationLink.IsCollection == false, "Singleton entity reference can only be reported for a singleton navigation links.");
            Debug.Assert(navigationProperty != null, "navigationProperty != null");

            ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, isExpanded);

            if (entityReferenceLink != null)
            {
                navigationLinkInfo.entityReferenceLinks = new LinkedList <ODataEntityReferenceLink>();
                navigationLinkInfo.entityReferenceLinks.AddFirst(entityReferenceLink);
            }

            return(navigationLinkInfo);
        }
        /// <summary>
        /// Reads any next link annotation immediately after the end of a feed.
        /// </summary>
        /// <param name="feed">The feed being read.</param>
        /// <param name="expandedNavigationLinkInfo">The information about the expanded link. This must be non-null if we're reading an expanded feed, and must be null if we're reading a top-level feed.</param>
        /// <param name="duplicatePropertyNamesChecker">The top-level duplicate property names checker, if we're reading a top-level feed.</param>
        internal void ReadNextLinkAnnotationAtFeedEnd(
            ODataFeedBase feed,
            ODataJsonLightReaderNavigationLinkInfo expandedNavigationLinkInfo,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker)
        {
            Debug.Assert(feed != null, "feed != null");

            // Check for annotations on the feed that occur after the feed itself. (Note: the only allowed one is odata.nextLink, and we fail for anything else.)
            // We do this slightly differently depending on whether the feed was an expanded navigation or a top-level feed.
            if (expandedNavigationLinkInfo != null)
            {
                this.ReadExpandedFeedAnnotationsAtFeedEnd(feed, expandedNavigationLinkInfo);
            }
            else
            {
                Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null");

                // Check for feed instance annotations that appear after the feed.
                bool isReordering = this.JsonReader is ReorderingJsonReader;
                this.ReadTopLevelFeedAnnotations(feed, duplicatePropertyNamesChecker, /*forFeedStart*/false, /*readAllFeedProperties*/isReordering);
            }
        }
        /// <summary>
        /// Checks if there is a next link annotation immediately after an expanded feed, and reads and stores it if there is one. 
        /// We fail here if we encounter any other property annotation for the expanded navigation (since these should come before the property itself).
        /// </summary>
        /// <param name="feed">The feed that was just read.</param>
        /// <param name="expandedNavigationLinkInfo">The information for the current expanded navigation link being read.</param>
        private void ReadExpandedFeedAnnotationsAtFeedEnd(ODataFeedBase feed, ODataJsonLightReaderNavigationLinkInfo expandedNavigationLinkInfo)
        {
            Debug.Assert(expandedNavigationLinkInfo != null, "expandedNavigationLinkInfo != null");
            Debug.Assert(expandedNavigationLinkInfo.NavigationLink.IsCollection == true, "Only collection navigation properties can have feed content.");

            // Look at the next property in the owning entry, if it's a property annotation for the expanded navigation link info property, read it.
            string propertyName, annotationName;
            while (this.JsonReader.NodeType == JsonNodeType.Property &&
                   TryParsePropertyAnnotation(this.JsonReader.GetPropertyName(), out propertyName, out annotationName) &&
                   string.CompareOrdinal(propertyName, expandedNavigationLinkInfo.NavigationLink.Name) == 0)
            {
                if (!this.ReadingResponse)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightPropertyAndValueDeserializer_UnexpectedPropertyAnnotation(propertyName, annotationName));
                }

                // Read over the property name.
                this.JsonReader.Read();

                switch (annotationName)
                {
                    case ODataAnnotationNames.ODataNextLink:
                        if (feed.NextPageLink != null)
                        {
                            throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_DuplicateExpandedFeedAnnotation(ODataAnnotationNames.ODataNextLink, expandedNavigationLinkInfo.NavigationLink.Name));
                        }

                        // Read the property value.
                        feed.NextPageLink = this.ReadAndValidateAnnotationStringValueAsUri(ODataAnnotationNames.ODataNextLink);
                        break;

                    case ODataAnnotationNames.ODataCount:
                        if (feed.Count != null)
                        {
                            throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_DuplicateExpandedFeedAnnotation(ODataAnnotationNames.ODataCount, expandedNavigationLinkInfo.NavigationLink.Name));
                        }

                        // Read the property value.
                        feed.Count = this.ReadAndValidateAnnotationAsLongForIeee754Compatible(ODataAnnotationNames.ODataCount);
                        break;

                    case ODataAnnotationNames.ODataDeltaLink:   // Delta links are not supported on expanded feeds.
                    default:
                        throw new ODataException(ODataErrorStrings.ODataJsonLightEntryAndFeedDeserializer_UnexpectedPropertyAnnotationAfterExpandedFeed(annotationName, expandedNavigationLinkInfo.NavigationLink.Name));
                }
            }
        }
        /// <summary>
        /// Creates a navigation link info for a collection of entity reference links.
        /// </summary>
        /// <param name="navigationLink">The navigation link to report.</param>
        /// <param name="navigationProperty">The navigation property for which the link will be reported.</param>
        /// <param name="entityReferenceLinks">The entity reference links for the navigation link to report.</param>
        /// <param name="isExpanded">true if the navigation link is expanded.</param>
        /// <returns>The navigation link info created.</returns>
        internal static ODataJsonLightReaderNavigationLinkInfo CreateCollectionEntityReferenceLinksInfo(
            ODataNavigationLink navigationLink,
            IEdmNavigationProperty navigationProperty,
            LinkedList<ODataEntityReferenceLink> entityReferenceLinks,
            bool isExpanded)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(navigationLink.IsCollection == true, "Collection entity reference can only be reported for a collection navigation links.");
            Debug.Assert(navigationProperty != null, "navigationProperty != null");
            Debug.Assert(entityReferenceLinks == null || entityReferenceLinks.Count > 0, "entityReferenceLinks == null || entityReferenceLinks.Count > 0");

            ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, isExpanded);
            navigationLinkInfo.entityReferenceLinks = entityReferenceLinks;
            return navigationLinkInfo;
        }
        /// <summary>
        /// Creates a navigation link info for a projected navigation link that is missing from the payload.
        /// </summary>
        /// <param name="navigationProperty">The navigation property for which the link will be reported.</param>
        /// <returns>The navigation link info created.</returns>
        internal static ODataJsonLightReaderNavigationLinkInfo CreateProjectedNavigationLinkInfo(IEdmNavigationProperty navigationProperty)
        {
            Debug.Assert(navigationProperty != null, "navigationProperty != null");

            ODataNavigationLink navigationLink = new ODataNavigationLink { Name = navigationProperty.Name, IsCollection = navigationProperty.Type.IsCollection() };
            ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ false);
            return navigationLinkInfo;
        }
        /// <summary>
        /// Creates a navigation link info for a singleton entity reference link.
        /// </summary>
        /// <param name="navigationLink">The navigation link to report.</param>
        /// <param name="navigationProperty">The navigation property for which the link will be reported.</param>
        /// <param name="entityReferenceLink">The entity reference link for the navigation link to report.</param>
        /// <param name="isExpanded">true if the navigation link is expanded.</param>
        /// <returns>The navigation link info created.</returns>
        internal static ODataJsonLightReaderNavigationLinkInfo CreateSingletonEntityReferenceLinkInfo(
            ODataNavigationLink navigationLink,
            IEdmNavigationProperty navigationProperty,
            ODataEntityReferenceLink entityReferenceLink,
            bool isExpanded)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(navigationLink.IsCollection == false, "Singleton entity reference can only be reported for a singleton navigation links.");
            Debug.Assert(navigationProperty != null, "navigationProperty != null");

            ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, isExpanded);
            if (entityReferenceLink != null)
            {
                navigationLinkInfo.entityReferenceLinks = new LinkedList<ODataEntityReferenceLink>();
                navigationLinkInfo.entityReferenceLinks.AddFirst(entityReferenceLink);
            }

            return navigationLinkInfo;
        }
        /// <summary>
        /// Creates a navigation link info for an expanded feed link.
        /// </summary>
        /// <param name="navigationLink">The navigation link to report.</param>
        /// <param name="navigationProperty">The navigation property for which the link will be reported.</param>
        /// <param name="expandedFeed">The expanded feed for the navigation link to report.</param>
        /// <returns>The navigation link info created.</returns>
        internal static ODataJsonLightReaderNavigationLinkInfo CreateExpandedFeedLinkInfo(
            ODataNavigationLink navigationLink,
            IEdmNavigationProperty navigationProperty,
            ODataFeed expandedFeed)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(navigationLink.IsCollection == true, "Expanded feeds can only be reported for collection navigation links.");
            Debug.Assert(expandedFeed != null, "expandedFeed != null");

            ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ true);
            navigationLinkInfo.expandedFeed = expandedFeed;
            return navigationLinkInfo;
        }
        /// <summary>
        /// Creates a navigation link info for an expanded entry link.
        /// </summary>
        /// <param name="navigationLink">The navigation link to report.</param>
        /// <param name="navigationProperty">The navigation property for which the link will be reported.</param>
        /// <returns>The navigation link info created.</returns>
        internal static ODataJsonLightReaderNavigationLinkInfo CreateExpandedEntryLinkInfo(
            ODataNavigationLink navigationLink,
            IEdmNavigationProperty navigationProperty)
        {
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(navigationLink.IsCollection == false, "Expanded entry can only be reported for a singleton navigation link.");

            ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo = new ODataJsonLightReaderNavigationLinkInfo(navigationLink, navigationProperty, /*isExpanded*/ true);
            return navigationLinkInfo;
        }
 /// <summary>
 /// Constructor creating a new reader scope.
 /// </summary>
 /// <param name="navigationLinkInfo">The navigation link info attached to this scope.</param>
 /// <param name="navigationSource">The navigation source we are going to read entities for.</param>
 /// <param name="expectedEntityType">The expected type for the scope.</param>
 /// <param name="odataUri">The odataUri parsed based on the context uri for current scope</param> 
 /// <remarks>The <paramref name="expectedEntityType"/> has the following meaning
 ///   it's the expected base type the entries in the expanded link (either the single entry
 ///   or entries in the expanded feed).
 /// In all cases the specified type must be an entity type.</remarks>
 internal JsonLightNavigationLinkScope(ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo, IEdmNavigationSource navigationSource, IEdmEntityType expectedEntityType, ODataUri odataUri)
     : base(ODataReaderState.NavigationLinkStart, navigationLinkInfo.NavigationLink, navigationSource, expectedEntityType, odataUri)
 {
     this.NavigationLinkInfo = navigationLinkInfo;   
 }
        /// <summary>
        /// Starts the navigation link.
        /// Does metadata validation of the navigation link and sets up the reader to report it.
        /// </summary>
        /// <param name="navigationLinkInfo">The navigation link info for the navigation link to start.</param>
        private void StartNavigationLink(ODataJsonLightReaderNavigationLinkInfo navigationLinkInfo)
        {
            Debug.Assert(navigationLinkInfo != null, "navigationLinkInfo != null");
            ODataNavigationLink navigationLink = navigationLinkInfo.NavigationLink;
            IEdmNavigationProperty navigationProperty = navigationLinkInfo.NavigationProperty;

            Debug.Assert(
                this.jsonLightEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.Property ||
                this.jsonLightEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.EndObject ||
                this.jsonLightEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.StartObject ||
                this.jsonLightEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.StartArray ||
                this.jsonLightEntryAndFeedDeserializer.JsonReader.NodeType == JsonNodeType.PrimitiveValue && this.jsonLightEntryAndFeedDeserializer.JsonReader.Value == null,
                "Post-Condition: expected JsonNodeType.StartObject or JsonNodeType.StartArray or JsonNodeType.Primitive (null), or JsonNodeType.Property, JsonNodeType.EndObject");
            Debug.Assert(
                navigationProperty != null || this.jsonLightInputContext.MessageReaderSettings.ReportUndeclaredLinkProperties,
                "A navigation property must be found for each link we find unless we're allowed to report undeclared links.");
            Debug.Assert(navigationLink != null, "navigationLink != null");
            Debug.Assert(!string.IsNullOrEmpty(navigationLink.Name), "Navigation links must have a name.");
            Debug.Assert(
                navigationProperty == null || navigationLink.Name == navigationProperty.Name,
                "The navigation property must match the navigation link.");

            // we are at the beginning of a link
            IEdmEntityType targetEntityType = null;
            if (navigationProperty != null)
            {
                IEdmTypeReference navigationPropertyType = navigationProperty.Type;
                targetEntityType = navigationPropertyType.IsCollection()
                    ? navigationPropertyType.AsCollection().ElementType().AsEntity().EntityDefinition()
                    : navigationPropertyType.AsEntity().EntityDefinition();
            }

            if (this.jsonLightInputContext.ReadingResponse)
            {
                // Hookup the metadata builder to the navigation link.
                // Note that we set the metadata builder even when navigationProperty is null, which is the case when the link is undeclared.
                // For undeclared links, we will apply conventional metadata evaluation just as declared links.
                ODataEntityMetadataBuilder entityMetadataBuilder = this.jsonLightEntryAndFeedDeserializer.MetadataContext.GetEntityMetadataBuilderForReader(this.CurrentEntryState, this.jsonLightInputContext.MessageReaderSettings.UseKeyAsSegment);
                navigationLink.MetadataBuilder = entityMetadataBuilder;
            }

            Debug.Assert(this.CurrentNavigationSource != null || this.readingParameter, "Json requires an navigation source when not reading parameter.");

            IEdmNavigationSource navigationSource = this.CurrentNavigationSource == null || navigationProperty == null ? null : this.CurrentNavigationSource.FindNavigationTarget(navigationProperty);
            ODataUri odataUri = null;
            if (navigationLinkInfo.NavigationLink.ContextUrl != null)
            {
                ODataPath odataPath = ODataJsonLightContextUriParser.Parse(
                        this.jsonLightEntryAndFeedDeserializer.Model,
                        UriUtils.UriToString(navigationLinkInfo.NavigationLink.ContextUrl), 
                        navigationLinkInfo.NavigationLink.IsCollection.GetValueOrDefault() ? ODataPayloadKind.Feed : ODataPayloadKind.Entry,
                        this.jsonLightEntryAndFeedDeserializer.MessageReaderSettings.ReaderBehavior,
                        this.jsonLightEntryAndFeedDeserializer.JsonLightInputContext.ReadingResponse).Path;
                odataUri = new ODataUri()
                {
                    Path = odataPath 
                };
            }

            this.EnterScope(new JsonLightNavigationLinkScope(navigationLinkInfo, navigationSource, targetEntityType, odataUri));
        }