/// <summary>
        /// Validates that the authentication service implements the <see cref="IAuthentication{T}"/> interface
        /// naturally for use in codegen.
        /// </summary>
        /// <remarks>
        /// This check ensures no part of the interface was implemented explicitly.
        /// </remarks>
        /// <param name="authenticationServiceDescription">The domain service description for the type that implemented
        /// the <see cref="IAuthentication{T}"/> interface.
        /// </param>
        /// <param name="genericIAuthenticationType">The generic version of <see cref="IAuthentication{T}"/> implemented
        /// by the service type of the <paramref name="authenticationServiceDescription"/>.
        /// </param>
        /// <exception cref="InvalidOperationException"> is thrown if the <see cref="IAuthentication{T}"/> interface
        /// is not correctly implemented.
        /// </exception>
        private static void CheckIAuthentication(DomainServiceDescription authenticationServiceDescription, out Type genericIAuthenticationType)
        {
            bool implementsLogin      = false;
            bool implementsLogout     = false;
            bool implementsGetUser    = false;
            bool implementsUpdateUser = false;

            if (!typeof(IAuthentication <>).DefinitionIsAssignableFrom(authenticationServiceDescription.DomainServiceType, out genericIAuthenticationType))
            {
                throw new InvalidOperationException(Resources.ApplicationServices_MustBeIAuth);
            }

            Type userType = genericIAuthenticationType.GetGenericArguments()[0];

            foreach (DomainOperationEntry doe in authenticationServiceDescription.DomainOperationEntries)
            {
                switch (doe.Name)
                {
                case "Login":
                    implementsLogin = AuthenticationCodeProcessor.CheckIAuthenticationLogin(doe, userType);
                    break;

                case "Logout":
                    implementsLogout = AuthenticationCodeProcessor.CheckIAuthenticationLogout(doe, userType);
                    break;

                case "GetUser":
                    implementsGetUser = AuthenticationCodeProcessor.CheckIAuthenticationGetUser(doe, userType);
                    break;

                case "UpdateUser":
                    implementsUpdateUser = AuthenticationCodeProcessor.CheckIAuthenticationUpdateUser(doe, userType);
                    break;

                default:
                    break;
                }
            }

            if (!implementsLogin || !implementsLogout || !implementsGetUser || !implementsUpdateUser)
            {
                throw new InvalidOperationException(string.Format(
                                                        CultureInfo.InstalledUICulture,
                                                        Resources.ApplicationServices_MustBeIAuthImpl,
                                                        authenticationServiceDescription.DomainServiceType.Name));
            }
        }
        /// <summary>
        /// See <see cref="CodeProcessor.ProcessGeneratedCode"/>.
        /// </summary>
        /// <param name="domainServiceDescription">The domainServiceDescription</param>
        /// <param name="codeCompileUnit">The codeCompileUnit</param>
        /// <param name="typeMapping">The typeMapping</param>
        public override void ProcessGeneratedCode(DomainServiceDescription domainServiceDescription, CodeCompileUnit codeCompileUnit, IDictionary <Type, CodeTypeDeclaration> typeMapping)
        {
            // Make sure the provider extends IAuthentication<T>
            Type genericDomainServiceType;

            AuthenticationCodeProcessor.CheckIAuthentication(domainServiceDescription, out genericDomainServiceType);

            Type userEntityType = genericDomainServiceType.GetGenericArguments()[0];

            AuthenticationCodeProcessor.CheckIUser(userEntityType);

            // Implement IPrincipal and IIdentity in the user type
            CodeTypeDeclaration entityTypeDeclaration;

            typeMapping.TryGetValue(userEntityType, out entityTypeDeclaration);

            if (entityTypeDeclaration != null)
            {
                CodeTypeReference identityInterfaceTypeReference =
                    new CodeTypeReference(typeof(IIdentity))
                {
                    Options = CodeTypeReferenceOptions.GlobalReference
                };
                CodeTypeReference principalInterfaceTypeReference =
                    new CodeTypeReference(typeof(IPrincipal))
                {
                    Options = CodeTypeReferenceOptions.GlobalReference
                };

                entityTypeDeclaration.BaseTypes.Add(identityInterfaceTypeReference);
                entityTypeDeclaration.BaseTypes.Add(principalInterfaceTypeReference);

                ////
                //// private string IIdentity.AuthenticationType
                ////
                CodeMemberProperty authenticationTypeProperty = new CodeMemberProperty()
                {
                    Attributes = MemberAttributes.Private | MemberAttributes.Final,
                    HasGet     = true,
                    Name       = "AuthenticationType",
                    Type       = new CodeTypeReference(typeof(string))
                };

                // get { return string.Empty; }
                authenticationTypeProperty.GetStatements.Add(new CodeMethodReturnStatement(
                                                                 new CodePropertyReferenceExpression(
                                                                     new CodeTypeReferenceExpression(typeof(string)),
                                                                     "Empty")));

                authenticationTypeProperty.PrivateImplementationType = identityInterfaceTypeReference;
                entityTypeDeclaration.Members.Add(authenticationTypeProperty);

                ////
                //// public bool IsAuthenticated
                ////
                CodeMemberProperty isAuthenticatedProperty = new CodeMemberProperty()
                {
                    Attributes = MemberAttributes.Public | MemberAttributes.Final,
                    HasGet     = true,
                    Name       = "IsAuthenticated",
                    Type       = new CodeTypeReference(typeof(bool))
                };

                // get { return (true != string.IsNullOrEmpty(this.Name)); }
                isAuthenticatedProperty.GetStatements.Add(
                    new CodeMethodReturnStatement(
                        new CodeBinaryOperatorExpression(
                            new CodePrimitiveExpression(true),
                            CodeBinaryOperatorType.IdentityInequality,
                            new CodeMethodInvokeExpression(
                                new CodeTypeReferenceExpression(typeof(string)),
                                "IsNullOrEmpty",
                                new CodePropertyReferenceExpression(
                                    new CodeThisReferenceExpression(),
                                    "Name")))));

                isAuthenticatedProperty.Comments.AddRange(
                    AuthenticationCodeProcessor.GetDocComments(Resources.ApplicationServices_CommentIsAuth));
                isAuthenticatedProperty.ImplementationTypes.Add(identityInterfaceTypeReference);
                entityTypeDeclaration.Members.Add(isAuthenticatedProperty);

                ////
                //// private string IIdentity.Name
                ////
                // VB Codegen requires us to implement a ReadOnly version of Name as well
                CodeMemberProperty namePropertyExp = new CodeMemberProperty()
                {
                    Attributes = MemberAttributes.Private | MemberAttributes.Final,
                    HasGet     = true,
                    Name       = "Name",
                    Type       = new CodeTypeReference(typeof(string))
                };

                // get { return this.Name; }
                namePropertyExp.GetStatements.Add(
                    new CodeMethodReturnStatement(
                        new CodePropertyReferenceExpression(
                            new CodeThisReferenceExpression(),
                            "Name")));

                namePropertyExp.PrivateImplementationType = identityInterfaceTypeReference;
                entityTypeDeclaration.Members.Add(namePropertyExp);

                ////
                //// private IIdentity IPrincipal.Identity
                ////
                CodeMemberProperty identityProperty = new CodeMemberProperty()
                {
                    Attributes = MemberAttributes.Private | MemberAttributes.Final,
                    HasGet     = true,
                    Name       = "Identity",
                    Type       = identityInterfaceTypeReference,
                };

                // get { return this; }
                identityProperty.GetStatements.Add(
                    new CodeMethodReturnStatement(
                        new CodeThisReferenceExpression()));

                identityProperty.PrivateImplementationType = principalInterfaceTypeReference;
                entityTypeDeclaration.Members.Add(identityProperty);

                ////
                //// public bool IsInRole(string role)
                ////
                CodeMemberMethod isInRoleMethod = new CodeMemberMethod()
                {
                    Attributes = MemberAttributes.Public | MemberAttributes.Final,
                    Name       = "IsInRole",
                    ReturnType = new CodeTypeReference(typeof(bool))
                };
                isInRoleMethod.Parameters.Add(
                    new CodeParameterDeclarationExpression(
                        new CodeTypeReference(typeof(string)),
                        "role"));

                // if (this.Roles == null)
                // {
                //     return false;
                // }
                // return this.Roles.Contains(role);
                CodeConditionStatement ifRolesNullStatement = new CodeConditionStatement();
                ifRolesNullStatement.Condition = new CodeBinaryOperatorExpression(
                    new CodePropertyReferenceExpression(
                        new CodeThisReferenceExpression(),
                        "Roles"),
                    CodeBinaryOperatorType.IdentityEquality,
                    new CodePrimitiveExpression(null));
                ifRolesNullStatement.TrueStatements.Add(
                    new CodeMethodReturnStatement(new CodePrimitiveExpression(false)));

                isInRoleMethod.Statements.Add(ifRolesNullStatement);
                isInRoleMethod.Statements.Add(
                    new CodeMethodReturnStatement(
                        new CodeMethodInvokeExpression(
                            new CodeTypeReferenceExpression(
                                new CodeTypeReference(typeof(Enumerable))
                {
                    Options = CodeTypeReferenceOptions.GlobalReference
                }),
                            "Contains",
                            new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "Roles"),
                            new CodeVariableReferenceExpression("role"))));

                isInRoleMethod.Comments.AddRange(
                    AuthenticationCodeProcessor.GetDocComments(Resources.ApplicationServices_CommentIsInRole));
                isInRoleMethod.ImplementationTypes.Add(principalInterfaceTypeReference);
                entityTypeDeclaration.Members.Add(isInRoleMethod);

                // Changes to Name need to raise change notification for IsAuthenticated. To accomplish this,
                // we'll insert a change event at the end of the "if (this._name != value)" block.
                //
                // >> this.RaisePropertyChanged("IsAuthenticated");
                CodeMemberProperty nameProperty = entityTypeDeclaration.Members.OfType <CodeMemberProperty>().Where(c => c.Name == "Name").First();
                nameProperty.SetStatements.OfType <CodeConditionStatement>().First().TrueStatements.Add(
                    new CodeExpressionStatement(
                        new CodeMethodInvokeExpression(
                            new CodeThisReferenceExpression(),
                            "RaisePropertyChanged",
                            new CodePrimitiveExpression("IsAuthenticated"))));

                // Name should be set to string.Empty by default
                CodeMemberField nameField = entityTypeDeclaration.Members.OfType <CodeMemberField>().Where(c => c.Name == "_name").Single();
                nameField.InitExpression =
                    new CodePropertyReferenceExpression(
                        new CodeTypeReferenceExpression(typeof(string)),
                        "Empty");
            }

            // Set context base type
            CodeTypeDeclaration providerTypeDeclaration;

            typeMapping.TryGetValue(domainServiceDescription.DomainServiceType, out providerTypeDeclaration);

            if (providerTypeDeclaration != null)
            {
                providerTypeDeclaration.BaseTypes.Clear();
                providerTypeDeclaration.BaseTypes.Add(
                    new CodeTypeReference(AuthenticationCodeProcessor.AuthenticationDomainContextBaseName)
                {
                    Options = CodeTypeReferenceOptions.GlobalReference
                });
            }
        }