File: UI\WebControls\PasswordRecovery.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <copyright file="PasswordRecovery.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
 
namespace System.Web.UI.WebControls {
 
    using System.Collections;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Drawing;
    using System.Drawing.Design;
    using System.Globalization;
    using System.Security.Permissions;
    using System.Text;
    using System.Web.Configuration;
    using System.Web.Management;
    using System.Web.Security;
 
 
    /// <devdoc>
    /// Displays UI that allows a user to recover his/her password.  Prompts for username and possibly answer
    /// to security question.  If successful, the user's password is sent to him/her via email.  Uses
    /// a Membership provider.  UI can be customized using control properties or a template.
    /// </devdoc>
    [
    Bindable(false),
    DefaultEvent("SendingMail"),
    Designer("System.Web.UI.Design.WebControls.PasswordRecoveryDesigner, " + AssemblyRef.SystemDesign)
    ]
    public class PasswordRecovery : CompositeControl, IBorderPaddingControl, IRenderOuterTableControl {
        public static readonly string SubmitButtonCommandName = "Submit";
 
        // Needed for user template feature
        private const string _userNameID = "UserName";
        private const string _questionID = "Question";
        private const string _answerID = "Answer";
        private const string _failureTextID = "FailureText";
 
        // Needed only for "convert to template" feature, otherwise unnecessary
        private const string _userNameRequiredID = "UserNameRequired";
        private const string _answerRequiredID = "AnswerRequired";
        private const string _pushButtonID = "SubmitButton";
        private const string _imageButtonID = "SubmitImageButton";
        private const string _linkButtonID = "SubmitLinkButton";
        private const string _helpLinkID = "HelpLink";
 
        private const string _userNameContainerID = "UserNameContainerID";
        private const string _questionContainerID = "QuestionContainerID";
        private const string _successContainerID = "SuccessContainerID";
        private const ValidatorDisplay _requiredFieldValidatorDisplay = ValidatorDisplay.Static;
        private const string _userNameReplacementKey = "<%\\s*UserName\\s*%>";
        private const string _passwordReplacementKey = "<%\\s*Password\\s*%>";
 
        private string _answer;
        private View _currentView = View.UserName;
        private string _question;
        private string _userName;
        private bool _convertingToTemplate = false;
        private bool _renderDesignerRegion = false;
 
        private ITemplate _userNameTemplate;
        private UserNameContainer _userNameContainer;
        private ITemplate _questionTemplate;
        private QuestionContainer _questionContainer;
        private ITemplate _successTemplate;
        private SuccessContainer _successContainer;
 
        private const int _viewStateArrayLength = 11;
        private Style _submitButtonStyle;
        private TableItemStyle _labelStyle;
        private Style _textBoxStyle;
        private TableItemStyle _hyperLinkStyle;
        private TableItemStyle _instructionTextStyle;
        private TableItemStyle _titleTextStyle;
        private TableItemStyle _failureTextStyle;
        private TableItemStyle _successTextStyle;
        private MailDefinition _mailDefinition;
        private Style _validatorTextStyle;
 
