private void CreateNewActionOrFunction(EntityFramework edmx, MethodCollection methodCollection, ODataTargetInfo requestTarget)
        {
            // Create a new action (not idempotent) / function (idempotent) based on this request method!
            ActionOrFunctionBase target = null;

            if (methodCollection.AllMethodsIdempotent)
            {
                target = new Validation.OData.Function();
            }
            else
            {
                target = new Validation.OData.Action();
            }

            var schemaName = requestTarget.Name.NamespaceOnly();

            target.Name    = requestTarget.Name.TypeOnly();
            target.IsBound = true;
            target.Parameters.Add(new Parameter {
                Name = "bindingParameter", Type = requestTarget.QualifiedType, Nullable = false
            });
            foreach (var param in methodCollection.RequestBodyParameters)
            {
                target.Parameters.Add(
                    new Parameter
                {
                    Name     = param.Name,
                    Type     = param.Type.ODataResourceName(),
                    Nullable = (param.Required.HasValue ? param.Required.Value : false)
                });
            }

            if (methodCollection.ResponseType != null)
            {
                target.ReturnType = new ReturnType {
                    Type = methodCollection.ResponseType.ODataResourceName(), Nullable = false
                };
            }

            var schema = FindOrCreateSchemaForNamespace(schemaName, edmx, true);

            if (target is Function)
            {
                schema.Functions.Add((Function)target);
            }
            else
            {
                schema.Actions.Add((Validation.OData.Action)target);
            }
        }
        /// <summary>
        /// Walks the requestPath through the resources / entities defined in the edmx and resolves
        /// the type of request represented by the path
        /// </summary>
        /// <param name="requestPath"></param>
        /// <param name="requestMethod"></param>
        /// <param name="edmx"></param>
        /// <returns></returns>
        private static ODataTargetInfo ParseRequestTargetType(string requestPath, MethodCollection requestMethodCollection, EntityFramework edmx)
        {
            string[] requestParts = requestPath.Substring(1).Split(new char[] { '/' });

            EntityContainer entryPoint = (from s in edmx.DataServices.Schemas
                                          where s.EntityContainers.Count > 0
                                          select s.EntityContainers.FirstOrDefault()).SingleOrDefault();

            if (entryPoint == null)
            {
                throw new InvalidOperationException("Couldn't locate an EntityContainer to begin target resolution");
            }

            IODataNavigable currentObject  = entryPoint;
            IODataNavigable previousObject = null;

            for (int i = 0; i < requestParts.Length; i++)
            {
                string          uriPart    = requestParts[i];
                IODataNavigable nextObject = null;
                if (uriPart == "{var}")
                {
                    try
                    {
                        nextObject = currentObject.NavigateByEntityTypeKey(edmx);
                    }
                    catch (Exception ex)
                    {
                        throw new NotSupportedException("Unable to navigation into EntityType by key: " + currentObject.TypeIdentifier + " (" + ex.Message + ")");
                    }
                }
                else
                {
                    nextObject = currentObject.NavigateByUriComponent(uriPart, edmx);
                }

                if (nextObject == null && i == requestParts.Length - 1)
                {
                    // The last component wasn't known already, so that means we have a new thing.
                    // We assume that if the uriPart doesnt' have a namespace that this is a navigation property that isn't documented.

                    // TODO: We may need to be smarter about this if we allow actions without namespaces. If that's the case, we could look at the request
                    // method to figure out of this appears to be an action (POST?) or a navigationProperty (GET?)

                    return(new ODataTargetInfo
                    {
                        Name = uriPart,
                        Classification = uriPart.HasNamespace() ? ODataTargetClassification.Unknown : ODataTargetClassification.NavigationProperty,
                        QualifiedType = edmx.LookupIdentifierForType(currentObject)
                    });
                }
                else if (nextObject == null)
                {
                    throw new InvalidOperationException(
                              string.Format("Uri path requires navigating into unknown object hierarchy: missing property '{0}' on '{1}'", uriPart, currentObject.TypeIdentifier));
                }
                previousObject = currentObject;
                currentObject  = nextObject;
            }

            var response = new ODataTargetInfo
            {
                Name          = requestParts.Last(),
                QualifiedType = edmx.LookupIdentifierForType(currentObject)
            };

            if (currentObject is EntityType)
            {
                response.Classification = ODataTargetClassification.EntityType;
            }
            else if (currentObject is EntityContainer)
            {
                response.Classification = ODataTargetClassification.EntityContainer;
            }
            else if (currentObject is ODataSimpleType)
            {
                response.Classification = ODataTargetClassification.SimpleType;
            }
            else if (currentObject is ODataCollection)
            {
                if (previousObject != entryPoint)
                {
                    response.Classification = ODataTargetClassification.NavigationProperty;
                    response.QualifiedType  = edmx.LookupIdentifierForType(previousObject);
                }
                else
                {
                    response.Classification = ODataTargetClassification.EntitySet;
                }
            }
            else if (currentObject is ComplexType)
            {
                throw new NotSupportedException(string.Format("Encountered a ComplexType. This is probably a doc bug where type '{0}' should be defined with keyProperty to be an EntityType", currentObject.TypeIdentifier));
            }
            else
            {
                throw new NotSupportedException(string.Format("Unhandled object type: {0}", currentObject.GetType().Name));
            }

            return(response);
        }
        /// <summary>
        /// Use the properties of methodCollection to augment what we know about this entity type
        /// </summary>
        /// <param name="requestTarget"></param>
        /// <param name="methodCollection"></param>
        private void AppendToEntityType(EntityFramework edmx, ODataTargetInfo requestTarget, MethodCollection methodCollection)
        {
            StringBuilder sb        = new StringBuilder();
            const string  seperator = ", ";

            sb.AppendWithCondition(methodCollection.GetAllowed, "GET", seperator);
            sb.AppendWithCondition(methodCollection.PostAllowed, "POST", seperator);
            sb.AppendWithCondition(methodCollection.PutAllowed, "PUT", seperator);
            sb.AppendWithCondition(methodCollection.DeleteAllowed, "DELETE", seperator);

            Console.WriteLine("EntityType '{0}' supports: ({1})", requestTarget.QualifiedType, sb.ToString());
        }
        private void AppendToNavigationProperty(EntityFramework edmx, ODataTargetInfo navigationProperty, MethodCollection methods)
        {
            EntityType parentType = edmx.ResourceWithIdentifier <EntityType>(navigationProperty.QualifiedType);

            NavigationProperty matchingProperty =
                parentType.NavigationProperties.FirstOrDefault(np => np.Name == navigationProperty.Name);

            if (null != matchingProperty)
            {
                // TODO: Append information from methods into this navigation property
                StringBuilder sb        = new StringBuilder();
                const string  seperator = ", ";
                sb.AppendWithCondition(methods.GetAllowed, "GET", seperator);
                sb.AppendWithCondition(methods.PostAllowed, "POST", seperator);
                sb.AppendWithCondition(methods.PutAllowed, "PUT", seperator);
                sb.AppendWithCondition(methods.DeleteAllowed, "DELETE", seperator);

                Console.WriteLine("Collection '{0}' supports: ({1})", navigationProperty.QualifiedType + "/" + navigationProperty.Name, sb);
            }
            else
            {
                Console.WriteLine(
                    "EntityType '{0}' doesn't have a matching navigationProperty '{1}' but a request exists for this. Sounds like a documentation error.",
                    navigationProperty.QualifiedType,
                    navigationProperty.Name);
            }
        }