// <summary>
        //     Resolves the given 'path' with the given project's macros and validates it based on these rules:
        //     1. The resolved path should not be null or empty
        //     2. We should be able to create a absolute URI from the resolved path OR
        //     2.1 We should be able to create a relative URI, relative to the project from the resolved path
        //     3. If the path is a custom path, it should be included in the project and should be relative to the project.
        //     4. The file must exist.
        // </summary>
        internal static FileInfo ResolveAndValidatePath(Project project, string path, PathValidationErrorMessages errorMessages)
        {
#if DEBUG
            errorMessages.ValidateAllProperties();
#endif
            var resolvedPath = VsUtils.ResolvePathWithMacro(
                null, path,
                new Dictionary<string, string>
                    {
                        { ExtensibleFileManager.EFTOOLS_USER_MACRONAME, ExtensibleFileManager.UserEFToolsDir.FullName },
                        { ExtensibleFileManager.EFTOOLS_VS_MACRONAME, ExtensibleFileManager.VSEFToolsDir.FullName }
                    });

            // First check null
            if (String.IsNullOrEmpty(resolvedPath))
            {
                throw new InvalidOperationException(errorMessages.NullFile);
            }

            // resolved path should be a resolvable full path, so try creating a URI. We will need the URI's local path for the next step. This process
            // will strip out any levels of indirection in the path ('..\'). If this is a relative path pointing to a file in the project then this step will
            // be a no-op.
            Uri resolvedUri;
            if (Uri.TryCreate(resolvedPath, UriKind.Absolute, out resolvedUri))
            {
                resolvedPath = resolvedUri.LocalPath;
            }

            // We need to determine if this is a custom path; that is, something the user has typed in that is different from
            // the files in the 'user' and 'vs' directories.
            string temporaryRelativePath;
            if (VsUtils.TryGetRelativePathInParentPath(
                Path.Combine(ExtensibleFileManager.UserEFToolsDir.FullName, _dbGenFolderName), resolvedPath, out temporaryRelativePath)
                == false
                &&
                VsUtils.TryGetRelativePathInParentPath(
                    Path.Combine(ExtensibleFileManager.VSEFToolsDir.FullName, _dbGenFolderName), resolvedPath, out temporaryRelativePath)
                == false)
            {
                // Attempt to resolve to the project
                try
                {
                    bool projectHasFilename;
                    var projectPath = VsUtils.GetProjectPathWithName(project, out projectHasFilename);
                    var projectDirUri = new Uri(projectPath);
                    Debug.Assert(projectDirUri != null, "The project directory URI is null; why wasn't an exception thrown?");

                    if (projectDirUri != null)
                    {
                        if (false == Uri.TryCreate(projectDirUri, resolvedPath, out resolvedUri))
                        {
                            throw new InvalidOperationException(
                                String.Format(CultureInfo.CurrentCulture, errorMessages.NonValid, resolvedPath));
                        }
                        resolvedPath = resolvedUri.LocalPath;
                    }
                }
                catch (Exception e)
                {
                    throw new InvalidOperationException(
                        String.Format(CultureInfo.CurrentCulture, errorMessages.ParseError, path, e.Message), e);
                }

                // Now check if the file has been added to the project using the resolved path. We do not allow otherwise.
                if (VsUtils.GetProjectItemForDocument(resolvedPath, Services.ServiceProvider) == null)
                {
                    throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, errorMessages.NotInProject, resolvedPath));
                }
            }

            // If the specified file is not installed or does not exist, then we cannot continue
            var pathFileInfo = new FileInfo(resolvedPath);
            if (false == pathFileInfo.Exists)
            {
                throw new InvalidOperationException(
                    String.Format(CultureInfo.CurrentCulture, errorMessages.NonExistant, pathFileInfo.FullName));
            }

            return pathFileInfo;
        }
        internal static FileInfo ResolveAndValidateWorkflowPath(Project project, string unresolvedPath)
        {
            // Resolve and validate the workflow file path
            var errorMessages = new PathValidationErrorMessages
                {
                    NullFile = Resources.DatabaseCreation_ErrorWorkflowPathNotSet,
                    NonValid = Resources.DatabaseCreation_ErrorNonValidWorkflowUri,
                    ParseError = Resources.DatabaseCreation_ExceptionParsingWorkflowFilePath,
                    NonFile = Resources.DatabaseCreation_NonFileWorkflow,
                    NotInProject = Resources.DatabaseCreation_ErrorWorkflowFileNotInProject,
                    NonExistant = Resources.DatabaseCreation_WorkflowFileNotExists
                };

            return ResolveAndValidatePath(
                project,
                unresolvedPath,
                errorMessages);
        }