private void StartRead(ODataReader reader, ODataWriter writer)
 {
     ExceptionUtilities.Assert(reader.State == ODataReaderState.Start, "Reader is expected to be in state Start at StartRead.");
     while (reader.Read())
     {
         switch(reader.State)
         {
             case ODataReaderState.EntryStart:
                 writer.WriteStart((ODataEntry)reader.Item);
                 break;
             case ODataReaderState.FeedStart:
                 writer.WriteStart((ODataFeed)reader.Item);
                 break;
             case ODataReaderState.NavigationLinkStart:
                 writer.WriteStart((ODataNavigationLink)reader.Item);
                 break;
             case ODataReaderState.EntryEnd:
             case ODataReaderState.FeedEnd:
             case ODataReaderState.NavigationLinkEnd:
                 writer.WriteEnd();
                 break;
             default:
                 throw new NotSupportedException();
         };
     }
 }
        private ODataResponse ReadResponse(ODataReader odataReader)
        {
            ResponseNode rootNode = null;
            var nodeStack = new Stack<ResponseNode>();

            while (odataReader.Read())
            {
                if (odataReader.State == ODataReaderState.Completed)
                    break;

                switch (odataReader.State)
                {
                    case ODataReaderState.FeedStart:
                        StartFeed(nodeStack, CreateFeedAnnotaions(odataReader.Item as ODataFeed));
                        break;

                    case ODataReaderState.FeedEnd:
                        EndFeed(nodeStack, CreateFeedAnnotaions(odataReader.Item as ODataFeed), ref rootNode);
                        break;

                    case ODataReaderState.EntryStart:
                        StartEntry(nodeStack);
                        break;

                    case ODataReaderState.EntryEnd:
                        EndEntry(nodeStack, ref rootNode, odataReader.Item);
                        break;

                    case ODataReaderState.NavigationLinkStart:
                        StartNavigationLink(nodeStack, (odataReader.Item as ODataNavigationLink).Name);
                        break;

                    case ODataReaderState.NavigationLinkEnd:
                        EndNavigationLink(nodeStack);
                        break;
                }
            }

            return ODataResponse.FromNode(rootNode);
        }
        /// <summary>
        /// Reads an ODataFeed or an ODataItem from the reader.
        /// </summary>
        /// <param name="reader">The OData reader to read from.</param>
        /// <returns>The read feed or entry.</returns>
        public static ODataItemBase ReadEntryOrFeed(ODataReader reader)
        {
            if (reader == null)
            {
                throw Error.ArgumentNull("odataReader");
            }

            ODataItemBase topLevelItem = null;
            Stack<ODataItemBase> itemsStack = new Stack<ODataItemBase>();

            while (reader.Read())
            {
                switch (reader.State)
                {
                    case ODataReaderState.EntryStart:
                        ODataEntry entry = (ODataEntry)reader.Item;
                        ODataEntryWithNavigationLinks entryWrapper = null;
                        if (entry != null)
                        {
                            entryWrapper = new ODataEntryWithNavigationLinks(entry);
                        }

                        if (itemsStack.Count == 0)
                        {
                            Contract.Assert(entry != null, "The top-level entry can never be null.");
                            topLevelItem = entryWrapper;
                        }
                        else
                        {
                            ODataItemBase parentItem = itemsStack.Peek();
                            ODataFeedWithEntries parentFeed = parentItem as ODataFeedWithEntries;
                            if (parentFeed != null)
                            {
                                parentFeed.Entries.Add(entryWrapper);
                            }
                            else
                            {
                                ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)parentItem;
                                Contract.Assert(parentNavigationLink.NavigationLink.IsCollection == false, "Only singleton navigation properties can contain entry as their child.");
                                Contract.Assert(parentNavigationLink.NestedItems.Count == 0, "Each navigation property can contain only one entry as its direct child.");
                                parentNavigationLink.NestedItems.Add(entryWrapper);
                            }
                        }
                        itemsStack.Push(entryWrapper);
                        break;

                    case ODataReaderState.EntryEnd:
                        Contract.Assert(itemsStack.Count > 0 && (reader.Item == null || itemsStack.Peek().Item == reader.Item), "The entry which is ending should be on the top of the items stack.");
                        itemsStack.Pop();
                        break;

                    case ODataReaderState.NavigationLinkStart:
                        ODataNavigationLink navigationLink = (ODataNavigationLink)reader.Item;
                        Contract.Assert(navigationLink != null, "Navigation link should never be null.");

                        ODataNavigationLinkWithItems navigationLinkWrapper = new ODataNavigationLinkWithItems(navigationLink);
                        Contract.Assert(itemsStack.Count > 0, "Navigation link can't appear as top-level item.");
                        {
                            ODataEntryWithNavigationLinks parentEntry = (ODataEntryWithNavigationLinks)itemsStack.Peek();
                            parentEntry.NavigationLinks.Add(navigationLinkWrapper);
                        }

                        itemsStack.Push(navigationLinkWrapper);
                        break;

                    case ODataReaderState.NavigationLinkEnd:
                        Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek().Item == reader.Item, "The navigation link which is ending should be on the top of the items stack.");
                        itemsStack.Pop();
                        break;

                    case ODataReaderState.FeedStart:
                        ODataFeed feed = (ODataFeed)reader.Item;
                        Contract.Assert(feed != null, "Feed should never be null.");

                        ODataFeedWithEntries feedWrapper = new ODataFeedWithEntries(feed);
                        if (itemsStack.Count > 0)
                        {
                            ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)itemsStack.Peek();
                            Contract.Assert(parentNavigationLink != null, "this has to be an inner feed. inner feeds always have a navigation link.");
                            Contract.Assert(parentNavigationLink.NavigationLink.IsCollection == true, "Only collection navigation properties can contain feed as their child.");
                            parentNavigationLink.NestedItems.Add(feedWrapper);
                        }
                        else
                        {
                            topLevelItem = feedWrapper;
                        }

                        itemsStack.Push(feedWrapper);
                        break;

                    case ODataReaderState.FeedEnd:
                        Contract.Assert(itemsStack.Count > 0 && itemsStack.Peek().Item == reader.Item, "The feed which is ending should be on the top of the items stack.");
                        itemsStack.Pop();
                        break;

                    case ODataReaderState.EntityReferenceLink:
                        ODataEntityReferenceLink entityReferenceLink = (ODataEntityReferenceLink)reader.Item;
                        Contract.Assert(entityReferenceLink != null, "Entity reference link should never be null.");
                        ODataEntityReferenceLinkBase entityReferenceLinkWrapper = new ODataEntityReferenceLinkBase(entityReferenceLink);

                        Contract.Assert(itemsStack.Count > 0, "Entity reference link should never be reported as top-level item.");
                        {
                            ODataNavigationLinkWithItems parentNavigationLink = (ODataNavigationLinkWithItems)itemsStack.Peek();
                            parentNavigationLink.NestedItems.Add(entityReferenceLinkWrapper);
                        }

                        break;

                    default:
                        Contract.Assert(false, "We should never get here, it means the ODataReader reported a wrong state.");
                        break;
                }
            }

            Contract.Assert(reader.State == ODataReaderState.Completed, "We should have consumed all of the input by now.");
            Contract.Assert(topLevelItem != null, "A top level entry or feed should have been read by now.");
            return topLevelItem;
        }
        public static ODataFeed ReadFeedParameterValue(ODataReader feedReader)
        {
            ODataFeed entry = null;
            while (feedReader.Read())
            {
                if (feedReader.State == ODataReaderState.FeedEnd)
                {
                    entry = feedReader.Item as ODataFeed;
                }
            }

            return entry;
        }
        public static ODataEntry ReadEntryParameterValue(ODataReader entryReader)
        {
            ODataEntry entry = null;
            while (entryReader.Read())
            {
                if (entryReader.State == ODataReaderState.EntryEnd)
                {
                    entry = entryReader.Item as ODataEntry;
                }
            }

            return entry;
        }
            /// <summary>
            /// Read a navigation link with an <see cref="ODataReader"/> positioned on the navigation link start.
            /// </summary>
            /// <param name="reader">The <see cref="ODataReader"/> to use for reading the navigation link.</param>
            /// <returns>An <see cref="ODataNavigationLink"/>, possibly with annotations.</returns>
            /// <returns></returns>
            private ODataNavigationLink ReadNavigationLink(ODataReader reader)
            {
                this.assert.AreEqual(ODataReaderState.NavigationLinkStart, reader.State, "Reader states don't match.");

                reader.Read();

                List<ODataItem> expandedItems = new List<ODataItem>();
                while (reader.State != ODataReaderState.NavigationLinkEnd)
                {
                    if (reader.State == ODataReaderState.EntryStart)
                    {
                        if (reader.Item == null)
                        {
                            expandedItems.Add(null);

                            // Read over the entry start
                            reader.Read();
                        }
                        else
                        {
                            expandedItems.Add(this.ReadEntry(reader));
                        }

                        this.assert.AreEqual(ODataReaderState.EntryEnd, reader.State, "Reader states don't match.");
                    }
                    else if (reader.State == ODataReaderState.FeedStart)
                    {
                        expandedItems.Add(this.ReadFeed(reader));
                        this.assert.AreEqual(ODataReaderState.FeedEnd, reader.State, "Reader states don't match.");
                    }
                    else if (reader.State == ODataReaderState.EntityReferenceLink)
                    {
                        this.assert.IsTrue(this.testConfiguration.IsRequest, "EntityReferenceLink state should only be returned in requests.");
                        ODataEntityReferenceLink entityReferenceLink = (ODataEntityReferenceLink)reader.Item;
                        this.assert.IsNotNull(entityReferenceLink, "Reader should never report null entity reference link.");
                        expandedItems.Add(entityReferenceLink);
                    }
                    else
                    {
                        this.assert.Fail("Unexpected reader state '" + reader.State + "' for reading a navigation link.");
                    }

                    reader.Read();
                }

                this.assert.AreEqual(ODataReaderState.NavigationLinkEnd, reader.State, "Reader states don't match.");

                ODataNavigationLink navigationLink = (ODataNavigationLink)reader.Item;

                ODataNavigationLinkExpandedItemObjectModelAnnotation expandedLinkAnnotation = null;
                if (this.testConfiguration.IsRequest)
                {
                    this.assert.IsTrue(expandedItems.Count > 0, "Deferred link (navigation link without any content) should only be returned in responses.");
                    expandedLinkAnnotation = expandedItems.Count > 1
                        ? new ODataNavigationLinkExpandedItemObjectModelAnnotation() { ExpandedItem = expandedItems }
                        : new ODataNavigationLinkExpandedItemObjectModelAnnotation() { ExpandedItem = expandedItems[0] };
                }
                else
                {
                    this.assert.IsTrue(expandedItems.Count <= 1, "In response each navigation link may contain at most one item in its content (entry or feed).");
                    if (expandedItems.Count == 1)
                    {
                        expandedLinkAnnotation = new ODataNavigationLinkExpandedItemObjectModelAnnotation() { ExpandedItem = expandedItems[0] };
                    }
                }

                if (expandedLinkAnnotation != null)
                {
                    navigationLink.SetAnnotation(expandedLinkAnnotation);
                }

                return navigationLink;
            }
            /// <summary>
            /// Read an entry with an <see cref="ODataReader"/> positioned on the entry start.
            /// </summary>
            /// <param name="reader">The <see cref="ODataReader"/> to use for reading the entry.</param>
            /// <returns>An <see cref="ODataEntry"/>, possibly with annotations.</returns>
            private ODataEntry ReadEntry(ODataReader reader)
            {
                this.assert.AreEqual(ODataReaderState.EntryStart, reader.State, "Reader states don't match.");

                ODataEntry entry = (ODataEntry)reader.Item;
                ODataEntryPayloadOrderObjectModelAnnotation payloadOrderItems = this.storePayloadOrder ? new ODataEntryPayloadOrderObjectModelAnnotation() : null;
                ODataEntryNavigationLinksObjectModelAnnotation navigationLinks = new ODataEntryNavigationLinksObjectModelAnnotation();

                AddEntryPayloadOrderItems(entry, payloadOrderItems);
                if (payloadOrderItems != null)
                {
                    payloadOrderItems.AddStartEntry();
                }

                while (reader.Read())
                {
                    if (reader.State == ODataReaderState.NavigationLinkStart)
                    {
                        int positionInProperties = entry.Properties.Count();

                        AddEntryPayloadOrderItems(entry, payloadOrderItems);

                        ODataNavigationLink navigationLinkAtStart = (ODataNavigationLink)reader.Item;
                        if (payloadOrderItems != null)
                        {
                            payloadOrderItems.AddODataNavigationLink(navigationLinkAtStart);
                        }

                        ODataNavigationLink navigationLink = this.ReadNavigationLink(reader);
                        this.assert.AreSame(navigationLinkAtStart, navigationLink, "Expected the same navigation link instance.");
                        navigationLinks.Add(navigationLink, positionInProperties + navigationLinks.Count);
                    }
                    else if (reader.State == ODataReaderState.EntryEnd)
                    {
                        // we are done reading this entry
                        break;
                    }
                    else
                    {
                        this.assert.Fail("Unexpected reader state '" + reader.State + "' for reading an entry.");
                    }
                }

                this.assert.AreEqual(ODataReaderState.EntryEnd, reader.State, "Reader states don't match.");
                ODataEntry entryAtEnd = (ODataEntry)reader.Item;
                this.assert.AreSame(entry, entryAtEnd, "Expected the same entry instance.");

                AddEntryPayloadOrderItems(entry, payloadOrderItems);

                entry.SetAnnotation(navigationLinks);
                if (this.storePayloadOrder)
                {
                    entry.SetAnnotation(payloadOrderItems);
                }

                return entry;
            }
            /// <summary>
            /// Read a feed with an <see cref="ODataReader"/> positioned on the feed start.
            /// </summary>
            /// <param name="reader">The <see cref="ODataReader"/> to use for reading the feed.</param>
            /// <returns>An <see cref="ODataFeed"/>, possibly with annotations.</returns>
            private ODataFeed ReadFeed(ODataReader reader)
            {
                this.assert.AreEqual(ODataReaderState.FeedStart, reader.State, "Reader states don't match.");

                ODataFeed feed = (ODataFeed)reader.Item;
                ODataFeedPayloadOrderObjectModelAnnotation payloadOrderItems = this.storePayloadOrder ? new ODataFeedPayloadOrderObjectModelAnnotation() : null;
                ODataFeedEntriesObjectModelAnnotation feedEntries = new ODataFeedEntriesObjectModelAnnotation();

                AddFeedPayloadOrderItems(feed, payloadOrderItems);
                if (payloadOrderItems != null)
                {
                    payloadOrderItems.AddStartFeed();
                }

                while (reader.Read())
                {
                    if (reader.State == ODataReaderState.EntryStart)
                    {
                        AddFeedPayloadOrderItems(feed, payloadOrderItems);

                        ODataEntry entry = this.ReadEntry(reader);
                        if (payloadOrderItems != null)
                        {
                            payloadOrderItems.AddEntry(entry);
                        }

                        feedEntries.Add(entry);
                    }
                    else if (reader.State == ODataReaderState.FeedEnd)
                    {
                        // we are done reading the feed
                        break;
                    }
                    else
                    {
                        this.assert.Fail("Unexpected reader state '" + reader.State + "' for reading a feed.");
                    }
                }

                this.assert.AreEqual(ODataReaderState.FeedEnd, reader.State, "Reader states don't match.");
                ODataFeed feedAtEnd = (ODataFeed)reader.Item;
                this.assert.AreSame(feed, feedAtEnd, "Expected the same feed instance.");

                AddFeedPayloadOrderItems(feed, payloadOrderItems);

                feed.SetAnnotation(feedEntries);
                if (this.storePayloadOrder)
                {
                    feed.SetAnnotation(payloadOrderItems);
                }

                return feed;
            }
        private ODataResponse ReadResponse(ODataReader odataReader, bool includeResourceTypeInEntryProperties)
        {
            ResponseNode rootNode = null;
            var nodeStack = new Stack<ResponseNode>();

            while (odataReader.Read())
            {
                if (odataReader.State == ODataReaderState.Completed)
                    break;

                switch (odataReader.State)
                {
                    case ODataReaderState.FeedStart:
                        StartFeed(nodeStack, CreateFeedAnnotaions(odataReader.Item as ODataFeed));
                        break;

                    case ODataReaderState.FeedEnd:
                        EndFeed(nodeStack, CreateFeedAnnotaions(odataReader.Item as ODataFeed), ref rootNode);
                        break;

                    case ODataReaderState.EntryStart:
                        StartEntry(nodeStack);
                        break;

                    case ODataReaderState.EntryEnd:
                        EndEntry(nodeStack, ref rootNode, odataReader.Item, includeResourceTypeInEntryProperties);
                        break;

                    case ODataReaderState.NavigationLinkStart:
                        StartNavigationLink(nodeStack, (odataReader.Item as ODataNavigationLink).Name);
                        break;

                    case ODataReaderState.NavigationLinkEnd:
                        EndNavigationLink(nodeStack);
                        break;
                }
            }

            return rootNode.Feed != null
                ? ODataResponse.FromFeed(rootNode.Feed, rootNode.FeedAnnotations)
                : ODataResponse.FromEntry(rootNode.Entry);
        }