namespace RadDataFormAndRIA.LoginUI
{
	using System;
	using System.ComponentModel.DataAnnotations;
	using System.ServiceModel.DomainServices.Client;
	using System.ServiceModel.DomainServices.Client.ApplicationServices;
	using RadDataFormAndRIA.Web.Resources;

	/// <summary>
	/// This internal entity is used to ease the binding between the UI controls (DataForm and the label displaying a validation error) and the log on credentials entered by the user.
	/// </summary>
	public class LoginInfo : ComplexObject
	{
		private string userName;
		private bool rememberMe;
		private LoginOperation currentLoginOperation;

		/// <summary>
		/// Gets and sets the user name.
		/// </summary>
		[Display(Name = "UserNameLabel", ResourceType = typeof(RegistrationDataResources))]
		[Required]
		public string UserName
		{
			get
			{
				return this.userName;
			}

			set
			{
				if (this.userName != value)
				{
					this.ValidateProperty("UserName", value);
					this.userName = value;
					this.RaisePropertyChanged("UserName");
				}
			}
		}

		/// <summary>
		/// Gets or sets a function that returns the password.
		/// </summary>
		internal Func<string> PasswordAccessor { get; set; }

		/// <summary>
		/// Gets and sets the password.
		/// </summary>
		[Display(Name = "PasswordLabel", ResourceType = typeof(RegistrationDataResources))]
		[Required]
		public string Password
		{
			get
			{
				return (this.PasswordAccessor == null) ? string.Empty : this.PasswordAccessor();
			}
			set
			{
				this.ValidateProperty("Password", value);

				// Do not store the password in a private field as it should not be stored in memory in plain-text.
				// Instead, the supplied PasswordAccessor serves as the backing store for the value.

				this.RaisePropertyChanged("Password");
			}
		}

		/// <summary>
		/// Gets and sets the value indicating whether the user's authentication information should be recorded for future logins.
		/// </summary>
		[Display(Name = "RememberMeLabel", ResourceType = typeof(ApplicationStrings))]
		public bool RememberMe
		{
			get
			{
				return this.rememberMe;
			}

			set
			{
				if (this.rememberMe != value)
				{
					this.ValidateProperty("RememberMe", value);
					this.rememberMe = value;
					this.RaisePropertyChanged("RememberMe");
				}
			}
		}

		/// <summary>
		/// Gets or sets the current login operation.
		/// </summary>
		internal LoginOperation CurrentLoginOperation
		{
			get
			{
				return this.currentLoginOperation;
			}
			set
			{
				if (this.currentLoginOperation != value)
				{
					if (this.currentLoginOperation != null)
					{
						this.currentLoginOperation.Completed -= (s, e) => this.CurrentLoginOperationChanged();
					}

					this.currentLoginOperation = value;

					if (this.currentLoginOperation != null)
					{
						this.currentLoginOperation.Completed += (s, e) => this.CurrentLoginOperationChanged();
					}

					this.CurrentLoginOperationChanged();
				}
			}
		}

		/// <summary>
		/// Gets a value indicating whether the user is presently being logged in.
		/// </summary>
		[Display(AutoGenerateField = false)]
		public bool IsLoggingIn
		{
			get
			{
				return this.CurrentLoginOperation != null && !this.CurrentLoginOperation.IsComplete;
			}
		}

		/// <summary>
		/// Gets a value indicating whether the user can presently log in.
		/// </summary>
		[Display(AutoGenerateField = false)]
		public bool CanLogIn
		{
			get
			{
				return !this.IsLoggingIn;
			}
		}

		/// <summary>
		/// Raises operation-related property change notifications when the current login operation changes.
		/// </summary>
		private void CurrentLoginOperationChanged()
		{
			this.RaisePropertyChanged("IsLoggingIn");
			this.RaisePropertyChanged("CanLogIn");
		}

		/// <summary>
		/// Creates a new <see cref="LoginParameters"/> instance using the data stored in this entity.
		/// </summary>
		public LoginParameters ToLoginParameters()
		{
			return new LoginParameters(this.UserName, this.Password, this.RememberMe, null);
		}
	}
}