        private static readonly object EventVerifyingUser = new object();
        private static readonly object EventUserLookupError = new object();
        private static readonly object EventVerifyingAnswer = new object();
        private static readonly object EventAnswerLookupError = new object();
        private static readonly object EventSendMailError = new object();
        private static readonly object EventSendingMail = new object();
 
 
        /// <devdoc>
        /// Answer to the security question.
        /// </devdoc>
        [
        Browsable(false),
        Filterable(false),
        Themeable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public virtual string Answer {
            get {
                return (_answer == null) ? String.Empty : _answer;
            }
        }
 
        private string AnswerInternal {
            get {
                string answer = Answer;
                if (String.IsNullOrEmpty(answer) && _questionContainer != null) {
                    ITextControl answerTextBox = (ITextControl)_questionContainer.AnswerTextBox;
                    if (answerTextBox != null && answerTextBox.Text != null) {
                        return answerTextBox.Text;
                    }
                }
                return answer;
            }
        }
 
        /// <devdoc>
        /// The text that identifies the answer textbox.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultAnswerLabelText),
        WebSysDescription(SR.PasswordRecovery_AnswerLabelText)
        ]
        public virtual string AnswerLabelText {
            get {
                object obj = ViewState["AnswerLabelText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultAnswerLabelText) : (string)obj;
            }
            set {
                ViewState["AnswerLabelText"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The text to be shown in the validation summary when the answer is empty.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Validation"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultAnswerRequiredErrorMessage),
        WebSysDescription(SR.LoginControls_AnswerRequiredErrorMessage)
        ]
        public virtual string AnswerRequiredErrorMessage {
            get {
                object obj = ViewState["AnswerRequiredErrorMessage"];
                return (obj == null) ?
                    SR.GetString(SR.PasswordRecovery_DefaultAnswerRequiredErrorMessage) : (string)obj;
            }
            set {
                ViewState["AnswerRequiredErrorMessage"] = value;
            }
        }
 
 
        [
        WebCategory("Appearance"),
        DefaultValue(1),
        WebSysDescription(SR.Login_BorderPadding),
        SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces",
            Justification = "Interface denotes existence of property, not used for security.")
        ]
        public virtual int BorderPadding {
            get {
                object obj = ViewState["BorderPadding"];
                return (obj == null) ? 1 : (int)obj;
            }
            set {
                if (value < -1) {
                    throw new ArgumentOutOfRangeException("value", SR.GetString(SR.PasswordRecovery_InvalidBorderPadding));
                }
                ViewState["BorderPadding"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The style of the submit button.
        /// </devdoc>
        [
        WebCategory("Styles"),
        DefaultValue(null),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerProperty),
        WebSysDescription(SR.PasswordRecovery_SubmitButtonStyle)
        ]
        public Style SubmitButtonStyle {
            get {
                if (_submitButtonStyle == null) {
                    _submitButtonStyle = new Style();
                    if (IsTrackingViewState) {
                        ((IStateManager)_submitButtonStyle).TrackViewState();
                    }
                }
                return _submitButtonStyle;
            }
        }
 
 
        /// <devdoc>
        /// The type of the submit button.
        /// </devdoc>
        [
        WebCategory("Appearance"),
        DefaultValue(ButtonType.Button),
        WebSysDescription(SR.PasswordRecovery_SubmitButtonType)
        ]
        public virtual ButtonType SubmitButtonType {
            get {
                object obj = ViewState["SubmitButtonType"];
                return (obj == null) ? ButtonType.Button : (ButtonType)obj;
            }
            set {
                if (value < ButtonType.Button || value > ButtonType.Link) {
                    throw new ArgumentOutOfRangeException("value");
                }
                ViewState["SubmitButtonType"] = value;
            }
        }
 
        private bool ConvertingToTemplate {
            get {
                return (DesignMode && _convertingToTemplate);
            }
        }
 
        /// <devdoc>
        /// Internal because used from PasswordRecoveryAdapter.
        /// </devdoc>
        internal View CurrentView {
            get {
                return _currentView;
            }
            set {
                if (value < View.UserName || value > View.Success) {
                    throw new ArgumentOutOfRangeException("value");
                }
                if (value != CurrentView) {
                    _currentView = value;
                    UpdateValidators();
                }
            }
        }
 
 
        /// <devdoc>
        /// The style of the failure text.
        /// </devdoc>
        [
        WebCategory("Styles"),
        DefaultValue(null),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerProperty),
        WebSysDescription(SR.WebControl_FailureTextStyle)
        ]
        public TableItemStyle FailureTextStyle {
            get {
                if (_failureTextStyle == null) {
                    _failureTextStyle = new ErrorTableItemStyle();
                    if (IsTrackingViewState) {
                        ((IStateManager)_failureTextStyle).TrackViewState();
                    }
                }
                return _failureTextStyle;
            }
        }
 
 
        /// <devdoc>
        /// The text to be shown when there is an unexpected failure.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultGeneralFailureText),
        WebSysDescription(SR.PasswordRecovery_GeneralFailureText)
        ]
        public virtual string GeneralFailureText {
            get {
                object obj = ViewState["GeneralFailureText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultGeneralFailureText) : (string)obj;
            }
            set {
                ViewState["GeneralFailureText"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The text to be shown for the help link.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Links"),
        DefaultValue(""),
        WebSysDescription(SR.ChangePassword_HelpPageText)
        ]
        public virtual string HelpPageText {
            get {
                object obj = ViewState["HelpPageText"];
                return (obj == null) ? String.Empty : (string)obj;
            }
            set {
                ViewState["HelpPageText"] = value;
            }
        }
 
        [
        WebCategory("Links"),
        DefaultValue(""),
        WebSysDescription(SR.LoginControls_HelpPageIconUrl),
        Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        UrlProperty()
        ]
        public virtual string HelpPageIconUrl {
            get {
                object obj = ViewState["HelpPageIconUrl"];
                return (obj == null) ? String.Empty : (string)obj;
            }
            set {
                ViewState["HelpPageIconUrl"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The URL of the help page.
        /// </devdoc>
        [
        WebCategory("Links"),
        DefaultValue(""),
        WebSysDescription(SR.LoginControls_HelpPageUrl),
        Editor("System.Web.UI.Design.UrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        UrlProperty()
        ]
        public virtual string HelpPageUrl {
            get {
                object obj = ViewState["HelpPageUrl"];
                return (obj == null) ? String.Empty : (string)obj;
            }
            set {
                ViewState["HelpPageUrl"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The style of the hyperlinks.
        /// </devdoc>
        [
        WebCategory("Styles"),
        DefaultValue(null),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerProperty),
        WebSysDescription(SR.WebControl_HyperLinkStyle)
        ]
        public TableItemStyle HyperLinkStyle {
            get {
                if (_hyperLinkStyle == null) {
                    _hyperLinkStyle = new TableItemStyle();
                    if (IsTrackingViewState) {
                        ((IStateManager)_hyperLinkStyle).TrackViewState();
                    }
                }
                return _hyperLinkStyle;
            }
        }
 
 
        /// <devdoc>
        /// The style of the instructions.
        /// </devdoc>
        [
        WebCategory("Styles"),
        DefaultValue(null),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerProperty),
        WebSysDescription(SR.WebControl_InstructionTextStyle)
        ]
        public TableItemStyle InstructionTextStyle {
            get {
                if (_instructionTextStyle == null) {
                    _instructionTextStyle = new TableItemStyle();
                    if (IsTrackingViewState) {
                        ((IStateManager)_instructionTextStyle).TrackViewState();
                    }
                }
                return _instructionTextStyle;
            }
        }
 
 
        /// <devdoc>
        /// The style of the textbox labels.
        /// </devdoc>
        [
        WebCategory("Styles"),
        DefaultValue(null),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerProperty),
        WebSysDescription(SR.LoginControls_LabelStyle)
        ]
        public TableItemStyle LabelStyle {
            get {
                if (_labelStyle == null) {
                    _labelStyle = new TableItemStyle();
                    if (IsTrackingViewState) {
                        ((IStateManager)_labelStyle).TrackViewState();
                    }
                }
                return _labelStyle;
            }
        }
 
 
        /// <devdoc>
        /// The content and format of the e-mail message that contains the new password.
        /// </devdoc>
        [
        WebCategory("Behavior"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerProperty),
        Themeable(false),
        WebSysDescription(SR.PasswordRecovery_MailDefinition)
        ]
        public MailDefinition MailDefinition {
            get {
                if (_mailDefinition == null) {
                    _mailDefinition = new MailDefinition();
                    if (IsTrackingViewState) {
                        ((IStateManager)_mailDefinition).TrackViewState();
                    }
                }
                return _mailDefinition;
            }
        }
 
 
        /// <devdoc>
        ///     Gets or sets the name of the membership provider.  If null or empty, the default provider is used.
        /// </devdoc>
        [
        WebCategory("Data"),
        DefaultValue(""),
        Themeable(false),
        WebSysDescription(SR.MembershipProvider_Name)
        ]
        public virtual string MembershipProvider {
            get {
                object obj = ViewState["MembershipProvider"];
                return (obj == null) ? String.Empty : (string)obj;
            }
            set {
                ViewState["MembershipProvider"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The security question.
        /// </devdoc>
        [
        Browsable(false),
        Filterable(false),
        Themeable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
        ]
        public virtual string Question {
            get {
                return (_question != null) ? _question : String.Empty;
            }
            private set {
                _question = value;
            }
        }
 
 
        /// <devdoc>
        /// The text to be shown when the answer is incorrect.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultQuestionFailureText),
        WebSysDescription(SR.PasswordRecovery_QuestionFailureText)
        ]
        public virtual string QuestionFailureText {
            get {
                object obj = ViewState["QuestionFailureText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultQuestionFailureText) : (string)obj;
            }
            set {
                ViewState["QuestionFailureText"] = value;
            }
        }
 
 
        /// <devdoc>
        /// Text that is displayed to give instructions for answering the question.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultQuestionInstructionText),
        WebSysDescription(SR.PasswordRecovery_QuestionInstructionText)
        ]
        public virtual string QuestionInstructionText {
            get {
                object obj = ViewState["QuestionInstructionText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultQuestionInstructionText) : (string)obj;
            }
            set {
                ViewState["QuestionInstructionText"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The text that identifies the question.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultQuestionLabelText),
        WebSysDescription(SR.PasswordRecovery_QuestionLabelText)
        ]
        public virtual string QuestionLabelText {
            get {
                object obj = ViewState["QuestionLabelText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultQuestionLabelText) : (string)obj;
            }
            set {
                ViewState["QuestionLabelText"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The text to be shown for the title when answering the question.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultQuestionTitleText),
        WebSysDescription(SR.PasswordRecovery_QuestionTitleText)
        ]
        public virtual string QuestionTitleText {
            get {
                object obj = ViewState["QuestionTitleText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultQuestionTitleText) : (string)obj;
            }
            set {
                ViewState["QuestionTitleText"] = value;
            }
        }
 
 
        /// <devdoc>
        /// Template rendered to prompt the user for an answer to the security question.
        /// </devdoc>
        [
        Browsable(false),
        PersistenceMode(PersistenceMode.InnerProperty),
        TemplateContainer(typeof(PasswordRecovery)),
        WebSysDescription(SR.PasswordRecovery_QuestionTemplate)
        ]
        public virtual ITemplate QuestionTemplate {
            get {
                return _questionTemplate;
            }
            set {
                _questionTemplate = value;
                ChildControlsCreated = false;
            }
        }
 
        /// <devdoc>
        /// Internal because used from PasswordRecoveryAdapter.
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        WebSysDescription(SR.PasswordRecovery_QuestionTemplateContainer)
        ]
        public Control QuestionTemplateContainer {
            get {
                EnsureChildControls();
                return _questionContainer;
            }
        }
 
 
        /// <devdoc>
        /// The URL of an image to be displayed for the submit button.
        /// </devdoc>
        [
        WebCategory("Appearance"),
        DefaultValue(""),
        WebSysDescription(SR.ChangePassword_ChangePasswordButtonImageUrl),
        Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        UrlProperty()
        ]
        public virtual string SubmitButtonImageUrl {
            get {
                object obj = ViewState["SubmitButtonImageUrl"];
                return (obj == null) ? String.Empty : (string)obj;
            }
            set {
                ViewState["SubmitButtonImageUrl"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The text to be shown for the submit button.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultSubmitButtonText),
        WebSysDescription(SR.ChangePassword_ChangePasswordButtonText)
        ]
        public virtual string SubmitButtonText {
            get {
                object obj = ViewState["SubmitButtonText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultSubmitButtonText) : (string)obj;
            }
            set {
                ViewState["SubmitButtonText"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The URL that the user is directed to after the password e-mail has been sent.
        /// If non-null, always redirect the user to this page after successful password recovery.  Else, perform the refresh action.
        /// </devdoc>
        [
        WebCategory("Behavior"),
        DefaultValue(""),
        WebSysDescription(SR.LoginControls_SuccessPageUrl),
        Editor("System.Web.UI.Design.UrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
        Themeable(false),
        UrlProperty()
        ]
        public virtual string SuccessPageUrl {
            get {
                object obj = ViewState["SuccessPageUrl"];
                return (obj == null) ? String.Empty : (string)obj;
            }
            set {
                ViewState["SuccessPageUrl"] = value;
            }
        }
 
 
        /// <devdoc>
        /// Template rendered after the e-mail is sent.
        /// </devdoc>
        [
        Browsable(false),
        PersistenceMode(PersistenceMode.InnerProperty),
        WebSysDescription(SR.PasswordRecovery_SuccessTemplate),
        TemplateContainer(typeof(PasswordRecovery))
        ]
        public virtual ITemplate SuccessTemplate {
            get {
                return _successTemplate;
            }
            set {
                _successTemplate = value;
                ChildControlsCreated = false;
            }
        }
 
        /// <devdoc>
        /// Internal because used from PasswordRecoveryAdapter.
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        WebSysDescription(SR.PasswordRecovery_SuccessTemplateContainer)
        ]
        public Control SuccessTemplateContainer {
            get {
                EnsureChildControls();
                return _successContainer;
            }
        }
 
 
        /// <devdoc>
        /// The text to be shown after the password e-mail has been sent.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultSuccessText),
        WebSysDescription(SR.PasswordRecovery_SuccessText)
        ]
        public virtual string SuccessText {
            get {
                object obj = ViewState["SuccessText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultSuccessText) : (string)obj;
            }
            set {
                ViewState["SuccessText"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The style of the success text.
        /// </devdoc>
        [
        WebCategory("Styles"),
        DefaultValue(null),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerProperty),
        WebSysDescription(SR.PasswordRecovery_SuccessTextStyle)
        ]
        public TableItemStyle SuccessTextStyle {
            get {
                if (_successTextStyle == null) {
                    _successTextStyle = new TableItemStyle();
                    if (IsTrackingViewState) {
                        ((IStateManager)_successTextStyle).TrackViewState();
                    }
                }
                return _successTextStyle;
            }
        }
 
        [
        WebCategory("Layout"),
        DefaultValue(true),
        WebSysDescription(SR.LoginControls_RenderOuterTable),
        SuppressMessage("Microsoft.Security", "CA2119:SealMethodsThatSatisfyPrivateInterfaces",
            Justification = "Interface denotes existence of property, not used for security.")
        ]
        public virtual bool RenderOuterTable {
            get {
                object obj = ViewState["RenderOuterTable"];
                return (obj == null) ? true : (bool)obj;
            }
            set {
                ViewState["RenderOuterTable"] = value;
            }
        }
 
        protected override HtmlTextWriterTag TagKey {
            get {
                return HtmlTextWriterTag.Table;
            }
        }
 
 
        /// <devdoc>
        /// The style of the textboxes.
        /// </devdoc>
        [
        WebCategory("Styles"),
        DefaultValue(null),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerProperty),
        WebSysDescription(SR.LoginControls_TextBoxStyle)
        ]
        public Style TextBoxStyle {
            get {
                if (_textBoxStyle == null) {
                    _textBoxStyle = new Style();
                    if (IsTrackingViewState) {
                        ((IStateManager)_textBoxStyle).TrackViewState();
                    }
                }
                return _textBoxStyle;
            }
        }
 
 
        /// <devdoc>
        /// The layout of the labels in relation to the textboxes.
        /// </devdoc>
        [
        WebCategory("Layout"),
        DefaultValue(LoginTextLayout.TextOnLeft),
        WebSysDescription(SR.LoginControls_TextLayout)
        ]
        public virtual LoginTextLayout TextLayout {
            get {
                object obj = ViewState["TextLayout"];
                return (obj == null) ? LoginTextLayout.TextOnLeft : (LoginTextLayout)obj;
            }
            set {
                if (value < LoginTextLayout.TextOnLeft || value > LoginTextLayout.TextOnTop) {
                    throw new ArgumentOutOfRangeException("value");
                }
                ViewState["TextLayout"] = value;
                ChildControlsCreated = false;
            }
        }
 
 
        /// <devdoc>
        /// The style of the title.
        /// </devdoc>
        [
        WebCategory("Styles"),
        DefaultValue(null),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerProperty),
        WebSysDescription(SR.LoginControls_TitleTextStyle)
        ]
        public TableItemStyle TitleTextStyle {
            get {
                if (_titleTextStyle == null) {
                    _titleTextStyle = new TableItemStyle();
                    if (IsTrackingViewState) {
                        ((IStateManager)_titleTextStyle).TrackViewState();
                    }
                }
                return _titleTextStyle;
            }
        }
 
 
        /// <devdoc>
        /// The initial value in the user name textbox.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        DefaultValue(""),
        WebSysDescription(SR.UserName_InitialValue)
        ]
        public virtual string UserName {
            get {
                return (_userName == null) ? String.Empty : _userName;
            }
            set {
                _userName = value;
            }
        }
 
        internal string UserNameInternal {
            get {
                string userName = UserName;
                if (String.IsNullOrEmpty(userName) && _userNameContainer != null) {
                    ITextControl textbox = _userNameContainer.UserNameTextBox as ITextControl;
                    if (textbox != null) {
                        return textbox.Text;
                    }
                }
                return userName;
            }
        }
 
 
        /// <devdoc>
        /// The text to be shown when the user name is invalid.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultUserNameFailureText),
        WebSysDescription(SR.PasswordRecovery_UserNameFailureText)
        ]
        public virtual string UserNameFailureText {
            get {
                object obj = ViewState["UserNameFailureText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultUserNameFailureText) : (string)obj;
            }
            set {
                ViewState["UserNameFailureText"] = value;
            }
        }
 
 
        /// <devdoc>
        /// Text that is displayed to give instructions for entering the user name.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultUserNameInstructionText),
        WebSysDescription(SR.PasswordRecovery_UserNameInstructionText)
        ]
        public virtual string UserNameInstructionText {
            get {
                object obj = ViewState["UserNameInstructionText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultUserNameInstructionText) : (string)obj;
            }
            set {
                ViewState["UserNameInstructionText"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The text that identifies the user name.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultUserNameLabelText),
        WebSysDescription(SR.PasswordRecovery_UserNameLabelText)
        ]
        public virtual string UserNameLabelText {
            get {
                object obj = ViewState["UserNameLabelText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultUserNameLabelText) : (string)obj;
            }
            set {
                ViewState["UserNameLabelText"] = value;
            }
        }
 
 
        /// <devdoc>
        /// The text to be shown in the validation summary when the user name is empty.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Validation"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultUserNameRequiredErrorMessage),
        WebSysDescription(SR.ChangePassword_UserNameRequiredErrorMessage)
        ]
        public virtual string UserNameRequiredErrorMessage {
            get {
                object obj = ViewState["UserNameRequiredErrorMessage"];
                return (obj == null) ?
                    SR.GetString(SR.PasswordRecovery_DefaultUserNameRequiredErrorMessage) : (string)obj;
            }
            set {
                ViewState["UserNameRequiredErrorMessage"] = value;
            }
        }
 
 
        /// <devdoc>
        /// Template rendered to prompt the user to enter a user name.
        /// </devdoc>
        [
        Browsable(false),
        PersistenceMode(PersistenceMode.InnerProperty),
        TemplateContainer(typeof(PasswordRecovery)),
        WebSysDescription(SR.PasswordRecovery_UserNameTemplate)
        ]
        public virtual ITemplate UserNameTemplate {
            get {
                return _userNameTemplate;
            }
            set {
                _userNameTemplate = value;
                ChildControlsCreated = false;
            }
        }
 
        /// <devdoc>
        /// Internal because used from PasswordRecoveryAdapter.
        /// </devdoc>
        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        WebSysDescription(SR.PasswordRecovery_UserNameTemplateContainer)
        ]
        public Control UserNameTemplateContainer {
            get {
                EnsureChildControls();
                return _userNameContainer;
            }
        }
 
 
        /// <devdoc>
        /// The text to be shown for the title when entering the user name.
        /// </devdoc>
        [
        Localizable(true),
        WebCategory("Appearance"),
        WebSysDefaultValue(SR.PasswordRecovery_DefaultUserNameTitleText),
        WebSysDescription(SR.PasswordRecovery_UserNameTitleText)
        ]
        public virtual string UserNameTitleText {
            get {
                object obj = ViewState["UserNameTitleText"];
                return (obj == null) ? SR.GetString(SR.PasswordRecovery_DefaultUserNameTitleText) : (string)obj;
            }
            set {
                ViewState["UserNameTitleText"] = value;
            }
        }
 
        [
        WebCategory("Styles"),
        DefaultValue(null),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerProperty),
        WebSysDescription(SR.ChangePassword_ValidatorTextStyle)
        ]
        public Style ValidatorTextStyle {
            get {
                if (_validatorTextStyle == null) {
                    _validatorTextStyle = new ErrorStyle();
                    if (IsTrackingViewState) {
                        ((IStateManager)_validatorTextStyle).TrackViewState();
                    }
                }
                return _validatorTextStyle;
            }
        }
 
 
 
        /// <devdoc>
        /// Raised when the answer provided is incorrect.
        /// </devdoc>
        [
        WebCategory("Action"),
        WebSysDescription(SR.PasswordRecovery_AnswerLookupError)
        ]
        public event EventHandler AnswerLookupError {
            add {
                Events.AddHandler(EventAnswerLookupError, value);
            }
            remove {
                Events.RemoveHandler(EventAnswerLookupError, value);
            }
        }
 
 
        /// <devdoc>
        /// Raised before the answer is validated.
        /// </devdoc>
        [
        WebCategory("Action"),
        WebSysDescription(SR.PasswordRecovery_VerifyingAnswer)
        ]
        public event LoginCancelEventHandler VerifyingAnswer {
            add {
                Events.AddHandler(EventVerifyingAnswer, value);
            }
            remove {
                Events.RemoveHandler(EventVerifyingAnswer, value);
            }
        }
 
 
        /// <devdoc>
        /// Raised before the e-mail is sent.
        /// </devdoc>
        [
        WebCategory("Action"),
        WebSysDescription(SR.PasswordRecovery_SendingMail)
        ]
        public event MailMessageEventHandler SendingMail {
            add {
                Events.AddHandler(EventSendingMail, value);
            }
            remove {
                Events.RemoveHandler(EventSendingMail, value);
            }
        }
 
        [
        WebCategory("Action"),
        WebSysDescription(SR.CreateUserWizard_SendMailError)
        ]
        public event SendMailErrorEventHandler SendMailError {
            add {
                Events.AddHandler(EventSendMailError, value);
            }
            remove {
                Events.RemoveHandler(EventSendMailError, value);
            }
        }
 
 
        /// <devdoc>
        /// Raised before the username is looked up.
        /// </devdoc>
        [
        WebCategory("Action"),
        WebSysDescription(SR.PasswordRecovery_VerifyingUser)
        ]
        public event LoginCancelEventHandler VerifyingUser {
            add {
                Events.AddHandler(EventVerifyingUser, value);
            }
            remove {
                Events.RemoveHandler(EventVerifyingUser, value);
            }
        }
 
 
        /// <devdoc>
        /// Raised when the user name is invalid.
        /// </devdoc>
        [
        WebCategory("Action"),
        WebSysDescription(SR.PasswordRecovery_UserLookupError)
        ]
        public event EventHandler UserLookupError {
            add {
                Events.AddHandler(EventUserLookupError, value);
            }
            remove {
                Events.RemoveHandler(EventUserLookupError, value);
            }
        }
 
        /// <devdoc>
        /// Called when the answer text box changes.
        /// </devdoc>
        private void AnswerTextChanged(object source, EventArgs e) {
            _answer = ((ITextControl)source).Text;
        }
 
        private void AttemptSendPassword() {
            if (Page != null && !Page.IsValid) {
                return;
            }
 
            if (CurrentView == View.UserName) {
                AttemptSendPasswordUserNameView();
            }
            else if (CurrentView == View.Question) {
                AttemptSendPasswordQuestionView();
            }
        }
 
        /// <devdoc>
        /// Called when the user presses submit in the question view.
        /// Verifies the answer to the security question.  If correct, sends password in e-mail.
        /// If answer is incorrect or there is any other error, a failure message is shown.
        /// </devdoc>
        private void AttemptSendPasswordQuestionView() {
            MembershipProvider provider = LoginUtil.GetProvider(MembershipProvider);
            MembershipUser user = provider.GetUser(UserNameInternal, /*userIsOnline*/ false, /*throwOnError*/ false);
            if (user != null) {
                if (user.IsLockedOut) {
                    SetFailureTextLabel(_questionContainer, GeneralFailureText);
                    return;
                }
 
                Question = user.PasswordQuestion;
                if (String.IsNullOrEmpty(Question)) {
                    SetFailureTextLabel(_questionContainer, GeneralFailureText);
                    return;
                }
 
                LoginCancelEventArgs cancelEventArgs = new LoginCancelEventArgs();
                OnVerifyingAnswer(cancelEventArgs);
                if (cancelEventArgs.Cancel) {
                    return;
                }
 
                string answer = AnswerInternal;
                string password = null;
                string email = user.Email;
                // If there is no email address, show the GeneralFailureText and return immediately.
                // We must be especially sure we do not reset the password if we do not have an
                // email address. (VSWhidbey 387663)
                if (String.IsNullOrEmpty(email)) {
                    SetFailureTextLabel(_questionContainer, GeneralFailureText);
                    return;
                }
 
                if (provider.EnablePasswordRetrieval) {
                    password = user.GetPassword(answer, /*throwOnError*/ false);
                }
                else if (provider.EnablePasswordReset) {
                    password = user.ResetPassword(answer, /*throwOnError*/ false);
                }
                else {
                    throw new HttpException(SR.GetString(SR.PasswordRecovery_RecoveryNotSupported));
                }
 
                if (password != null) {
                    LoginUtil.SendPasswordMail(email, user.UserName, password, MailDefinition,
                                               SR.GetString(SR.PasswordRecovery_DefaultSubject),
                                               SR.GetString(SR.PasswordRecovery_DefaultBody),
                                               OnSendingMail, OnSendMailError, this);
                    PerformSuccessAction();
                }
                else {
                    OnAnswerLookupError(EventArgs.Empty);
                    SetFailureTextLabel(_questionContainer, QuestionFailureText);
                }
            }
            else {
                // If the user lookup fails after it succeeded in the previous view,
                // it is considered a general failure
                SetFailureTextLabel(_questionContainer, GeneralFailureText);
            }
        }
 
        /// <devdoc>
        /// Called when the user presses submit in the user name view.
        /// If user name is valid, sends password in e-mail.
        /// If user name is invalid or there is any other error, a failure message is shown.
        /// </devdoc>
        private void AttemptSendPasswordUserNameView() {
            LoginCancelEventArgs cancelEventArgs = new LoginCancelEventArgs();
            OnVerifyingUser(cancelEventArgs);
            if (cancelEventArgs.Cancel) {
                return;
            }
 
            MembershipProvider provider = LoginUtil.GetProvider(MembershipProvider);
            MembershipUser user = provider.GetUser(UserNameInternal, /*isUserOnline*/ false, /*throwOnError*/ false);
            if (user != null) {
                if (user.IsLockedOut) {
                    SetFailureTextLabel(_userNameContainer, UserNameFailureText);
                    return;
                }
 
                if (provider.RequiresQuestionAndAnswer) {
                    Question = user.PasswordQuestion;
                    if (String.IsNullOrEmpty(Question)) {
                        SetFailureTextLabel(_userNameContainer, GeneralFailureText);
                        return;
                    }
                    CurrentView = View.Question;
                }
                else {
                    string password = null;
                    string email = user.Email;
                    // If there is no email address, show the GeneralFailureText and return immediately.
                    // We must be especially sure we do not reset the password if we do not have an
                    // email address. (VSWhidbey 387663)                     
                    if (String.IsNullOrEmpty(email)) {
                        SetFailureTextLabel(_userNameContainer, GeneralFailureText);
                        return;
                    }
 
                    if (provider.EnablePasswordRetrieval) {
                        password = user.GetPassword(/*throwOnError*/ false);
                    }
                    else if (provider.EnablePasswordReset) {
                        password = user.ResetPassword(/*throwOnError*/ false);
                    }
                    else {
                        throw new HttpException(SR.GetString(SR.PasswordRecovery_RecoveryNotSupported));
                    }
 
                    if (password != null) {
                        LoginUtil.SendPasswordMail(email, user.UserName, password, MailDefinition,
                                                   SR.GetString(SR.PasswordRecovery_DefaultSubject),
                                                   SR.GetString(SR.PasswordRecovery_DefaultBody),
                                                   OnSendingMail, OnSendMailError, this);
                        PerformSuccessAction();
                    }
                    else {
                        SetFailureTextLabel(_userNameContainer, GeneralFailureText);
                    }
                }
            }
            else {
                OnUserLookupError(EventArgs.Empty);
                SetFailureTextLabel(_userNameContainer, UserNameFailureText);
            }
        }
 
 
        /// <devdoc>
        /// Instantiates the proper template in the template container, and wires up necessary events.
        /// </devdoc>
        protected internal override void CreateChildControls() {
            Controls.Clear();
            CreateUserView();
            CreateQuestionView();
            CreateSuccessView();
        }
 
        private void CreateQuestionView() {
            ITemplate template = null;
            _questionContainer = new QuestionContainer(this);
            _questionContainer.ID = _questionContainerID;
            _questionContainer.RenderDesignerRegion = _renderDesignerRegion;
            if (QuestionTemplate != null) {
                template = QuestionTemplate;
            }
            else {
                // 
                template = new DefaultQuestionTemplate(this);
                _questionContainer.EnableViewState = false;
 
                // Disable theming if using default template (VSWhidbey 86010)
                _questionContainer.EnableTheming = false;
 
            }
            template.InstantiateIn(_questionContainer);
            Controls.Add(_questionContainer);
 
            IEditableTextControl answerTextBox = _questionContainer.AnswerTextBox as IEditableTextControl;
            if (answerTextBox != null) {
                answerTextBox.TextChanged += new EventHandler(AnswerTextChanged);
            }
        }
 
        private void CreateSuccessView() {
            ITemplate template = null;
            _successContainer = new SuccessContainer(this);
            _successContainer.ID = _successContainerID;
            _successContainer.RenderDesignerRegion = _renderDesignerRegion;
            if (SuccessTemplate != null) {
                template = SuccessTemplate;
            }
            else {
                // 
                template = new DefaultSuccessTemplate(this);
                _successContainer.EnableViewState = false;
 
                // Disable theming if using default template (VSWhidbey 86010)
                _successContainer.EnableTheming = false;
            }
            template.InstantiateIn(_successContainer);
            Controls.Add(_successContainer);
        }
 
        private void CreateUserView() {
            ITemplate template = null;
            _userNameContainer = new UserNameContainer(this);
            _userNameContainer.ID = _userNameContainerID;
            _userNameContainer.RenderDesignerRegion = _renderDesignerRegion;
            if (UserNameTemplate != null) {
                template = UserNameTemplate;
            }
            else {
                // 
                template = new DefaultUserNameTemplate(this);
                _userNameContainer.EnableViewState = false;
 
                // Disable theming if using default template (VSWhidbey 86010)
                _userNameContainer.EnableTheming = false;
 
            }
            template.InstantiateIn(_userNameContainer);
            Controls.Add(_userNameContainer);
 
            // Set the editable child control properties here for two reasons:
            // - So change events will be raised if viewstate is disabled on the child controls
            //   - Viewstate is always disabled for default template, and might be for user template
            // - So the controls render correctly in the designer
            SetUserNameEditableChildProperties();
 
            IEditableTextControl userNameTextBox = _userNameContainer.UserNameTextBox as IEditableTextControl;
            if (userNameTextBox != null) {
                userNameTextBox.TextChanged += new EventHandler(UserNameTextChanged);
            }
        }
 
        /// <devdoc>
        /// Loads the control state for those properties that should persist across postbacks
        /// even when EnableViewState=false.
        /// </devdoc>
        protected internal override void LoadControlState(object savedState) {
            if (savedState != null) {
                Triplet state = (Triplet)savedState;
                if (state.First != null) {
                    base.LoadControlState(state.First);
                }
                if (state.Second != null) {
                    CurrentView = (View)(int)state.Second;
                }
                if (state.Third != null) {
                    _userName = (string)state.Third;
                }
            }
        }
 
 
        /// <devdoc>
        ///     Loads a saved state of the <see cref='System.Web.UI.WebControls.Login'/>.
        /// </devdoc>
        protected override void LoadViewState(object savedState) {
            if (savedState == null) {
                base.LoadViewState(null);
            }
            else {
                object[] myState = (object[])savedState;
                if (myState.Length != _viewStateArrayLength) {
                    throw new ArgumentException(SR.GetString(SR.ViewState_InvalidViewState));
                }
 
                base.LoadViewState(myState[0]);
                if (myState[1] != null) {
                    ((IStateManager)SubmitButtonStyle).LoadViewState(myState[1]);
                }
                if (myState[2] != null) {
                    ((IStateManager)LabelStyle).LoadViewState(myState[2]);
                }
                if (myState[3] != null) {
                    ((IStateManager)TextBoxStyle).LoadViewState(myState[3]);
                }
                if (myState[4] != null) {
                    ((IStateManager)HyperLinkStyle).LoadViewState(myState[4]);
                }
                if (myState[5] != null) {
                    ((IStateManager)InstructionTextStyle).LoadViewState(myState[5]);
                }
                if (myState[6] != null) {
                    ((IStateManager)TitleTextStyle).LoadViewState(myState[6]);
                }
                if (myState[7] != null) {
                    ((IStateManager)FailureTextStyle).LoadViewState(myState[7]);
                }
                if (myState[8] != null) {
                    ((IStateManager)SuccessTextStyle).LoadViewState(myState[8]);
                }
                if (myState[9] != null) {
                    ((IStateManager)MailDefinition).LoadViewState(myState[9]);
                }
                if (myState[10] != null) {
                    ((IStateManager)ValidatorTextStyle).LoadViewState(myState[10]);
                }
            }
        }
 
 
        /// <devdoc>
        /// Raises the AnswerLookup event.
        /// </devdoc>
        protected virtual void OnAnswerLookupError(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EventAnswerLookupError];
            if (handler != null) {
                handler(this, e);
            }
        }
 
 
        /// <devdoc>
        /// Raises the VerifyingAnswer event.
        /// </devdoc>
        protected virtual void OnVerifyingAnswer(LoginCancelEventArgs e) {
            LoginCancelEventHandler handler = (LoginCancelEventHandler)Events[EventVerifyingAnswer];
            if (handler != null) {
                handler(this, e);
            }
        }
 
 
        /// <devdoc>
        /// Raises the SendingMail event.
        /// </devdoc>
        protected virtual void OnSendingMail(MailMessageEventArgs e) {
            MailMessageEventHandler handler = (MailMessageEventHandler)Events[EventSendingMail];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        protected virtual void OnSendMailError(SendMailErrorEventArgs e) {
            SendMailErrorEventHandler handler = (SendMailErrorEventHandler)Events[EventSendMailError];
            if (handler != null) {
                handler(this, e);
            }
        }
 
 
        /// <devdoc>
        /// Raises the VerifyingUser event.
        /// </devdoc>
        protected virtual void OnVerifyingUser(LoginCancelEventArgs e) {
            LoginCancelEventHandler handler = (LoginCancelEventHandler)Events[EventVerifyingUser];
            if (handler != null) {
                handler(this, e);
            }
        }
 
 
        /// <devdoc>
        /// Called when an event is raised by a control inside one of our templates.  Attempts to send
        /// password if the event was raised by the submit button.
        /// </devdoc>
        protected override bool OnBubbleEvent(object source, EventArgs e) {
            bool handled = false;
            if (e is CommandEventArgs) {
                CommandEventArgs ce = (CommandEventArgs)e;
                if (ce.CommandName.Equals(SubmitButtonCommandName, StringComparison.CurrentCultureIgnoreCase)) {
                    AttemptSendPassword();
                    handled = true;
                }
            }
            return handled;
        }
 
 
        protected internal override void OnInit(EventArgs e) {
            base.OnInit(e);
            Page.RegisterRequiresControlState(this);
            Page.LoadComplete += new EventHandler(OnPageLoadComplete);
        }
 
        private void OnPageLoadComplete(object sender, EventArgs e) {
            if (CurrentView == View.Question) {
                // Question will be null if the page was posted back using a control outside the
                // PasswordRecovery (VSWhidbey 81302).  Load the Question in Page.LoadComplete instead
                // of Control.OnPreRender(), so that the Question property is available to the page
                // developer earlier in the lifecycle.
                if (String.IsNullOrEmpty(Question)) {
                    MembershipProvider provider = LoginUtil.GetProvider(MembershipProvider);
                    MembershipUser user = provider.GetUser(UserNameInternal, /*isUserOnline*/ false, /*throwOnError*/ false);
                    if (user != null) {
                        Question = user.PasswordQuestion;
                        if (String.IsNullOrEmpty(Question)) {
                            SetFailureTextLabel(_questionContainer, GeneralFailureText);
                        }
                    }
                    else {
                        SetFailureTextLabel(_questionContainer, GeneralFailureText);
                    }
                }
            }
        }
 
        /// <devdoc>
        /// Overridden to set the editable child control properteries.
        /// </devdoc>
        protected internal override void OnPreRender(EventArgs e) {
            base.OnPreRender(e);
 
            _userNameContainer.Visible = false;
            _questionContainer.Visible = false;
            _successContainer.Visible = false;
            switch (CurrentView) {
                case View.UserName:
                    _userNameContainer.Visible = true;
                    // Set the editable child control properties here instead of Render, so they get into viewstate
                    // for the user template.
                    SetUserNameEditableChildProperties();
                    break;
                case View.Question:
                    _questionContainer.Visible = true;
                    break;
                case View.Success:
                    _successContainer.Visible = true;
                    break;
            }
        }
 
 
        /// <devdoc>
        /// Raises the UserLookupError event
        /// </devdoc>
        protected virtual void OnUserLookupError(EventArgs e) {
            EventHandler handler = (EventHandler)Events[EventUserLookupError];
            if (handler != null) {
                handler(this, e);
            }
        }
 
        private void PerformSuccessAction() {
            string successPageUrl = SuccessPageUrl;
            if (!String.IsNullOrEmpty(successPageUrl)) {
                // Microsoft suggested that we should not terminate execution of current page, to give
                // page a chance to cleanup its resources.  This may be less performant though.
                // Microsoft suggested that we need to call ResolveClientUrl before redirecting.
                // Example is this control inside user control, want redirect relative to user control dir.
                Page.Response.Redirect(ResolveClientUrl(successPageUrl), false);
            }
            else {
                CurrentView = View.Success;
            }
        }
 
 
        /// <devdoc>
        ///     Adds the ClientID and renders contents, because we don't want the outer <span>.
        /// </devdoc>
        protected internal override void Render(HtmlTextWriter writer) {
            if (Page != null) {
                Page.VerifyRenderingInServerForm(this);
            }
 
            EnsureChildControls();
 
            if (DesignMode) {
                // Need to redo this for the designer as there's no PreRender(sigh)
                _userNameContainer.Visible = false;
                _questionContainer.Visible = false;
                _successContainer.Visible = false;
                switch (CurrentView) {
                    case View.UserName:
                        _userNameContainer.Visible = true;
                        break;
                    case View.Question:
                        _questionContainer.Visible = true;
                        break;
                    case View.Success:
                        _successContainer.Visible = true;
                        break;
                }
            }
 
            switch (CurrentView) {
                case View.UserName:
                    SetUserNameChildProperties();
                    break;
                case View.Question:
                    SetQuestionChildProperties();
                    break;
                case View.Success:
                    SetSuccessChildProperties();
                    break;
            }
 
            RenderContents(writer);
        }
 
        /// <devdoc>
        /// Saves the control state for those properties that should persist across postbacks
        /// even when EnableViewState=false.
        /// </devdoc>
        protected internal override object SaveControlState() {
            object baseState = base.SaveControlState();
            if (baseState != null || _currentView != 0 || _userName != null) {
                // Save the int value of the enum (instead of the enum value itself)
                // to save space in ControlState
                object currentViewState = null;
                object userNameState = null;
 
                if (_currentView != 0) {
                    currentViewState = (int)_currentView;
                }
                // Don't save _userName once we have reached the success view (VSWhidbey 81327)
                if (_userName != null && _currentView != View.Success) {
                    userNameState = _userName;
                }
                return new Triplet(baseState, currentViewState, userNameState);
            }
            return null;
        }
 
 
        /// <internalonly/>
        /// <devdoc>
        ///     Saves the state of the <see cref='System.Web.UI.WebControls.Login'/>.
        /// </devdoc>
        protected override object SaveViewState() {
            object[] myState = new object[_viewStateArrayLength];
 
            myState[0] = base.SaveViewState();
            myState[1] = (_submitButtonStyle != null) ? ((IStateManager)_submitButtonStyle).SaveViewState() : null;
            myState[2] = (_labelStyle != null) ? ((IStateManager)_labelStyle).SaveViewState() : null;
            myState[3] = (_textBoxStyle != null) ? ((IStateManager)_textBoxStyle).SaveViewState() : null;
            myState[4] = (_hyperLinkStyle != null) ? ((IStateManager)_hyperLinkStyle).SaveViewState() : null;
            myState[5] = (_instructionTextStyle != null) ? ((IStateManager)_instructionTextStyle).SaveViewState() : null;
            myState[6] = (_titleTextStyle != null) ? ((IStateManager)_titleTextStyle).SaveViewState() : null;
            myState[7] = (_failureTextStyle != null) ? ((IStateManager)_failureTextStyle).SaveViewState() : null;
            myState[8] = (_successTextStyle != null) ? ((IStateManager)_successTextStyle).SaveViewState() : null;
            myState[9] = (_mailDefinition != null) ? ((IStateManager)_mailDefinition).SaveViewState() : null;
            myState[10] = (_validatorTextStyle != null) ? ((IStateManager)_validatorTextStyle).SaveViewState() : null;
 
            for (int i = 0; i < _viewStateArrayLength; i++) {
                if (myState[i] != null) {
                    return myState;
                }
            }
 
            // More performant to return null than an array of null values
            return null;
        }
 
        /// <internalonly/>
        /// <devdoc>
        /// Allows the designer to set the CurrentView, so the different templates can be shown in the designer.
        /// </devdoc>
        [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
        protected override void SetDesignModeState(IDictionary data) {
            if (data != null) {
                object o = data["CurrentView"];
                if (o != null) {
                    CurrentView = (View)o;
                }
                o = data["ConvertToTemplate"];
                if (o != null) {
                    _convertingToTemplate = (bool)o;
                }
                o = data["RegionEditing"];
                if (o != null) {
                    _renderDesignerRegion = (bool)o;
                }
            }
        }
 
        /// <devdoc>
        /// Used frequently, so extracted into method.
        /// </devdoc>
        private void SetFailureTextLabel(QuestionContainer container, string failureText) {
            ITextControl failureTextLabel = (ITextControl)container.FailureTextLabel;
            if (failureTextLabel != null) {
                failureTextLabel.Text = failureText;
            }
        }
 
        /// <devdoc>
        /// Used frequently, so extracted into method.
        /// </devdoc>
        private void SetFailureTextLabel(UserNameContainer container, string failureText) {
            ITextControl failureTextLabel = (ITextControl)container.FailureTextLabel;
            if (failureTextLabel != null) {
                failureTextLabel.Text = failureText;
            }
        }
 
        /// <devdoc>
        /// Internal because called from PasswordRecoveryAdapter.
        /// </devdoc>
        internal void SetQuestionChildProperties() {
            SetQuestionCommonChildProperties();
            if (QuestionTemplate == null) {
                SetQuestionDefaultChildProperties();
            }
        }
 
        /// <devdoc>
        /// Properties that apply to both default and user templates.
        /// </devdoc>
        private void SetQuestionCommonChildProperties() {
            QuestionContainer container = _questionContainer;
 
            // Clear out the tab index so it doesn't get applied to the tables in the container
            Util.CopyBaseAttributesToInnerControl(this, container);
 
            container.ApplyStyle(ControlStyle);
 
            // We need to use UserNameInternal for the DropDownList case where it won't fire a TextChanged for the first item
            ITextControl userName = (ITextControl)container.UserName;
            if (userName != null) {
                // VSWhidbey 304890 - Encode the user name
                userName.Text = HttpUtility.HtmlEncode(UserNameInternal);
            }
 
            ITextControl question = (ITextControl)container.Question;
            if (question != null) {
                // VSWhidbey 385802 - Encode the question
                question.Text = HttpUtility.HtmlEncode(Question);
            }
 
            ITextControl answerTextBox = (ITextControl)container.AnswerTextBox;
            if (answerTextBox != null) {
                answerTextBox.Text = String.Empty;
            }
        }
 
        /// <devdoc>
        /// Properties that apply to only the default template.
        /// </devdoc>
        private void SetQuestionDefaultChildProperties() {
            QuestionContainer container = _questionContainer;
 
            // Need to set the BorderPadding on the BorderTable instead of the LayoutTable, since
            // setting it on the LayoutTable would cause all of the controls inside the Login to be
            // separated by the BorderPadding amount.
            container.BorderTable.CellPadding = BorderPadding;
            container.BorderTable.CellSpacing = 0;
 
            Literal title = container.Title;
            string titleText = QuestionTitleText;
            if (titleText.Length > 0) {
                title.Text = titleText;
                if (_titleTextStyle != null) {
                    LoginUtil.SetTableCellStyle(title, TitleTextStyle);
                }
                LoginUtil.SetTableCellVisible(title, true);
            }
            else {
                LoginUtil.SetTableCellVisible(title, false);
            }
 
            Literal instruction = container.Instruction;
            string instructionText = QuestionInstructionText;
            if (instructionText.Length > 0) {
                instruction.Text = instructionText;
                if (_instructionTextStyle != null) {
                    LoginUtil.SetTableCellStyle(instruction, InstructionTextStyle);
                }
                LoginUtil.SetTableCellVisible(instruction, true);
            }
            else {
                LoginUtil.SetTableCellVisible(instruction, false);
            }
 
            Literal userNameLabel = container.UserNameLabel;
            string userNameLabelText = UserNameLabelText;
            if (userNameLabelText.Length > 0) {
                userNameLabel.Text = userNameLabelText;
                if (_labelStyle != null) {
                    LoginUtil.SetTableCellStyle(userNameLabel, LabelStyle);
                }
                userNameLabel.Visible = true;
            }
            else {
                // DO NOT make the whole table cell invisible, because in some layouts it must exist for things
                // to align correctly.  Uncommon that this property will be empty anyway.
                userNameLabel.Visible = false;
            }
 
            // Do not make this control invisible if its text is empty, because it must be present in the created
            // template in the designer.  Uncommon that the text will be empty anyway.
            Control userName = container.UserName;
            if (UserNameInternal.Length > 0) {
                userName.Visible = true;
            }
            else {
                userName.Visible = false;
            }
            if (userName is WebControl) ((WebControl)userName).TabIndex = TabIndex;
 
            Literal questionLabel = container.QuestionLabel;
            string questionLabelText = QuestionLabelText;
            if (questionLabelText.Length > 0) {
                questionLabel.Text = questionLabelText;
                if (_labelStyle != null) {
                    LoginUtil.SetTableCellStyle(questionLabel, LabelStyle);
                }
                questionLabel.Visible = true;
            }
            else {
                // DO NOT make the whole table cell invisible, because in some layouts it must exist for things
                // to align correctly.  Uncommon that this property will be empty anyway.
                questionLabel.Visible = false;
            }
 
            // Do not make this control invisible if its text is empty, because it must be present in the created
            // template in the designer.  Uncommon that the text will be empty anyway.
            Control question = container.Question;
            if (Question.Length > 0) {
                question.Visible = true;
            }
            else {
                question.Visible = false;
            }
 
            Literal answerLabel = container.AnswerLabel;
            string answerLabelText = AnswerLabelText;
            if (answerLabelText.Length > 0) {
                answerLabel.Text = answerLabelText;
                if (_labelStyle != null) {
                    LoginUtil.SetTableCellStyle(answerLabel, LabelStyle);
                }
                answerLabel.Visible = true;
            }
            else {
                // DO NOT make the whole table cell invisible, because in some layouts it must exist for things
                // to align correctly.  Uncommon that this property will be empty anyway.
                answerLabel.Visible = false;
            }
 
            WebControl answerTextBox = (WebControl)container.AnswerTextBox;
            Debug.Assert(answerTextBox != null, "AnswerTextBox cannot be null for the DefaultTemplate");
            if (_textBoxStyle != null) {
                answerTextBox.ApplyStyle(TextBoxStyle);
            }
            answerTextBox.TabIndex = TabIndex;
            answerTextBox.AccessKey = AccessKey;
 
            bool enableValidation = (CurrentView == View.Question);
            RequiredFieldValidator answerRequired = container.AnswerRequired;
            answerRequired.ErrorMessage = AnswerRequiredErrorMessage;
            answerRequired.ToolTip = AnswerRequiredErrorMessage;
            answerRequired.Enabled = enableValidation;
            answerRequired.Visible = enableValidation;
            if (_validatorTextStyle != null) {
                answerRequired.ApplyStyle(_validatorTextStyle);
            }
 
            LinkButton linkButton = container.LinkButton;
            ImageButton imageButton = container.ImageButton;
            Button pushButton = container.PushButton;
 
            WebControl button = null;
            switch (SubmitButtonType) {
                case ButtonType.Link:
                    linkButton.Text = SubmitButtonText;
                    button = linkButton;
                    break;
                case ButtonType.Image:
                    imageButton.ImageUrl = SubmitButtonImageUrl;
                    imageButton.AlternateText = SubmitButtonText;
                    button = imageButton;
                    break;
                case ButtonType.Button:
                    pushButton.Text = SubmitButtonText;
                    button = pushButton;
                    break;
            }
 
            // Set all buttons to nonvisible, then set the selected button to visible
            linkButton.Visible = false;
            imageButton.Visible = false;
            pushButton.Visible = false;
            button.Visible = true;
            button.TabIndex = TabIndex;
 
            if (_submitButtonStyle != null) {
                button.ApplyStyle(SubmitButtonStyle);
            }
 
            HyperLink helpPageLink = container.HelpPageLink;
            string helpPageText = HelpPageText;
 
            Image helpPageIcon = container.HelpPageIcon;
            if (helpPageText.Length > 0) {
                helpPageLink.Text = helpPageText;
                helpPageLink.NavigateUrl = HelpPageUrl;
                helpPageLink.TabIndex = TabIndex;
                helpPageLink.Visible = true;
            }
            else {
                helpPageLink.Visible = false;
            }
 
            string helpPageIconUrl = HelpPageIconUrl;
            bool helpPageIconVisible = (helpPageIconUrl.Length > 0);
            helpPageIcon.Visible = helpPageIconVisible;
            if (helpPageIconVisible) {
                helpPageIcon.ImageUrl = helpPageIconUrl;
                helpPageIcon.AlternateText = helpPageText;
            }
 
            if (helpPageLink.Visible || helpPageIcon.Visible) {
                if (_hyperLinkStyle != null) {
                    // Apply style except font to table cell, then apply font and forecolor to HyperLinks
                    // VSWhidbey 81289
                    TableItemStyle hyperLinkStyleExceptFont = new TableItemStyle();
                    hyperLinkStyleExceptFont.CopyFrom(HyperLinkStyle);
                    hyperLinkStyleExceptFont.Font.Reset();
                    LoginUtil.SetTableCellStyle(helpPageLink, hyperLinkStyleExceptFont);
                    helpPageLink.Font.CopyFrom(HyperLinkStyle.Font);
                    helpPageLink.ForeColor = HyperLinkStyle.ForeColor;
                }
                LoginUtil.SetTableCellVisible(helpPageLink, true);
            }
            else {
                LoginUtil.SetTableCellVisible(helpPageLink, false);
            }
 
            Control failureTextLabel = container.FailureTextLabel;
            if (((ITextControl)failureTextLabel).Text.Length > 0) {
                LoginUtil.SetTableCellStyle(failureTextLabel, FailureTextStyle);
                LoginUtil.SetTableCellVisible(failureTextLabel, true);
            }
            else {
                LoginUtil.SetTableCellVisible(failureTextLabel, false);
            }
        }
 
        /// <devdoc>
        /// Internal because called from PasswordRecoveryAdapter.
        /// </devdoc>
        internal void SetSuccessChildProperties() {
            SuccessContainer container = _successContainer;
 
            // Clear out the tab index so it doesn't get applied to the tables in the container
            Util.CopyBaseAttributesToInnerControl(this, container);
 
            container.ApplyStyle(ControlStyle);
 
            if (SuccessTemplate == null) {
                container.BorderTable.CellPadding = BorderPadding;
                container.BorderTable.CellSpacing = 0;
 
                Literal successTextLabel = container.SuccessTextLabel;
                string successText = SuccessText;
                if (successText.Length > 0) {
                    successTextLabel.Text = successText;
                    if (_successTextStyle != null) {
                        LoginUtil.SetTableCellStyle(successTextLabel, _successTextStyle);
                    }
                    LoginUtil.SetTableCellVisible(successTextLabel, true);
                }
                else {
                    LoginUtil.SetTableCellVisible(successTextLabel, false);
                }
            }
        }
 
        /// <devdoc>
        /// Internal because called from PasswordRecoveryAdapter.
        /// </devdoc>
        internal void SetUserNameChildProperties() {
            SetUserNameCommonChildProperties();
            if (UserNameTemplate == null) {
                SetUserNameDefaultChildProperties();
            }
        }
 
        /// <devdoc>
        /// Properties that apply to both default and user templates.
        /// </devdoc>
        private void SetUserNameCommonChildProperties() {
            // Clear out the tab index so it doesn't get applied to the tables in the container
            Util.CopyBaseAttributesToInnerControl(this, _userNameContainer);
 
            _userNameContainer.ApplyStyle(ControlStyle);
        }
 
        /// <devdoc>
        /// Properties that apply to only the default template.
        /// </devdoc>
        private void SetUserNameDefaultChildProperties() {
            UserNameContainer container = _userNameContainer;
            if (UserNameTemplate == null) {
                _userNameContainer.BorderTable.CellPadding = BorderPadding;
                _userNameContainer.BorderTable.CellSpacing = 0;
 
                Literal title = container.Title;
                string titleText = UserNameTitleText;
                if (titleText.Length > 0) {
                    title.Text = titleText;
                    if (_titleTextStyle != null) {
                        LoginUtil.SetTableCellStyle(title, TitleTextStyle);
                    }
                    LoginUtil.SetTableCellVisible(title, true);
                }
                else {
                    LoginUtil.SetTableCellVisible(title, false);
                }
 
                Literal instruction = container.Instruction;
                string instructionText = UserNameInstructionText;
                if (instructionText.Length > 0) {
                    instruction.Text = instructionText;
                    if (_instructionTextStyle != null) {
                        LoginUtil.SetTableCellStyle(instruction, InstructionTextStyle);
                    }
                    LoginUtil.SetTableCellVisible(instruction, true);
                }
                else {
                    LoginUtil.SetTableCellVisible(instruction, false);
                }
 
                Literal userNameLabel = container.UserNameLabel;
                string userNameLabelText = UserNameLabelText;
                if (userNameLabelText.Length > 0) {
                    userNameLabel.Text = userNameLabelText;
                    if (_labelStyle != null) {
                        LoginUtil.SetTableCellStyle(userNameLabel, LabelStyle);
                    }
                    userNameLabel.Visible = true;
                }
                else {
                    // DO NOT make the whole table cell invisible, because in some layouts it must exist for things
                    // to align correctly.  Uncommon that this property will be empty anyway.
                    userNameLabel.Visible = false;
                }
 
                WebControl userNameTextBox = (WebControl)container.UserNameTextBox;
                Debug.Assert(userNameTextBox != null, "UserNameTextBox cannot be null for the DefaultTemplate");
                if (_textBoxStyle != null) {
                    userNameTextBox.ApplyStyle(TextBoxStyle);
                }
                userNameTextBox.TabIndex = TabIndex;
                userNameTextBox.AccessKey = AccessKey;
 
                bool enableValidation = (CurrentView == View.UserName);
                RequiredFieldValidator userNameRequired = container.UserNameRequired;
                userNameRequired.ErrorMessage = UserNameRequiredErrorMessage;
                userNameRequired.ToolTip = UserNameRequiredErrorMessage;
                userNameRequired.Enabled = enableValidation;
                userNameRequired.Visible = enableValidation;
                if (_validatorTextStyle != null) {
                    userNameRequired.ApplyStyle(_validatorTextStyle);
                }
 
                LinkButton linkButton = container.LinkButton;
                ImageButton imageButton = container.ImageButton;
                Button pushButton = container.PushButton;
 
                WebControl button = null;
                switch (SubmitButtonType) {
                    case ButtonType.Link:
                        linkButton.Text = SubmitButtonText;
                        button = linkButton;
                        break;
                    case ButtonType.Image:
                        imageButton.ImageUrl = SubmitButtonImageUrl;
                        imageButton.AlternateText = SubmitButtonText;
                        button = imageButton;
                        break;
                    case ButtonType.Button:
                        pushButton.Text = SubmitButtonText;
                        button = pushButton;
                        break;
                }
 
                // Set all buttons to nonvisible, then set the selected button to visible
                linkButton.Visible = false;
                imageButton.Visible = false;
                pushButton.Visible = false;
                button.Visible = true;
                button.TabIndex = TabIndex;
 
                if (_submitButtonStyle != null) {
                    button.ApplyStyle(SubmitButtonStyle);
                }
 
                HyperLink helpPageLink = container.HelpPageLink;
                string helpPageText = HelpPageText;
 
                Image helpPageIcon = container.HelpPageIcon;
                if (helpPageText.Length > 0) {
                    helpPageLink.Text = helpPageText;
                    helpPageLink.NavigateUrl = HelpPageUrl;
                    helpPageLink.Visible = true;
                    helpPageLink.TabIndex = TabIndex;
                }
                else {
                    helpPageLink.Visible = false;
                }
                string helpPageIconUrl = HelpPageIconUrl;
                bool helpPageIconVisible = (helpPageIconUrl.Length > 0);
                helpPageIcon.Visible = helpPageIconVisible;
                if (helpPageIconVisible) {
                    helpPageIcon.ImageUrl = helpPageIconUrl;
                    helpPageIcon.AlternateText = helpPageText;
                }
 
                if (helpPageLink.Visible || helpPageIcon.Visible) {
                    if (_hyperLinkStyle != null) {
                        // Apply style except font to table cell, then apply font and forecolor to HyperLinks
                        // VSWhidbey 81289
                        Style hyperLinkStyleExceptFont = new TableItemStyle();
                        hyperLinkStyleExceptFont.CopyFrom(HyperLinkStyle);
                        hyperLinkStyleExceptFont.Font.Reset();
                        LoginUtil.SetTableCellStyle(helpPageLink, hyperLinkStyleExceptFont);
                        helpPageLink.Font.CopyFrom(HyperLinkStyle.Font);
                        helpPageLink.ForeColor = HyperLinkStyle.ForeColor;
                    }
                    LoginUtil.SetTableCellVisible(helpPageLink, true);
                }
                else {
                    LoginUtil.SetTableCellVisible(helpPageLink, false);
                }
 
                Control failureTextLabel = container.FailureTextLabel;
                if (((ITextControl)failureTextLabel).Text.Length > 0) {
                    LoginUtil.SetTableCellStyle(failureTextLabel, FailureTextStyle);
                    LoginUtil.SetTableCellVisible(failureTextLabel, true);
                }
                else {
                    LoginUtil.SetTableCellVisible(failureTextLabel, false);
                }
            }
        }
 
        /// <devdoc>
        /// Called from CreateChildControls and PreRender
        // - So change events will be raised if viewstate is disabled on the child controls
        //   - Viewstate is always disabled for default template, and might be for user template
        // - So the controls render correctly in the designer
        /// </devdoc>
        private void SetUserNameEditableChildProperties() {
            // We need to use UserNameInternal for the DropDownList case where it won't fire a TextChanged for the first item
            string userName = UserNameInternal;
            if (userName.Length > 0) {
                ITextControl userNameTextBox = (ITextControl)_userNameContainer.UserNameTextBox;
                // UserNameTextBox is a required control, but it may be null at design-time
                if (userNameTextBox != null) {
                    userNameTextBox.Text = userName;
                }
            }
        }
 
 
        /// <devdoc>
        /// Marks the starting point to begin tracking and saving changes to the
        /// control as part of the control viewstate.
        /// </devdoc>
        protected override void TrackViewState() {
            base.TrackViewState();
 
            if (_submitButtonStyle != null) {
                ((IStateManager)_submitButtonStyle).TrackViewState();
            }
            if (_labelStyle != null) {
                ((IStateManager)_labelStyle).TrackViewState();
            }
            if (_textBoxStyle != null) {
                ((IStateManager)_textBoxStyle).TrackViewState();
            }
            if (_hyperLinkStyle != null) {
                ((IStateManager)_hyperLinkStyle).TrackViewState();
            }
            if (_instructionTextStyle != null) {
                ((IStateManager)_instructionTextStyle).TrackViewState();
            }
            if (_titleTextStyle != null) {
                ((IStateManager)_titleTextStyle).TrackViewState();
            }
            if (_failureTextStyle != null) {
                ((IStateManager)_failureTextStyle).TrackViewState();
            }
            if (_successTextStyle != null) {
                ((IStateManager)_successTextStyle).TrackViewState();
            }
            if (_mailDefinition != null) {
                ((IStateManager)_mailDefinition).TrackViewState();
            }
            if (_validatorTextStyle != null) {
                ((IStateManager)_validatorTextStyle).TrackViewState();
            }
        }
 
        private void UpdateValidators() {
            if (UserNameTemplate == null && _userNameContainer != null) {
                bool enabled = (CurrentView == View.UserName);
                _userNameContainer.UserNameRequired.Enabled = enabled;
                _userNameContainer.UserNameRequired.Visible = enabled;
            }
            if (QuestionTemplate == null && _questionContainer != null) {
                bool enabled = (CurrentView == View.Question);
                _questionContainer.AnswerRequired.Enabled = enabled;
                _questionContainer.AnswerRequired.Visible = enabled;
            }
        }
 
        /// <devdoc>
        /// Called when the answer text box changes.
        /// </devdoc>
        private void UserNameTextChanged(object source, EventArgs e) {
            UserName = ((ITextControl)source).Text;
        }
 
        /// <devdoc>
        /// The default question template for the control, used if QuestionTemplate is null.
        /// </devdoc>
        private sealed class DefaultQuestionTemplate : ITemplate {
            private PasswordRecovery _owner;
 
            public DefaultQuestionTemplate(PasswordRecovery owner) {
                _owner = owner;
            }
 
            /// <devdoc>
            ///  Creates the child controls, sets certain properties (mostly static properties)
            /// </devdoc>
            private void CreateControls(QuestionContainer questionContainer) {
                string validationGroup = _owner.UniqueID;
 
                questionContainer.Title = new Literal();
                questionContainer.Instruction = new Literal();
                questionContainer.UserNameLabel = new Literal();
                questionContainer.UserName = new Literal();
                questionContainer.QuestionLabel = new Literal();
                questionContainer.Question = new Literal();
 
                // Needed for "convert to template" feature
                questionContainer.UserName.ID = _userNameID;
                questionContainer.Question.ID = _questionID;
 
                TextBox answerTextBox = new TextBox();
                answerTextBox.ID = _answerID;
                questionContainer.AnswerTextBox = answerTextBox;
                questionContainer.AnswerLabel = new LabelLiteral(answerTextBox);
 
                bool enableValidation = (_owner.CurrentView == View.Question);
                RequiredFieldValidator answerRequired = new RequiredFieldValidator();
                answerRequired.ID = _answerRequiredID;
                answerRequired.ValidationGroup = validationGroup;
                answerRequired.ControlToValidate = answerTextBox.ID;
                answerRequired.Display = _requiredFieldValidatorDisplay;
                answerRequired.Text = SR.GetString(SR.LoginControls_DefaultRequiredFieldValidatorText);
                answerRequired.Enabled = enableValidation;
                answerRequired.Visible = enableValidation;
                questionContainer.AnswerRequired = answerRequired;
 
                LinkButton linkButton = new LinkButton();
                linkButton.ID = _linkButtonID;
                linkButton.ValidationGroup = validationGroup;
                linkButton.CommandName = SubmitButtonCommandName;
                questionContainer.LinkButton = linkButton;
 
                ImageButton imageButton = new ImageButton();
                imageButton.ID = _imageButtonID;
                imageButton.ValidationGroup = validationGroup;
                imageButton.CommandName = SubmitButtonCommandName;
                questionContainer.ImageButton = imageButton;
 
                Button pushButton = new Button();
                pushButton.ID = _pushButtonID;
                pushButton.ValidationGroup = validationGroup;
                pushButton.CommandName = SubmitButtonCommandName;
                questionContainer.PushButton = pushButton;
 
                questionContainer.HelpPageLink = new HyperLink();
                questionContainer.HelpPageLink.ID = _helpLinkID;
                questionContainer.HelpPageIcon = new Image();
 
                Literal failureTextLabel = new Literal();
                failureTextLabel.ID = _failureTextID;
                questionContainer.FailureTextLabel = failureTextLabel;
            }
 
            /// <devdoc>
            /// Adds the controls to a table for layout.  Layout depends on TextLayout.
            /// </devdoc>
            private void LayoutControls(QuestionContainer questionContainer) {
                LoginTextLayout textLayout = _owner.TextLayout;
                if (textLayout == LoginTextLayout.TextOnLeft) {
                    LayoutTextOnLeft(questionContainer);
                }
                else {
                    LayoutTextOnTop(questionContainer);
                }
            }
 
            private void LayoutTextOnLeft(QuestionContainer questionContainer) {
                Table table = new Table();
                table.CellPadding = 0;
                TableRow r;
                TableCell c;
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.ColumnSpan = 2;
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(questionContainer.Title);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.ColumnSpan = 2;
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(questionContainer.Instruction);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Right;
                c.Controls.Add(questionContainer.UserNameLabel);
                r.Cells.Add(c);
 
                c = new TableCell();
                c.Controls.Add(questionContainer.UserName);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Right;
                c.Controls.Add(questionContainer.QuestionLabel);
                r.Cells.Add(c);
 
                c = new TableCell();
                c.Controls.Add(questionContainer.Question);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Right;
                c.Controls.Add(questionContainer.AnswerLabel);
                if (_owner.ConvertingToTemplate) {
                    questionContainer.AnswerLabel.RenderAsLabel = true;
                }
                r.Cells.Add(c);
 
                c = new TableCell();
                c.Controls.Add(questionContainer.AnswerTextBox);
                c.Controls.Add(questionContainer.AnswerRequired);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.ColumnSpan = 2;
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(questionContainer.FailureTextLabel);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.ColumnSpan = 2;
                c.HorizontalAlign = HorizontalAlign.Right;
                c.Controls.Add(questionContainer.LinkButton);
                c.Controls.Add(questionContainer.ImageButton);
                c.Controls.Add(questionContainer.PushButton);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.ColumnSpan = 2;
                c.Controls.Add(questionContainer.HelpPageIcon);
                c.Controls.Add(questionContainer.HelpPageLink);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                Table table2 = LoginUtil.CreateChildTable(_owner.ConvertingToTemplate);
                r = new TableRow();
                c = new TableCell();
                c.Controls.Add(table);
                r.Cells.Add(c);
                table2.Rows.Add(r);
 
                questionContainer.LayoutTable = table;
                questionContainer.BorderTable = table2;
                questionContainer.Controls.Add(table2);
            }
 
            private void LayoutTextOnTop(QuestionContainer questionContainer) {
                Table table = new Table();
                table.CellPadding = 0;
                TableRow r;
                TableCell c;
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(questionContainer.Title);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(questionContainer.Instruction);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.Controls.Add(questionContainer.UserNameLabel);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.Controls.Add(questionContainer.UserName);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.Controls.Add(questionContainer.QuestionLabel);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.Controls.Add(questionContainer.Question);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.Controls.Add(questionContainer.AnswerLabel);
                if (_owner.ConvertingToTemplate) {
                    questionContainer.AnswerLabel.RenderAsLabel = true;
                }
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.Controls.Add(questionContainer.AnswerTextBox);
                c.Controls.Add(questionContainer.AnswerRequired);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(questionContainer.FailureTextLabel);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Right;
                c.Controls.Add(questionContainer.LinkButton);
                c.Controls.Add(questionContainer.ImageButton);
                c.Controls.Add(questionContainer.PushButton);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.Controls.Add(questionContainer.HelpPageIcon);
                c.Controls.Add(questionContainer.HelpPageLink);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                Table table2 = LoginUtil.CreateChildTable(_owner.ConvertingToTemplate);
                r = new TableRow();
                c = new TableCell();
                c.Controls.Add(table);
                r.Cells.Add(c);
                table2.Rows.Add(r);
 
                questionContainer.LayoutTable = table;
                questionContainer.BorderTable = table2;
                questionContainer.Controls.Add(table2);
            }
 
            void ITemplate.InstantiateIn(Control container) {
                QuestionContainer questionContainer = (QuestionContainer)container;
                CreateControls(questionContainer);
                LayoutControls(questionContainer);
            }
        }
 
        /// <devdoc>
        /// The default success template for the control, used if SuccessTemplate is null.
        /// </devdoc>
        private sealed class DefaultSuccessTemplate : ITemplate {
            private PasswordRecovery _owner;
 
            public DefaultSuccessTemplate(PasswordRecovery owner) {
                _owner = owner;
            }
 
            private void CreateControls(SuccessContainer successContainer) {
                successContainer.SuccessTextLabel = new Literal();
            }
 
            private void LayoutControls(SuccessContainer successContainer) {
                Table table = new Table();
                table.CellPadding = 0;
                TableRow r = new LoginUtil.DisappearingTableRow();
                TableCell c = new TableCell();
 
                c.Controls.Add(successContainer.SuccessTextLabel);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                // Extra table for border padding
                Table table2 = LoginUtil.CreateChildTable(_owner.ConvertingToTemplate);
                r = new TableRow();
                c = new TableCell();
                c.Controls.Add(table);
                r.Cells.Add(c);
                table2.Rows.Add(r);
 
                successContainer.LayoutTable = table;
                successContainer.BorderTable = table2;
                successContainer.Controls.Add(table2);
            }
 
            void ITemplate.InstantiateIn(Control container) {
                SuccessContainer successContainer = (SuccessContainer)container;
                CreateControls(successContainer);
                LayoutControls(successContainer);
            }
        }
 
        /// <devdoc>
        /// The default user name template for the control, used if UserNameTemplate is null.
        /// </devdoc>
        private sealed class DefaultUserNameTemplate : ITemplate {
            private PasswordRecovery _owner;
 
            public DefaultUserNameTemplate(PasswordRecovery owner) {
                _owner = owner;
            }
 
            private void CreateControls(UserNameContainer userNameContainer) {
                string validationGroup = _owner.UniqueID;
 
                userNameContainer.Title = new Literal();
                userNameContainer.Instruction = new Literal();
 
                TextBox userNameTextBox = new TextBox();
                // Must explicitly set the ID of controls that raise postback events
                userNameTextBox.ID = _userNameID;
                userNameContainer.UserNameTextBox = userNameTextBox;
                userNameContainer.UserNameLabel = new LabelLiteral(userNameTextBox);
 
                bool enableValidation = (_owner.CurrentView == View.UserName);
                RequiredFieldValidator userNameRequired = new RequiredFieldValidator();
                userNameRequired.ID = _userNameRequiredID;
                userNameRequired.ValidationGroup = validationGroup;
                userNameRequired.ControlToValidate = userNameTextBox.ID;
                userNameRequired.Display = _requiredFieldValidatorDisplay;
                userNameRequired.Text = SR.GetString(SR.LoginControls_DefaultRequiredFieldValidatorText);
                userNameRequired.Enabled = enableValidation;
                userNameRequired.Visible = enableValidation;
                userNameContainer.UserNameRequired = userNameRequired;
 
                LinkButton linkButton = new LinkButton();
                linkButton.ID = _linkButtonID;
                linkButton.ValidationGroup = validationGroup;
                linkButton.CommandName = SubmitButtonCommandName;
                userNameContainer.LinkButton = linkButton;
 
                ImageButton imageButton = new ImageButton();
                imageButton.ID = _imageButtonID;
                imageButton.ValidationGroup = validationGroup;
                imageButton.CommandName = SubmitButtonCommandName;
                userNameContainer.ImageButton = imageButton;
 
                Button pushButton = new Button();
                pushButton.ID = _pushButtonID;
                pushButton.ValidationGroup = validationGroup;
                pushButton.CommandName = SubmitButtonCommandName;
                userNameContainer.PushButton = pushButton;
 
                userNameContainer.HelpPageLink = new HyperLink();
                userNameContainer.HelpPageLink.ID = _helpLinkID;
                userNameContainer.HelpPageIcon = new Image();
 
                Literal failureTextLabel = new Literal();
                failureTextLabel.ID = _failureTextID;
                userNameContainer.FailureTextLabel = failureTextLabel;
            }
 
            private void LayoutControls(UserNameContainer userNameContainer) {
                LoginTextLayout textLayout = _owner.TextLayout;
                if (textLayout == LoginTextLayout.TextOnLeft) {
                    LayoutTextOnLeft(userNameContainer);
                }
                else {
                    LayoutTextOnTop(userNameContainer);
                }
            }
 
            private void LayoutTextOnLeft(UserNameContainer userNameContainer) {
                Table table = new Table();
                table.CellPadding = 0;
                TableRow r;
                TableCell c;
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.ColumnSpan = 2;
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(userNameContainer.Title);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.ColumnSpan = 2;
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(userNameContainer.Instruction);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Right;
                c.Controls.Add(userNameContainer.UserNameLabel);
                if (_owner.ConvertingToTemplate) {
                    userNameContainer.UserNameLabel.RenderAsLabel = true;
                }
                r.Cells.Add(c);
 
                c = new TableCell();
                c.Controls.Add(userNameContainer.UserNameTextBox);
                c.Controls.Add(userNameContainer.UserNameRequired);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.ColumnSpan = 2;
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(userNameContainer.FailureTextLabel);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.ColumnSpan = 2;
                c.HorizontalAlign = HorizontalAlign.Right;
                c.Controls.Add(userNameContainer.LinkButton);
                c.Controls.Add(userNameContainer.ImageButton);
                c.Controls.Add(userNameContainer.PushButton);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.ColumnSpan = 2;
                c.Controls.Add(userNameContainer.HelpPageIcon);
                c.Controls.Add(userNameContainer.HelpPageLink);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                Table table2 = LoginUtil.CreateChildTable(_owner.ConvertingToTemplate);
                r = new TableRow();
                c = new TableCell();
                c.Controls.Add(table);
                r.Cells.Add(c);
                table2.Rows.Add(r);
 
                userNameContainer.LayoutTable = table;
                userNameContainer.BorderTable = table2;
                userNameContainer.Controls.Add(table2);
            }
 
            private void LayoutTextOnTop(UserNameContainer userNameContainer) {
                Table table = new Table();
                table.CellPadding = 0;
                TableRow r;
                TableCell c;
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(userNameContainer.Title);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(userNameContainer.Instruction);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.Controls.Add(userNameContainer.UserNameLabel);
                if (_owner.ConvertingToTemplate) {
                    userNameContainer.UserNameLabel.RenderAsLabel = true;
                }
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.Controls.Add(userNameContainer.UserNameTextBox);
                c.Controls.Add(userNameContainer.UserNameRequired);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Center;
                c.Controls.Add(userNameContainer.FailureTextLabel);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.HorizontalAlign = HorizontalAlign.Right;
                c.Controls.Add(userNameContainer.LinkButton);
                c.Controls.Add(userNameContainer.ImageButton);
                c.Controls.Add(userNameContainer.PushButton);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                r = new LoginUtil.DisappearingTableRow();
                c = new TableCell();
                c.Controls.Add(userNameContainer.HelpPageIcon);
                c.Controls.Add(userNameContainer.HelpPageLink);
                r.Cells.Add(c);
                table.Rows.Add(r);
 
                Table table2 = LoginUtil.CreateChildTable(_owner.ConvertingToTemplate);
                r = new TableRow();
                c = new TableCell();
                c.Controls.Add(table);
                r.Cells.Add(c);
                table2.Rows.Add(r);
 
                userNameContainer.LayoutTable = table;
                userNameContainer.BorderTable = table2;
                userNameContainer.Controls.Add(table2);
            }
 
            void ITemplate.InstantiateIn(Control container) {
                UserNameContainer userNameContainer = (UserNameContainer)container;
                CreateControls(userNameContainer);
                LayoutControls(userNameContainer);
            }
        }
 
 
        /// <devdoc>
        ///     Container for the question template.  Contains properties that reference each child control.
        ///     For the default template, the properties are set when the child controls are created.
        ///     For the user template, the controls are looked up dynamically by ID.  Some controls are required,
        ///     and an exception is thrown if they are missing.  Other controls are optional, and an exception is
        ///     thrown if they have the wrong type.
        ///     Internal instead of private because it must be used by PasswordRecoveryAdapter.
        /// </devdoc>
        internal sealed class QuestionContainer : LoginUtil.GenericContainer<PasswordRecovery>, INonBindingContainer {
            private LabelLiteral _answerLabel;
            private RequiredFieldValidator _answerRequired;
            private Control _answerTextBox;
            private Control _failureTextLabel;
            private HyperLink _helpPageLink;
            private Image _helpPageIcon;
            private ImageButton _imageButton;
            private Literal _instruction;
            private LinkButton _linkButton;
            private Button _pushButton;
            private Control _question;
            private Literal _questionLabel;
            private Literal _title;
            private Literal _userNameLabel;
            private Control _userName;
 
            public QuestionContainer(PasswordRecovery owner) : base(owner) {
            }
 
            public LabelLiteral AnswerLabel {
                get {
                    return _answerLabel;
                }
                set {
                    _answerLabel = value;
                }
            }
 
            public RequiredFieldValidator AnswerRequired {
                get {
                    return _answerRequired;
                }
 
                set {
                    _answerRequired = value;
                }
            }
 
            public Control AnswerTextBox {
                get {
                    if (_answerTextBox != null) {
                        return _answerTextBox;
                    }
                    else {
                        return FindRequiredControl<IEditableTextControl>(_answerID, SR.PasswordRecovery_NoAnswerTextBox);
                    }
                }
                set {
                    _answerTextBox = value;
                }
            }
 
            protected override bool ConvertingToTemplate {
                get {
                    return Owner.ConvertingToTemplate;
                }
            }
 
            public Control FailureTextLabel {
                get {
                    if (_failureTextLabel != null) {
                        return _failureTextLabel;
                    }
                    else {
                        return FindOptionalControl<ITextControl>(_failureTextID);
                    }
                }
                set {
                    _failureTextLabel = value;
                }
            }
 
            public Image HelpPageIcon {
                get {
                    return _helpPageIcon;
                }
                set {
                    _helpPageIcon = value;
                }
            }
 
            public HyperLink HelpPageLink {
                get {
                    return _helpPageLink;
                }
                set {
                    _helpPageLink = value;
                }
            }
 
            public ImageButton ImageButton {
                get {
                    return _imageButton;
                }
                set {
                    _imageButton = value;
                }
            }
 
            public Literal Instruction {
                get {
                    return _instruction;
                }
                set {
                    _instruction = value;
                }
            }
 
            public LinkButton LinkButton {
                get {
                    return _linkButton;
                }
                set {
                    _linkButton = value;
                }
            }
 
            public Button PushButton {
                get {
                    return _pushButton;
                }
                set {
                    _pushButton = value;
                }
            }
 
            public Control Question {
                get {
                    if (_question != null) {
                        return _question;
                    }
                    else {
                        return FindOptionalControl<ITextControl>(_questionID);
                    }
                }
                set {
                    _question = value;
                }
            }
 
            public Literal QuestionLabel {
                get {
                    return _questionLabel;
                }
                set {
                    _questionLabel = value;
                }
            }
 
            public Literal Title {
                get {
                    return _title;
                }
                set {
                    _title = value;
                }
            }
 
            public Control UserName {
                get {
                    if (_userName != null) {
                        return _userName;
                    }
                    else {
                        return FindOptionalControl<ITextControl>(_userNameID);
                    }
                }
                set {
                    _userName = value;
                }
            }
 
            public Literal UserNameLabel {
                get {
                    return _userNameLabel;
                }
                set {
                    _userNameLabel = value;
                }
            }
        }
 
        /// <devdoc>
        ///     Container for the success template.
        ///     Internal instead of private because it must be used by PasswordRecoveryAdapter.
        /// </devdoc>
        internal sealed class SuccessContainer : LoginUtil.GenericContainer<PasswordRecovery>, INonBindingContainer {
            private Literal _successTextLabel;
 
            public SuccessContainer(PasswordRecovery owner) : base(owner) {
            }
 
            protected override bool ConvertingToTemplate {
                get {
                    return Owner.ConvertingToTemplate;
                }
            }
 
            public Literal SuccessTextLabel {
                get {
                    return _successTextLabel;
                }
                set {
                    _successTextLabel = value;
                }
            }
        }
 
        /// <devdoc>
        ///     Container for the user name template.  Contains properties that reference each child control.
        ///     For the default template, the properties are set when the child controls are created.
        ///     For the user template, the controls are looked up dynamically by ID.  Some controls are required,
        ///     and an exception is thrown if they are missing.  Other controls are optional, and an exception is
        ///     thrown if they have the wrong type.
        ///     Internal instead of private because it must be used by PasswordRecoveryAdapter.
        /// </devdoc>
        internal sealed class UserNameContainer : LoginUtil.GenericContainer<PasswordRecovery>, INonBindingContainer {
            private Control _failureTextLabel;
            private Image _helpPageIcon;
            private HyperLink _helpPageLink;
            private ImageButton _imageButton;
            private Literal _instruction;
            private LinkButton _linkButton;
            private Button _pushButton;
            private Literal _title;
            private LabelLiteral _userNameLabel;
            private RequiredFieldValidator _userNameRequired;
            private Control _userNameTextBox;
 
            public UserNameContainer(PasswordRecovery owner) : base(owner) {
            }
 
            protected override bool ConvertingToTemplate {
                get {
                    return Owner.ConvertingToTemplate;
                }
            }
 
            public Control FailureTextLabel {
                get {
                    if (_failureTextLabel != null) {
                        return _failureTextLabel;
                    }
                    else {
                        return FindOptionalControl<ITextControl>(_failureTextID);
                    }
                }
                set {
                    _failureTextLabel = value;
                }
            }
 
            public Image HelpPageIcon {
                get {
                    return _helpPageIcon;
                }
                set {
                    _helpPageIcon = value;
                }
            }
 
            public HyperLink HelpPageLink {
                get {
                    return _helpPageLink;
                }
                set {
                    _helpPageLink = value;
                }
            }
 
            public ImageButton ImageButton {
                get {
                    return _imageButton;
                }
                set {
                    _imageButton = value;
                }
            }
 
            public Literal Instruction {
                get {
                    return _instruction;
                }
                set {
                    _instruction = value;
                }
            }
 
            public LinkButton LinkButton {
                get {
                    return _linkButton;
                }
                set {
                    _linkButton = value;
                }
            }
 
            public Button PushButton {
                get {
                    return _pushButton;
                }
                set {
                    _pushButton = value;
                }
            }
 
            public Literal Title {
                get {
                    return _title;
                }
                set {
                    _title = value;
                }
            }
 
            public LabelLiteral UserNameLabel {
                get {
                    return _userNameLabel;
                }
                set {
                    _userNameLabel = value;
                }
            }
 
            public RequiredFieldValidator UserNameRequired {
                get {
                    return _userNameRequired;
                }
 
                set {
                    _userNameRequired = value;
                }
            }
 
            public Control UserNameTextBox {
                get {
                    if (_userNameTextBox != null) {
                        return _userNameTextBox;
                    }
                    else {
                        return FindRequiredControl<IEditableTextControl>(_userNameID, SR.PasswordRecovery_NoUserNameTextBox);
                    }
                }
                set {
                    _userNameTextBox = value;
                }
            }
        }
 
        /// <devdoc>
        /// Internal because used from PasswordRecoveryAdapter
        /// </devdoc>
        internal enum View {
            UserName,
            Question,
            Success
        }
    }
}