using System;
using System.Collections;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.Data.Sql;
using ASPNETVN.PORTAL.Components.Helpers;

namespace ASPNETVN.PORTAL.Components.Security
{
    public enum UserStatus
    {
        ACTIVE,
        DEACTIVE,
        LOCK
    }

    public partial class User
    {
        public override string ToString()
        {
            return this._Name + "|" + this._Email + "|" + this._ID;
        }

        public static DataSet SelectBy_RoleID(string roleID)
        {
            if (roleID == "ALL")
            {
                return SelectAll();
            }

            const string spName = "p_SYSTEM_User_SelectBy_RoleID";
            Database db = DatabaseFactory.CreateDatabase();

            DbCommand dbCommand = db.GetStoredProcCommand(spName);

            db.AddInParameter(dbCommand, "@RoleID", DbType.String, roleID);

            return db.ExecuteDataSet(dbCommand);
        }

        public static DataSet SelectBy_ID(int id)
        {
            const string spName = "p_SYSTEM_User_Load";
            Database db = DatabaseFactory.CreateDatabase();

            DbCommand dbCommand = db.GetStoredProcCommand(spName);
            db.AddInParameter(dbCommand, "@ID", DbType.Int32, id);
            return db.ExecuteDataSet(dbCommand);
        }

        // Check Exist By Email and PortalID.
        public static bool CheckExist(string email)
        {
            const string spName = "p_SYSTEM_User_CheckExistBy_Email_PortalID";
            Database db = DatabaseFactory.CreateDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(spName);
            
            db.AddInParameter(dbCommand, "@Email", DbType.String, email);
            db.AddInParameter(dbCommand, "@PortalID", DbType.Guid, Global.PortalID);
            
            IDataReader reader = db.ExecuteReader(dbCommand);
            bool returnValue = false;
            if (reader.Read())
            {
                returnValue = true;
            }
            reader.Close();
            dbCommand.Connection.Close();
            return returnValue;
        }

        // Reset Password By Email and PortalID with random new password.
        public static string ResetPassword(string email)
        {
            // Generate new password.
            Random rnd = new Random();
            string newPassword = string.Empty;
            for (int n = 0; n < 8; n++)
            {
                newPassword += rnd.Next(0, 9).ToString();
            }

            return ResetPassword(email, newPassword);
        }

        // Reset Password By Email and PortalID with specific password.
        public static string ResetPassword(string email, string newPassword)
        {
            const string spName = "p_SYSTEM_User_ResetPasswordBy_Email_PortalID";
            Database db = DatabaseFactory.CreateDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(spName);
            
            db.AddInParameter(dbCommand, "@Email", DbType.String, email);
            db.AddInParameter(dbCommand, "@PortalID", DbType.Guid, Global.PortalID);
            db.AddInParameter(dbCommand, "@NewPassword", DbType.String, PortalSecurity.Encrypt(newPassword));
            int i = db.ExecuteNonQuery(dbCommand);
            if (i <= 0) newPassword = string.Empty;
            return newPassword;
        }

        public int Register()
        {
            const string spName = "p_SYSTEM_User_Register";
            SqlDatabase db = (SqlDatabase) DatabaseFactory.CreateDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(spName);
            db.AddInParameter(dbCommand, "@Name", SqlDbType.VarChar, this._Name);
            db.AddInParameter(dbCommand, "@Email", SqlDbType.VarChar, this._Email);
            db.AddInParameter(dbCommand, "@Password", SqlDbType.VarChar, PortalSecurity.Encrypt(this._Password));
            db.AddInParameter(dbCommand, "@PortalID", SqlDbType.UniqueIdentifier, Global.PortalID);
            db.AddOutParameter(dbCommand, "@ID", SqlDbType.Int, 4);
            db.ExecuteNonQuery(dbCommand);
            return (int) db.GetParameterValue(dbCommand, "@ID");
        }

        public static DataSet Search(string whereExpression)
        {
            string query = "SELECT * FROM t_SYSTEM_Users WHERE " + whereExpression;
            Database db = DatabaseFactory.CreateDatabase();
            DbCommand dbCommand = db.GetSqlStringCommand(query);
            return db.ExecuteDataSet(dbCommand);
        }

