/// <summary>
        /// Handle $count segment
        /// </summary>
        /// <param name="previous">previous segment info.</param>
        /// <returns>The count segment info</returns>
        private static SegmentInfo CreateCountSegment(SegmentInfo previous)
        {
            CheckSegmentIsComposable(previous);

            if ((previous.TargetKind != RequestTargetKind.Resource || previous.SingleResult) && previous.TargetKind != RequestTargetKind.Collection)
            {
                throw DataServiceException.CreateResourceNotFound(Strings.RequestUriProcessor_CountNotSupported(previous.Identifier));
            }

            var segment = new SegmentInfo();

            segment.Identifier = XmlConstants.UriCountSegment;

            // DEVNOTE: prior to refactoring, $count was handled alongside properties
            // TODO: introduce a new target-source value or otherwise refactor this so that
            // $count is not treated like a property. Using the previous segment's kind
            // becomes problematic for service operations because the current segment
            // will not know the specific operation.
            segment.TargetSource = RequestTargetSource.Property;

            segment.SingleResult       = true;
            segment.TargetKind         = RequestTargetKind.PrimitiveValue;
            segment.TargetResourceType = previous.TargetResourceType;
            segment.TargetResourceSet  = previous.TargetResourceSet;

            return(segment);
        }
        /// <summary>
        /// Creates a property segment
        /// </summary>
        /// <param name="previous">previous segment info.</param>
        /// <param name="property">property to create the segment for.</param>
        /// <returns>new segment for the given property.</returns>
        private SegmentInfo CreatePropertySegment(SegmentInfo previous, ResourceProperty property)
        {
            // Handle a strongly-typed property.
            SegmentInfo segment = new SegmentInfo()
            {
                Identifier = property.Name, ProjectedProperty = property
            };

            segment.TargetResourceType = property.ResourceType;
            ResourcePropertyKind propertyKind = property.Kind;

            segment.SingleResult = (propertyKind != ResourcePropertyKind.ResourceSetReference);
            segment.TargetSource = RequestTargetSource.Property;

            if (previous.TargetKind == RequestTargetKind.Link && property.TypeKind != ResourceTypeKind.EntityType)
            {
                throw DataServiceException.CreateBadRequestError(Strings.RequestUriProcessor_LinkSegmentMustBeFollowedByEntitySegment(segment.Identifier, XmlConstants.UriLinkSegment));
            }

            switch (propertyKind)
            {
            case ResourcePropertyKind.ComplexType:
                segment.TargetKind = RequestTargetKind.ComplexObject;
                break;

            case ResourcePropertyKind.Collection:
                segment.TargetKind = RequestTargetKind.Collection;
                break;

            case ResourcePropertyKind.ResourceReference:
            case ResourcePropertyKind.ResourceSetReference:
                segment.TargetKind        = RequestTargetKind.Resource;
                segment.TargetResourceSet = this.providerWrapper.GetResourceSet(previous.TargetResourceSet, previous.TargetResourceType, property);
                if (segment.TargetResourceSet == null)
                {
                    throw DataServiceException.CreateResourceNotFound(property.Name);
                }

                break;

            default:
                Debug.Assert(property.IsOfKind(ResourcePropertyKind.Primitive), "must be primitive type property");
                segment.TargetKind = RequestTargetKind.Primitive;
                break;
            }

            return(segment);
        }
        /// <summary>Creates the first <see cref="SegmentInfo"/> for a request.</summary>
        /// <param name="segment">The text of the segment.</param>
        /// <returns>A description of the information on the segment.</returns>
        private SegmentInfo CreateFirstSegment(ODataPathSegment segment)
        {
            Debug.Assert(segment != null, "identifier != null");

            // Look for well-known system entry points.
            if (segment is MetadataSegment)
            {
                return(new SegmentInfo {
                    Identifier = XmlConstants.UriMetadataSegment, TargetKind = RequestTargetKind.Metadata
                });
            }

            if (segment is BatchSegment)
            {
                return(new SegmentInfo {
                    Identifier = XmlConstants.UriBatchSegment, TargetKind = RequestTargetKind.Batch
                });
            }

            if (segment is CountSegment)
            {
                // $count on root: throw
                throw DataServiceException.CreateResourceNotFound(Strings.RequestUriProcessor_CountOnRoot);
            }

            // Look for a service operation.
            OperationImportSegment serviceOperation = segment as OperationImportSegment;

            if (serviceOperation != null)
            {
                Debug.Assert(serviceOperation.OperationImports.Count() == 1, "Operation import segment should only ever have exactly one operation. Was a change made to how MetadataProviderEdmModel finds actions/service operations");
                var operationImport = serviceOperation.OperationImports.Single();
                var operation       = ((MetadataProviderEdmOperationImport)operationImport).ServiceOperation;
                Debug.Assert(operation != null, "operation != null");

                if (operation.Kind == OperationKind.ServiceOperation)
                {
                    return(CreateSegmentForServiceOperation(operation));
                }

                Debug.Assert(operation.Kind == OperationKind.Action, "serviceAction.Kind == OperationKind.Action");
                return(this.CreateSegmentForServiceAction(null /*previousSegment*/, operation));
            }

            var batchReferenceSegment = segment as BatchReferenceSegment;

            if (batchReferenceSegment != null)
            {
                SegmentInfo referencedSegmentInfo = this.crossReferenceCallback(batchReferenceSegment.ContentId);
                Debug.Assert(referencedSegmentInfo != null, "Could not find SegmentInfo for content-id: " + batchReferenceSegment.ContentId);
                referencedSegmentInfo.Identifier = batchReferenceSegment.ContentId;
                return(referencedSegmentInfo);
            }

            // Look for an entity set.
            EntitySetSegment entitySetSegment = segment as EntitySetSegment;

            if (entitySetSegment != null)
            {
                var container = ((IResourceSetBasedEdmEntitySet)entitySetSegment.EntitySet).ResourceSet;
                Debug.Assert(container != null, "container != null");
                SegmentInfo segmentInfo = new SegmentInfo
                {
                    Identifier         = container.Name,
                    TargetResourceSet  = container,
                    TargetResourceType = container.ResourceType,
                    TargetSource       = RequestTargetSource.EntitySet,
                    TargetKind         = RequestTargetKind.Resource,
                    SingleResult       = false
                };

                return(segmentInfo);
            }

            WebUtil.CheckResourceExists(false, segment.ToString());
            return(null);
        }