using System;
using System.Configuration;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.Configuration;
using System.IO;
using System.Data;
using XMLProviders;

namespace Helion.CustomProviders.XML
{
   public partial class MembershipProvider :
   System.Web.Security.MembershipProvider
   {
      private MembershipDataSet memberData;
      private string name;
      private string memberFile;
      private bool enablePasswordReset = false;
      private bool enablePasswordRetrieval = false;
      private string applicationName;
      private byte[] decryptionKey;
      private byte[] validationKey;
      private bool requiresQuestionAndAnswer = false;
      private bool requiresUniqueEmail = false;
      private MembershipPasswordFormat passFormat =
          MembershipPasswordFormat.Hashed;
      private int maxInvalidPasswordAttempts;
      private int minRequiredNonAlphanumericCharacters;
      private int minRequiredPasswordLengh;
      private int passwordAttemptWindow;
      private string passwordStrengthRegularExpression;

      public override void Initialize(string name,
          System.Collections.Specialized.NameValueCollection config)
      {
         this.name = name;
         if (config["applicationName"] != null)
            applicationName = config["applicationName"];
         if (config["enablePasswordRetrieval"] != null)
            enablePasswordRetrieval =
                Convert.ToBoolean(config["enablePasswordRetrieval"]);
         if (config["enablePasswordReset"] != null)
            enablePasswordReset = Convert.ToBoolean(config["enablePasswordReset"]);
         if (config["requiresQuestionAndAnswer"] != null)
            requiresQuestionAndAnswer =
                Convert.ToBoolean(config["requiresQuestionAndAnswer"]);
         if (config["requiresUniqueEmail"] != null)
            requiresUniqueEmail =
                Convert.ToBoolean(config["requiresUniqueEmail"]);
         if (config["maxInvalidPasswordAttempts"] != null)
            maxInvalidPasswordAttempts =
                Convert.ToInt32(config["maxInvalidPasswordAttempts"]);
         if (config["minRequiredNonAlphanumericCharacters"] != null)
            minRequiredNonAlphanumericCharacters =
                Convert.ToInt32(config["minRequiredNonAlphanumericCharacters"]);
         if (config["minRequiredPasswordLength"] != null)
            minRequiredPasswordLength =
                Convert.ToInt32(config["minRequiredPasswordLength"]);
         if (config["passwordAttemptWindow"] != null)
            passwordAttemptWindow =
                Convert.ToInt32(config["passwordAttemptWindow"]);
         if (config["passwordStrengthRegularExpression"] != null)
            passwordStrengthRegularExpression =
                config["passwordStrengthRegularExpression"];

         if (config["passwordFormat"] != null)
         {
            switch (config["passwordFormat"].ToLower())
            {
               case "clear":
                  passFormat = MembershipPasswordFormat.Clear;
                  break;
               case "hashed":
                  passFormat = MembershipPasswordFormat.Hashed;
                  break;
               case "encrypted":
                  passFormat = MembershipPasswordFormat.Encrypted;
                  break;
               default:
                  throw new ConfigurationErrorsException(
                      string.Format("Unknown password format {0}.",
                      config["passwordFormat"]));
            }
         }
         memberFile =
             ConfigurationManager.ConnectionStrings[
                 config["connectionStringName"]].ConnectionString;
         InitializeData();
         LoadKey(config);
      }

      /* Różne proste właściwości get/set usunięte z listingu dla zachowania jasności */

      public override bool ChangePassword(string username, string oldPassword,
      string newPassword)
    {
        MembershipDataSet.UsersRow user = GetUserByName(username);
        if (user == null)
             throw new InvalidDataException("No such user exists.");
        if (!ComparePassword(oldPassword, user.Password))
             throw new ApplicationException("Existing password does not match.");

        user.Password = ConvertPasswordForStorage(newPassword);
        user.LastPasswordChangedTimeStamp = DateTime.Now;
        SaveData();
        return true;
    }

      public override bool ChangePasswordQuestionAndAnswer(string username,
      string password, string newPasswordQuestion, string newPasswordAnswer)
      {
         MembershipDataSet.UsersRow user =
             GetUserByNameAndPassword(username, password);

         user.PasswordQuestion = newPasswordQuestion;
         user.PasswordAnswer = newPasswordAnswer;
         SaveData();
         return true;
      }

      public override MembershipUser CreateUser(string username, string password,
      string email,
          string passwordQuestion, string passwordAnswer, bool IsApproved,
          object providerUserKey, out MembershipCreateStatus status)
    {
        status = MembershipCreateStatus.UserRejected;

        MembershipDataSet.UsersRow user = GetUserByName(username);
        if (user != null)
        {
            status = MembershipCreateStatus.DuplicateUserName;
            return null;
        }
    if (requiresUniqueEmail)
    {
        MembershipDataSet.UsersRow[] users =
            (MembershipDataSet.UsersRow[])memberData.Users.Select(
                "Email='" + email + "' AND ApplicationName='" + applicationName + "'");
        if ((users != null) && (users.Length > 0))
        {
            return null;
        }
    }
    Guid newUserId = Guid.NewGuid();
    MembershipDataSet.UsersRow newUser = memberData.Users.NewUsersRow();
    newUser.UserId = newUserId;
    newUser.UserName = username;
    newUser.Password = ConvertPasswordForStorage(password);
    newUser.Email = email;
    newUser.ApplicationName = applicationName;
    newUser.PasswordQuestion = passwordQuestion;
    newUser.PasswordAnswer = passwordAnswer;
    newUser.IsApproved = isApproved;
    newUser.LastActivityTimeStamp = DateTime.Now;
    newUser.LastLoginTimeStamp = DateTime.Now;
    newUser.Comment = string.Empty;
    newUser.UserCreationTimeStamp = DateTime.Now;
    newUser.LastPasswordChangedTimeStamp = DateTime.Now;
    memberData.Users.AddUsersRow(newUser);
    SaveData();
    MembershipUser newMembershipUser = new MembershipUser(name,
        username, providerUserKey, email, passwordQuestion, string.Empty,
        isApproved, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now,
        DateTime.MinValue);
    status = MembershipCreateStatus.Success;
    return newMembershipUser;
    }

      public override bool DeleteUser(string username, bool deleteAllRelatedData)
      {
         MembershipDataSet.UsersRow user = GetUserByName(username);
         if (user == null)
            throw new ApplicationException("No such user exists.");
         user.Delete();
         SaveData();
         return true;
      }

      public override MembershipUserCollection FindUsersByEmail(string emailToMatch,
          int pageIndex, int pageSize, out int totalRecord)
      {
         MembershipUserCollection uc = QueryUsers(
            "Email='" + emailToMatch + "' AND ApplicationName='" + applicationName + "'",
            pageIndex, pageSize, out totalRecords);
         return uc;
      }

      public override MembershipUserCollection FindUsersByName(string usernameToMatch,
          int pageIndex, int pageSize, out int totalRecords)
      {
         MembershipUserCollection uc = QueryUsers(
            "UserName='" + usernameToMatch + "' AND ApplicationName='" +
            applicationName + "'",
            pageIndex, pageSize, out totalRecords);
         return uc;
      }

      public override MembershipUserCollection GetAllUsers(int pageIndex,
          int pageSize, out int totalRecords)
      {
         MembershipUserCollection uc = QueryUsers(
            "ApplicationName='" + applicationName + "'", pageIndex,
            pageSize, out totalRecords);
         return uc;
      }

      public override int GetNumberOfUsersOnLine()
      {
         int totalRecords;
         MembershipUserCollection uc = QueryUsers(
             "LastActivityTimeStamp >= " + DateTime.Now.AddMinutes(-1 *
             Membership.UserIsOnlineTimeWindow).ToString(),
             0, 1, out totalRecords);
         return totalRecords;
      }

      public override string GetPassword(string username,
      string answer)
      {
         if ((!enablePasswordRetrieval) ||
         (passFormat == MembershipPasswordFormat.Hashed))
            throw new
                ApplicationException(
                    "Current configuration Settings prevent password retrieval.");
         MembershipDataSet.UsersRow user = GetUserByName(username);
         if (user == null)
            throw new ApplicationException("No such user exists.");
         if (requiresQuestionAndAnswer)
         {
            if (user.PasswordAnswer.ToUpper() != answer.ToUpper())
            {
               throw new ApplicationExeption(
                   "Security question answer supplied is incorrect.");
            }
         }
         return GetClearPassword(user.Password);
      }

      public override MembershipUser GetUser(string username, bool userIsOnline)
      {
         MembershipDataSet.UsersRow user = GetUserByName(username);
         MembershipUser mu;
         if (userIsOnline)
         {
            user.LastActivityTimeStamp = DateTime.Now;
            SaveData();
         }
         mu = new MembershipUser(
             name, user.UserName, user.UserID,
             user.Email, user.PasswordQuestion, user.Comment,
             user.IsApproved, false, user.UserCreationTimeStamp, user.LastLoginTimeStamp,
             user.LastActivityTimeStamp, user.LastPasswordChangedTimeStamp,
             DateTime.MinValue);
         return mu;
      }

      public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
      {
         DataRow[] rows =
             memberData.Users.Select(
                 "UserId='" + ((Guid)providerUserKey).ToString() + "'");
         if ((rows != null) && (rows.Length > 0))
         {
            MembershipDataSet.UsersRow user = (MembershipDataSet.UsersRow)rows[0];
            MembershipUser mu;
            if (userIsOnline)
            {
               user.LastActivityTimeStamp = DateTime.Now;
               SaveData();
            }
            mu = new MembershipUser(
                    name, user.UserName, user.UserID,
                    user.Email, user.PasswordQuestion, user.Comment,
                    user.IsApproved, false, user.UserCreationTimeStamp,
                    user.LastLoginTimeStamp,
                    user.LastActivityTimeStamp, user.LastPasswordChangedTimeStamp,
                    DateTime.MinValue);
            return mu;
         }
         else
         {
            throw new ApplicationException("Specified user does not exist.");
         }
      }

      public override string GetUserNameByEmail(string email)
      {
         MembershipDataSet.UsersRow user;
         DataRow[] rows =
             memberData.Users.Select(
                 "Email='" + email + "'" +
                 " AND ApplicationName='" + applicationName + "'");
         if ((rows != null) && (rows.Length > 0))
         {
            user = (MembershipDataSet.UsersRow)rows[0];
            return user.UserName;
         }
         else
            throw new ApplicationException(
                "No such user exists with given e-mail address.");
      }

      public override string ResetPassword(string username, string answer)
      {
         if (!enablePasswordReset)
            throw new ApplicationException(
                "Cannot reset password under current provider configuration settings.");
         MembershipDataSet.UsersRow user = GetUserByName(username);
         if (user == null)
            throw new ApplicationException("No such user found.");
         string newPw =
             Membership.GeneratePassword(minRequiredPasswordLength,
                 minRequiredNonAlphanumericCharacters);
         user.Password = ConvertPasswordForStorage(newPw);
         user.LastPasswordChangedTimeStamp = DateTime.Now;
         SaveData();
         return newPw;
      }

      public override bool UnlockUser(string userName)
      {
         // ten dostawca nie blokuje użytkowników, więc nic nie rób
         return true;
      }

      public override void UpdateUser(MembershipUser user)
      {
         DataRow[] rows =
             memberData.Users.Select(
                 string.Format("UserID={0}", ((Guid)user.ProvideUserKey).ToString()));
         if ((rows != null) && (rows.Length > 0))
         {
            MembershiipDataSet.UsersRow userRow =
                (MembersipDataSet.UsersRow)rows[0];
            CopyMembershipUserToRow(user, userRow);
            SaveData();
         }
         else
            throw new ApplicationException("No such user found to update.");
      }

      public override bool ValidateUser(string username, string password)
      {
         MembershipDataSet.UsersRow user = GetUserByName(username);
         if (user == null)
            return false;
         if (!ComparePassword(password, user.Password))
            return false;
         user.LastLoginTimeStamp = DateTime.Now;
         user.LastActivityTimeStamp = DateTime.Now;
         SaveData();
         return true;
      }
   }
}