        //-----------------------------------------------------------------------------------------
        public static bool Active(string activeCode)
        {
            try
            {
                const string spName = "p_SYSTEM_User_Active";
                Database db = DatabaseFactory.CreateDatabase();
                DbCommand dbCommand = db.GetStoredProcCommand(spName);
                db.AddInParameter(dbCommand, "@Email", DbType.String, DecryptHelper.Decrypt(activeCode));
                db.AddInParameter(dbCommand, "@PortalID", DbType.Guid, Global.PortalID);
                int i = db.ExecuteNonQuery(dbCommand);
                return i > 0;
            }
            catch
            {
                return false;
            }
        }

        public static void UpdateStatus(int id, UserStatus status)
        {
            const string spName = "p_SYSTEM_User_UpdateStatus";
            Database db = DatabaseFactory.CreateDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(spName);
            db.AddInParameter(dbCommand, "@Status", DbType.String, status.ToString());
            db.AddInParameter(dbCommand, "@ID", DbType.Int32, id);
            db.ExecuteNonQuery(dbCommand);
        }

        // Change Password By Email and PortalID.
        public static bool ChangePassword(string email, string oldPassword, string newPassword)
        {
            const string spName = "p_SYSTEM_User_ChangePassword";
            Database db = DatabaseFactory.CreateDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(spName);
            db.AddInParameter(dbCommand, "@PortalID", DbType.Guid, Global.PortalID);
            db.AddInParameter(dbCommand, "@Email", DbType.String, email);
            db.AddInParameter(dbCommand, "@NewPassword", DbType.String, PortalSecurity.Encrypt(newPassword));
            db.AddInParameter(dbCommand, "@OldPassword", DbType.String, PortalSecurity.Encrypt(oldPassword));
            int i = db.ExecuteNonQuery(dbCommand);
            return i > 0;
        }

        public static bool AddToRole(int userID, string roleID)
        {
            const string spName = "p_SYSTEM_User_Role_Insert";
            Database db = DatabaseFactory.CreateDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(spName);
            db.AddInParameter(dbCommand, "@UserID", DbType.Int32, userID);
            db.AddInParameter(dbCommand, "@RoleID", DbType.String, roleID);
            int i = db.ExecuteNonQuery(dbCommand);
            return i > 0;
        }


        public static void AddToRole(int userID, int roleID)
        {
            AddToRole(null, userID, roleID);
        }


        private static void DeleteRole(DbTransaction transaction, int userID)
        {
            const string spName = "p_SYSTEM_Users_Roles_DeleteBy_UserID";
            SqlDatabase db = (SqlDatabase)DatabaseFactory.CreateDatabase();
            SqlCommand dbCommand = (SqlCommand)db.GetStoredProcCommand(spName);
            db.AddInParameter(dbCommand, "@UserID", SqlDbType.Int, userID);
            db.ExecuteNonQuery(dbCommand, transaction);
        }

        public static int RemoveRole(int userID, int roleID)
        {
            const string spName = "p_SYSTEM_Users_Roles_DeleteBy_UserID_RoleID";
            SqlDatabase db = (SqlDatabase)DatabaseFactory.CreateDatabase();
            SqlCommand dbCommand = (SqlCommand)db.GetStoredProcCommand(spName);
            db.AddInParameter(dbCommand, "@UserID", SqlDbType.Int, userID);
            db.AddInParameter(dbCommand, "@RoleID", SqlDbType.Int, roleID);
            return db.ExecuteNonQuery(dbCommand);

        }

        private static void AddToRole(DbTransaction transaction, int userID, int roleID)
        {
            const string spName = "p_SYSTEM_User_AddToRole";
            SqlDatabase db = (SqlDatabase)DatabaseFactory.CreateDatabase();
            SqlCommand dbCommand = (SqlCommand)db.GetStoredProcCommand(spName);

            db.AddInParameter(dbCommand, "@UserID", SqlDbType.Int, userID);
            db.AddInParameter(dbCommand, "@RoleID", SqlDbType.Int, roleID);

            if (transaction != null)
                db.ExecuteNonQuery(dbCommand, transaction);
            else
                db.ExecuteNonQuery(dbCommand);
        }


