#if SQLSERVER
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace Sdaleo.Systems.SQLServer
{
    #region SQLServer Security Enums

    /// <summary>
    /// Server Roles as specified in SQL Server
    /// </summary>
    public enum SQLServerRole
    {
        sysadmin,
        securityadmin,
        serveradmin,
        setupadmin,
        processadmin,
        diskadmin,
        dbcreator,
        bulkadmin,
    }

    /// <summary>
    /// User Roles as specified in SQL Server
    /// </summary>
    public enum SQLServerUserRole
    {
        db_accessadmin,
        db_backupoperator,
        db_datareader,
        db_datawriter,
        db_ddladmin,
        db_denydatareader,
        db_denydatawriter,
        db_owner,
        db_securityadmin,
    }

    /// <summary>
    /// These are the SQL Actions you can take on 
    /// SQLTablePermissions or SQLServerDatabasePermissions
    /// </summary>
    public enum SQLServerPermissionAction
    {
        GRANT,
        REVOKE,
        DENY
    }

    /// <summary>
    /// User Permissions on any User Database ('_' must be stripped before using in in sql)
    /// </summary>
    public enum SQLServerDatabasePermission
    {
        CREATE_DATABASE, // <--- permission only allowed on 'Master' Database
        CONNECT,
        CREATE_TABLE,
        CREATE_DEFAULT,
        CREATE_FUNCTION,
        CREATE_PROCEDURE,
        CREATE_RULE,
        CREATE_VIEW,
        BACKUP_DATABASE,
        BACKUP_LOG
    }
    
    #endregion

    /// <summary>
    /// Security/Permission SQL Server Related
    /// </summary>
    public class SQLServerSecurity
    {        
        #region Internal Security Helper Functions

        /// <summary>
        /// We must strip out the '_' on the SQLServerDatabasePermission Enum to use it in an SQL Query
        /// </summary>
        internal static string SQLServerDatabasePermission_ToString(SQLServerDatabasePermission DatabasePermission)
        {
            return DatabasePermission.ToString().Replace('_', ' ');
        }

        /// <summary>
        /// Quick Helper function to get an SQLServerDatabasePermission[] that has all Permissions defined
        /// </summary>
        internal static SQLServerDatabasePermission[] SQLServerDatabasePermission_ToArray()
        {
            return (SQLServerDatabasePermission[])Enum.GetValues(typeof(SQLServerDatabasePermission));
        }

        /// <summary>
        /// Returns generated SQL Database Permissions string for the specified Database,Username with the specified permissions
        /// </summary>
        /// <param name="Username">Name of an existing User (required)</param>
        /// <param name="Action">Permission Action to take (required)</param>
        /// <param name="databasePermissions">array of  User Database permissions (required)</param>
        /// <param name="bIsMasterDB">Some User Permission require to be executed ONLY on the Master Database, set to true if this is sql is being generated for 'master'</param>
        /// <returns>a Database permission string or empty string if error occured</returns>
        internal static string BuildSQLServerDatabasePermissionsStr(string Username, SQLServerDatabasePermission[] databasePermissions, SQLServerPermissionAction Action, bool bIsMasterDB)
        {
            if (String.IsNullOrEmpty(Username) || (databasePermissions == null))
                return string.Empty;

            // add Action
            string sql = Action.ToString() + " ";

            // add each permission individually
            for (int i = 0; i < databasePermissions.Length; ++i)
            {
                // Skip certain permissions, unless this is the Master DB
                if ((databasePermissions[i] == SQLServerDatabasePermission.CREATE_DATABASE) && !bIsMasterDB)
                    continue;

                sql += SQLServerDatabasePermission_ToString(databasePermissions[i]);
                bool bIsLast = (i == (databasePermissions.Length - 1));
                if (!bIsLast)
                    sql += ",";
            }

            // add action adjective
            if (Action == SQLServerPermissionAction.REVOKE)
                sql += " FROM ";
            else
                sql += " TO ";

            // add user
            sql += string.Format("[{0}]", Username);

            return sql;
        }
        
        #endregion

        #region Database User Role 

        /// <summary>
        /// Use this to add a specified User Role to a specified User in the DB
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="Username">an existing Username to add role to (required)</param>
        /// <param name="Role">Role to add to specified MemberName</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public DBError DatabaseUserRoleAdd(IConnectDb credential, string Username, SQLServerUserRole Role)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");
            
            if (!ValidationConsts.Generic.IsValidUserName(Username))
                return DBError.Create("Invalid Username Passed In");            
            
            // Execute the Query 
            string sql = String.Format("sp_addrolemember @membername = '{0}', @rolename = '{1}'", Username, Role.ToString());
            DB db = DB.Create(credential);
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            return retVal;
        }

        /// <summary>
        /// Use this to drop a specified User Role from a specified User in the DB
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="Username">an existing Username to drop role from (required)</param>
        /// <param name="Role">Role to drop from specified MemberName</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseUserRoleDrop(IConnectDb credential, string Username, SQLServerUserRole Role)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(Username))
                return DBError.Create("Invalid Username Passed In");         

            // Execute and return the Query
            string sql = String.Format("sp_droprolemember @membername = '{0}', @rolename = '{1}'", Username, Role.ToString());            
            DB db = DB.Create(credential);
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            return retVal;
        }

        #endregion

        #region Database User

        /// <summary>
        /// Use this to query if the Username already exists as an SQL Database User (Does not query Server users ONLY DB Users)
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="Username">Specify the Username to Query for (required)</param>
        /// <param name="bExists">True if the User exists in the specified Database, False otherwise</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseUserExists(IConnectDb credential, string Username, out bool bExists)
        {
            bExists = false;
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(Username))
                return DBError.Create("Invalid Username Passed In");         

            // Execute the Query and return
            string sql = string.Format("SELECT [name] FROM sys.database_principals WHERE [type_desc]='SQL_USER' and [name] = '{0}'", Username);
            DB db = DB.Create(credential);
            DBRetVal retVal = db.ExecuteScalar(sql);
            bExists = retVal.IsValid;
            return retVal;
        }

        /// <summary>
        /// Use this to retrieve a list of all the Database users for the specified SQL Server with DB Credentials
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="Users">a list of Database User, or Null if error occured</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseUsers(IConnectDb credential, out string[] Users)
        {
            Users = null;
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");            

            // Execute the Query
            string sql = "SELECT [name] FROM sys.database_principals WHERE [type_desc]='SQL_USER'";
            DB db = DB.Create(credential);
            DBRetVal retVal = db.FillDataTable(sql);                        
            if (retVal.IsValid)
            {
                List<String> retList = new List<string>();
                foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
                         retList.Add(row["name"].ToString());
                Users = retList.ToArray();
            }
            return retVal;
        }

        /// <summary>
        /// Add a new Username to the Specified Database for the specified Login
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="Username">Specify the Username for the database (can be same as LoginName) (required)</param>
        /// <param name="Loginname">Specify the LoginName (valid SQL Server Login Name) to create Username for (required)</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseUserAdd(IConnectDb credential, string Username, string LoginName)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(Username))
                return DBError.Create("Invalid Username Passed In");

            if (!ValidationConsts.Generic.IsValidUserName(LoginName))
                return DBError.Create("Invalid LoginName Passed In");

            // Execute the Query
            string sql = string.Format("CREATE USER [{0}] FOR LOGIN [{1}] WITH DEFAULT_SCHEMA = [{0}]", Username, LoginName);
            DB db = DB.Create(credential);
            DBRetVal retVal = db.ExecuteNonQuery(sql);                           
            if (!retVal.ErrorOccured)
            {
                // Since SQL 2005, We should create a SCHEMA for each User
                sql = string.Format("CREATE SCHEMA [{0}] AUTHORIZATION [{0}]", Username);
                retVal = db.ExecuteNonQuery(sql);
            }
            return retVal;
        }

        /// <summary>
        /// Drops an existing Username from the Specified Database
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="Username">Specify the Username for the database (required)</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseUserDrop(IConnectDb credential, string Username)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(Username))
                return DBError.Create("Invalid Username Passed In");

            // Since SQL 2005, We must drop the SCHEMA first for each User
            string sql = string.Format("DROP SCHEMA [{0}]", Username);
            DB db = DB.Create(credential);
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            if (!retVal.ErrorOccured)
            {
                sql = string.Format("DROP USER [{0}]", Username);
                retVal = db.ExecuteNonQuery(sql);
            }
            return retVal;
        }

        #endregion

        #region Database User Permission

        /// <summary>
        /// Automatically grant,deny,revoke all permissions on the database for the specified user
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="Username">Specify the Username for the database (required)</param>
        /// <param name="action">GRANT,DENY, or REVOKE 'Permission_All' Permission on that db</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseUserPermissionsAll(IConnectDb credential, string Username, SQLServerPermissionAction action)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(Username))
                return DBError.Create("Invalid Username Passed In");

            // Execute and return
            return DatabaseUserPermissions(credential, Username, SQLServerDatabasePermission_ToArray(), action);
        }

        /// <summary>
        /// Allows you to specify permissions to grant,deny,revoke on the database for the specified user
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="Username">Specify the Username for the database (required)</param>
        /// <param name="permissions">an array of permissions to take action on on db</param>
        /// <param name="action">GRANT,DENY, or REVOKE specified Permissions on that db</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseUserPermissions(IConnectDb credential, string Username, SQLServerDatabasePermission[] permissions, SQLServerPermissionAction action)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(Username))
                return DBError.Create("Invalid Username Passed In");

            // Execute the Query
            string sql = BuildSQLServerDatabasePermissionsStr(Username, permissions, action, SQLServerUtilities.IsSQLServerMasterDatabaseName(credential.DBMS.Database));
            DB db = DB.Create(credential);
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            return retVal;
        }

        #endregion

        #region Database Ownership

        /// <summary>
        /// Changes the Specified Database's Ownership to be owned by the specified LoginName
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>        
        /// <param name="LoginName">Specify the Login Name to To take over Database Ownership for (required)</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseChangeOwnership(IConnectDb credential, string LoginName)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(LoginName))
                return DBError.Create("Invalid LoginName Passed In");
         
            // Make sure that Login doesn't already own that Database
            bool bContinue = true;
            string[] ownedDBs = null;
            DBError dberror = DatabasesOwnedByLogin(credential.DBMS.WithoutDatabase(), LoginName, out ownedDBs);
            if (!dberror.ErrorOccured && ownedDBs != null)
            {
                foreach (string dbName in ownedDBs)
                {
                    if (dbName.ToLower() == credential.DBMS.Database.ToLower())
                    {
                        bContinue = false;
                        break;
                    }
                }
            }

            // Change the Database Ownership
            if (bContinue)
            {
                DB db = DB.Create(credential.DBMS.WithoutDatabase());
                string sql = String.Format("ALTER Authorization On Database::[{0}] To [{1}])", credential.DBMS.Database, LoginName);
                DBRetVal retVal = db.ExecuteNonQuery(sql);                
                return retVal;
            }
            return dberror;
        }

        /// <summary>
        /// Retrieve the SQL Login that is the Owner of the specified Database for the specified SQL Server
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="Owner">Name of DB Owner</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseOwner(IConnectDb credential, out string Owner)
        {
            Owner = String.Empty;
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            // Execute the Query
            DB db = DB.Create(credential);
            string sql = String.Format("Select suser_sname(owner_sid) from sys.databases where [name] = '{0}'", credential.DBMS.Database);
            DBRetVal retVal = db.ExecuteScalar(sql);
            if (retVal.IsValid)
                Owner = retVal.GetScalarRetVal();
            return retVal;            
        }

        /// <summary>
        /// Use this to retrieve all Databases that are owned by the specified Login for the specified SQL Server
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="LoginName">Specify the Login Name to Query Database Ownership for (required)</param>
        /// <param name="DatabasesOwned">DatabaseNames that are owned by this Login, null if none are found or error occured</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabasesOwnedByLogin(IConnectDb credential, string LoginName, out string[] DatabasesOwned)
        {
            DatabasesOwned = null;
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(LoginName))
                return DBError.Create("Invalid LoginName Passed In");

            // Execute the Query
            string sql = String.Format("Select [name] from sys.databases where [owner_sid] = SUSER_SID('{0}')", LoginName);
            DB db = DB.Create(credential);
            DBRetVal retVal = db.FillDataTable(sql);            
            if (retVal.IsValid)
            {
                List<String> retList = new List<String>();
                foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
                    retList.Add(row["name"].ToString());
                DatabasesOwned = retList.ToArray();
            }
            return retVal;
        }

        #endregion

        #region Login Roles

        /// <summary>
        /// Use this to add a specified Server Role to a specified Login in the DB
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="LoginName">existing login name to add server role to (required)</param>
        /// <param name="Role">Role to add to specified LoginName</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError LoginRoleAdd(IConnectDb credential, string LoginName, SQLServerRole Role)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(LoginName))
                return DBError.Create("Invalid LoginName Passed In");

            // Execute the Query and Return 
            string sql = String.Format("sp_addsrvrolemember @loginame = '{0}', @rolename = '{1}'", LoginName, Role.ToString());
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteNonQuery(sql);            
            return retVal;
        }

        /// <summary>
        /// Use this to drop a specified Server Role from a specified Login in the DB
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="LoginName">existing login name to drop server role from (required)</param>
        /// <param name="Role">Role to drop from a specified LoginName</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError LoginRoleDrop(IConnectDb credential, string LoginName, SQLServerRole Role)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(LoginName))
                return DBError.Create("Invalid LoginName Passed In");

            // Execute Query
            string sql = String.Format("sp_dropsrvrolemember @loginame = '{0}', @rolename = '{1}'", LoginName, Role.ToString());
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            return retVal;
        }

        /// <summary>
        /// Use this to query the SQLServer for the roles that are defined for the specified LoginName
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="LoginName">existing login name to query server roles for</param>
        /// <param name="Roles">Roles Corresponding the the ServerLogin</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError LoginRoles(IConnectDb credential, string LoginName, out SQLServerRole[] Roles)
        {
            Roles = null;
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(LoginName))
                return DBError.Create("Invalid LoginName Passed In");

            // Build SQL String
            string sql = "SELECT * FROM sys.server_role_members rm JOIN sys.server_principals Roles ON ";
            sql += "rm.role_principal_id = Roles.principal_id JOIN sys.server_principals Logins ON ";
            sql += "rm.member_principal_id = Logins.principal_id ";
            sql += String.Format("Where Logins.name = '{0}'", LoginName);
            DB db = DB.Create(credential.DBMS.WithoutDatabase());

            // Fetch the Data
            DBRetVal retVal = db.FillDataTable(sql);
            if (retVal.IsValid)
            {
                List<SQLServerRole> retList = new List<SQLServerRole>();                
                foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
                {
                    SQLServerRole role = (SQLServerRole)Enum.Parse(typeof(SQLServerRole), row["name"].ToString());
                    retList.Add(role);
                }
                Roles = retList.ToArray(); 
            }
            return retVal;
        }

        #endregion

        #region Login

        /// <summary>
        /// Easy Check to see if the passed in Login has SysAdmin rights (Full Control)
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="LoginName">existing login name to query sysadmin role for</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError LoginIsSysAdmin(IConnectDb credential, string LoginName, out bool IsAdmin)
        {
            IsAdmin = false;
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(LoginName))
                return DBError.Create("Invalid LoginName Passed In");      

            SQLServerRole[] roles = null;
            DBError dberror = LoginRoles(credential, LoginName, out roles);
            if (dberror.ErrorOccured)
                return dberror;

            IsAdmin = roles.Contains(SQLServerRole.sysadmin);            
            return dberror;
        }

        /// <summary>
        /// Use this to query if the LoginName already exists as an SQL Server User (Does not query db User ONLY server Users)
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="LoginName">Specify the Login Name to Query for (required)</param>
        /// <param name="bExists">true if login already exist as an SQL User in the system, false otherwise</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError LoginExists(IConnectDb credential, string LoginName, out bool bExists)
        {
            bExists = true;
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(LoginName))
                return DBError.Create("Invalid LoginName Passed In");   

            // Execute Query
            string sql = string.Format("SELECT [name] FROM sys.sql_logins WHERE [name] = '{0}'", LoginName);
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteScalar(sql);
            bExists = retVal.IsValid;
            return retVal;            
        }

        /// <summary>
        /// Use this to retrieve all the SQL Logins for the specified Server
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="ServerLogins">All SQL Server Logins on the specified server, or null if error occured</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError Logins(IConnectDb credential, out string[] ServerLogins)
        {
            ServerLogins = null;
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            string sql = "SELECT [name] FROM sys.sql_logins";
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.FillDataTable(sql);
            if (retVal.IsValid)
            {
                List<String> retList = new List<string>();
                foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
                         retList.Add(row["name"].ToString());
                ServerLogins = retList.ToArray();
            }
            return retVal;
        }

        /// <summary>
        /// Adds a Login to the SQL Server Instance
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="LoginName">LoginName (required)</param>
        /// <param name="LoginPassword">LoginPassword (required)</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError LoginAdd(IConnectDb credential, string LoginName, string LoginPassword)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(LoginName))
                return DBError.Create("Invalid LoginName Passed In");

            if (!ValidationConsts.Generic.IsValidPassword(LoginPassword))
                return DBError.Create("Invalid LoginPassword Passed In");         

            // Execute the Query
            string sql = String.Format("CREATE LOGIN [{0}] WITH PASSWORD = '{1}', CHECK_EXPIRATION = OFF, CHECK_POLICY = OFF", LoginName, LoginPassword);
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            return retVal;            
        }

        /// <summary>
        /// Drops a Login from the SQL Server Instance
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="LoginName">LoginName (required)</param>
        /// <param name="FallbackLoginName">Fallback Login used to change ownership to, in case error occurs because LoginName owns Databases (not required)</param>
        /// <returns>true if successful, false otherwise</returns>
        public static DBError LoginDrop(IConnectDb credential, string LoginName, string FallbackLoginName)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(LoginName))
                return DBError.Create("Invalid LoginName Passed In");

            // If User owns Databases, the Login Drop will fail, so
            // query for existing databases
            string[] ownedDBs = null;
            DBError dberror = DatabasesOwnedByLogin(credential, LoginName, out ownedDBs);

            // If Fallback Login was specified, use it to change the ownership on the Databases
            if (ValidationConsts.Generic.IsValidUserName(FallbackLoginName) && (ownedDBs != null))
            {
                foreach (string ownedDB in ownedDBs)
                {
                    dberror = DatabaseChangeOwnership(credential.DBMS.WithDatabase(ownedDB), FallbackLoginName);
                    if (dberror.ErrorOccured)
                        return dberror;
                }

                // Query Ownership again
                dberror = DatabasesOwnedByLogin(credential, LoginName, out ownedDBs);
            }

            // If ther are no Owned DBs, this should succeed
            if (ownedDBs == null)
            {
                DB db = DB.Create(credential.DBMS.WithoutDatabase());
                string sql = String.Format("DROP LOGIN [{0}]", LoginName);
                DBRetVal retVal = db.ExecuteNonQuery(sql);
                return retVal;
            }
            return dberror;
        }

        /// <summary>
        /// Changes the Password for the Login Name being passed in. The Login Name can be the same name as the User specified
        /// via Credential (if that is the case, you must update your credential object, when this function returns true)
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="LoginName">LoginName to change password for(can be the same/different than the User passed in thru credential) (required)</param>
        /// <param name="NewLoginPassword">NewLoginPassword (required)</param>
        /// <returns>true if successful * Password was changed for the passed in LoginName *, false otherwise</returns>
        public static DBError LoginChangePassword(IConnectDb credential, string LoginName, string NewLoginPassword)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if (!ValidationConsts.Generic.IsValidUserName(LoginName))
                return DBError.Create("Invalid LoginName Passed In");

            if (!ValidationConsts.Generic.IsValidPassword(NewLoginPassword))
                return DBError.Create("Invalid NewLoginPassword Passed In");  

            // Execute the Query and Return
            string sql = string.Format("ALTER LOGIN [{0}] WITH PASSWORD = '{1}'", LoginName, NewLoginPassword);
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            return retVal;
        }

        #endregion
    }
}
#endif