        public static bool AddToRoles(int userID, ArrayList roles)
        {
            bool returnValue;
            SqlDatabase db = (SqlDatabase)DatabaseFactory.CreateDatabase();
            using (SqlConnection connection = (SqlConnection)db.CreateConnection())
            {
                connection.Open();
                SqlTransaction transaction = connection.BeginTransaction();
                {
                    try
                    {
                        // Clear all role of user before insert new role.
                        DeleteRole(transaction, userID);

                        foreach (string role in roles)
                        {
                            AddToRole(transaction, userID, Convert.ToInt32(role));
                        }
                        transaction.Commit();
                        returnValue = true;
                    }
                    catch
                    {
                        transaction.Rollback();
                        returnValue = false;
                    }
                    finally
                    {
                        connection.Close();
                    }
                }
            }
            return returnValue;
        }

        //---------------------------------------------------------------------------------------------

        //// Get Roles By Email and PortalID.
        //public static string[] GetRoles(string email)
        //{
        //    string spName = "p_SYSTEM_User_GetRolesBy_Email_PortalID";
        //    Database db = DatabaseFactory.CreateDatabase();
        //    DbCommand dbCommand = db.GetStoredProcCommand(spName);

        //    db.AddInParameter(dbCommand, "@Email", DbType.String, email);
        //    db.AddInParameter(dbCommand, "@PortalID", DbType.Int32, Global.PortalID);

        //    IDataReader reader = db.ExecuteReader(dbCommand);

        //    ArrayList userRoles = new ArrayList();
        //    while (reader.Read())
        //    {
        //        userRoles.Add(reader["ID"].ToString());
        //    }

        //    reader.Close();
        //    dbCommand.Connection.Close();
        //    return (string[]) userRoles.ToArray(typeof (string));
        //}

        public static string[] GetRoles(int userID)
        {
            const string spName = "p_SYSTEM_User_GetRolesBy_UserID";
            Database db = DatabaseFactory.CreateDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(spName);

            db.AddInParameter(dbCommand, "@UserID", DbType.String, userID);

            IDataReader reader = db.ExecuteReader(dbCommand);

            ArrayList userRoles = new ArrayList();
            while (reader.Read())
            {
                userRoles.Add(reader["ID"].ToString());
            }

            reader.Close();
            dbCommand.Connection.Close();
            return (string[])userRoles.ToArray(typeof(string));
        }

        public static DataSet SelectRolesBy_UserID(int userID)
        {
            const string spName = "p_SYSTEM_User_GetRolesBy_UserID";
            Database db = DatabaseFactory.CreateDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(spName);
            db.AddInParameter(dbCommand, "@UserID", DbType.String, userID);
            return db.ExecuteDataSet(dbCommand);
        }

        //-----------------------------------------------------------------------------------------

        // Login By Email and Password and PortalID.
        public static IdentityUser Login(string email, string password)
        {
            const string spName = "p_SYSTEM_User_Login";
            SqlDatabase db = (SqlDatabase)DatabaseFactory.CreateDatabase();
            SqlCommand dbCommand = (SqlCommand) db.GetStoredProcCommand(spName);
            db.AddInParameter(dbCommand, "@PortalID", SqlDbType.UniqueIdentifier, Global.PortalID);
            db.AddInParameter(dbCommand, "@Email", SqlDbType.VarChar, email);
            db.AddInParameter(dbCommand, "@Password", SqlDbType.VarChar, PortalSecurity.Encrypt(password));
            IDataReader reader = db.ExecuteReader(dbCommand);
            IdentityUser returnValue = null;
            if (reader.Read())
            {
                returnValue = new IdentityUser(Convert.ToInt32(reader["ID"]), reader["Email"].ToString());
            }
            reader.Close();
            dbCommand.Connection.Close();
            return returnValue;
        }

        //-----------------------------------------------------------------------------------------

        public static int ChangeDepartment(int userID, string departmentID)
        {
            const string spName = "p_SYSTEM_User_ChangeDepartment";
            SqlDatabase db = (SqlDatabase) DatabaseFactory.CreateDatabase();
            SqlCommand dbCommand = (SqlCommand) db.GetStoredProcCommand(spName);

            db.AddInParameter(dbCommand, "@ID", SqlDbType.Int, userID);
            db.AddInParameter(dbCommand, "@DepartmentID", SqlDbType.VarChar, departmentID);
            return db.ExecuteNonQuery(dbCommand);
        }
    }
}