//------------------------------------------------------------------------------
// The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at  http://www.nopCommerce.com/License.aspx. 
// 
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. 
// See the License for the specific language governing rights and limitations under the License.
// 
// The Original Code is nopCommerce.
// The Initial Developer of the Original Code is NopSolutions.
// All Rights Reserved.
// 
// Contributor(s): _______. 
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration.Provider;
using System.Web.Configuration;
using System.Collections.Specialized;
using System.Configuration;
using System.Web.Hosting;

namespace NopSolutions.NopCommerce.DataAccess.Security
{
    /// <summary>
    /// Represents a banned IP address
    /// </summary>
    public abstract class DBBlacklistProvider : ProviderBase
    {
                #region Fields
        private static bool _initialized;
        private static Exception _initializeException;
        private static object _lock;
        private static DBBlacklistProvider _provider;
        private static DBBlacklistProviderCollection _providers;
        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of DBIpAddressProvider class
        /// </summary>
        static DBBlacklistProvider()
        {
            _lock = new object();
            _initialized = false;
            _initializeException = null;
        }
        #endregion

        #region Methods
        /// <summary>
        /// Gets an IP address by its ID
        /// </summary>
        /// <param name="bannedIpAddressID">IP Address unique identifier</param>
        /// <returns>IP address</returns>
        public abstract DBBannedIpAddress GetIpAddressByID(int bannedIpAddressID);

        /// <summary>
        /// Gets all IP addresses
        /// </summary>
        /// <returns>IP address collection</returns>
        public abstract DBBannedIpAddressCollection GetIpAddressAll();

        /// <summary>
        /// Inserts an IP address
        /// </summary>
        /// <param name="address">IP address</param>
        /// <param name="comment">Reason why the IP was banned</param>
        /// <param name="createdOn">When the record was inserted</param>
        /// <param name="updatedOn">When the record was last updated</param>
        /// <returns>IP address</returns>
        public abstract DBBannedIpAddress InsertBannedIpAddress(string address, string comment, DateTime createdOn, DateTime updatedOn);

        /// <summary>
        /// Updates an IP address
        /// </summary>
        /// <param name="bannedIpAddressID">IP address unique identifier</param>
        /// <param name="address">IP address</param>
        /// <param name="comment">Reason why the IP was banned</param>
        /// <param name="createdOn">When the record was last updated</param>
        /// <param name="updatedOn">When the record was last updated</param>
        /// <returns></returns>
        public abstract DBBannedIpAddress UpdateBannedIpAddress(int bannedIpAddressID, string address, string comment, DateTime createdOn, DateTime updatedOn);

        /// <summary>
        /// Deletes an IP address
        /// </summary>
        /// <param name="bannedIpAddressID">IP address unique identifier</param>
        public abstract void DeleteBannedIpAddress(int bannedIpAddressID);

        /// <summary>
        /// Gets an IP network by its ID
        /// </summary>
        /// <param name="bannedIpNetworkID">IP network unique identifier</param>
        /// <returns>IP network</returns>
        public abstract DBBannedIpNetwork GetIpNetworkByID(int bannedIpNetworkID);

        /// <summary>
        /// Gets all IP addresses
        /// </summary>
        /// <returns>IP address collection</returns>
        public abstract DBBannedIpNetworkCollection GetIpNetworkAll();

        /// <summary>
        /// Inserts an IP network
        /// </summary>
        /// <param name="startAddress">First IP address in the range</param>
        /// <param name="endAddress">Last IP address in the range</param>
        /// <param name="comment">Reason why the IP network was banned</param>
        /// <param name="ipException">Exceptions in the range</param>
        /// <param name="createdOn">When the record was inserted</param>
        /// <param name="updatedOn">When the record was last updated</param>
        /// <returns>IP network</returns>
        public abstract DBBannedIpNetwork InsertBannedIpNetwork(string startAddress, string endAddress, string comment, string ipException, DateTime createdOn, DateTime updatedOn);

        /// <summary>
        /// Updates an IP network
        /// </summary>
        /// <param name="bannedIpNetworkID">IP network unique identifier</param>
        /// <param name="startAddress">First IP address in the range</param>
        /// <param name="endAddress">Last IP address in the range</param>
        /// <param name="comment">Reason why the IP network was banned</param>
        /// <param name="ipException">Exceptions in the range</param>
        /// <param name="createdOn">When the record was inserted</param>
        /// <param name="updatedOn">When the record was last updated</param>
        /// <returns>IP network</returns>
        public abstract DBBannedIpNetwork UpdateBannedIpNetwork(int bannedIpNetworkID, string startAddress, string endAddress, string comment, string ipException, DateTime createdOn, DateTime updatedOn);

        /// <summary>
        /// Deletes an IP network
        /// </summary>
        /// <param name="bannedIpNetworkID">IP network unique identifier</param>
        public abstract void DeleteBannedIpNetwork(int bannedIpNetworkID);
        #endregion

        #region Utilities
        /// <summary>
        /// Returns the configuration section.
        /// </summary>
        /// <returns>The ConfigurationSection object.</returns>
        private static DBBlacklistProviderSection GetSection()
        {
            return (DBBlacklistProviderSection)ConfigurationManager.GetSection("nopDataProviders/BlacklistProvider");
        }

        /// <summary>
        /// Initializes the provider
        /// </summary>
        private static void Initialize()
        {
            if (_initialized)
            {
                if (_initializeException != null)
                {
                    throw _initializeException;
                }
            }
            else
            {
                if (_initializeException != null)
                {
                    throw _initializeException;
                }
                lock (_lock)
                {
                    if (_initialized)
                    {
                        if (_initializeException != null)
                        {
                            throw _initializeException;
                        }
                    }
                    else
                    {
                        try
                        {
                            DBBlacklistProviderSection section = GetSection();
                            if (((section.DefaultProvider == null) || (section.Providers == null)) || (section.Providers.Count < 1))
                            {
                                throw new ProviderException("Default provider not specified");
                            }
                            
                            _providers = new DBBlacklistProviderCollection();
                            if (HostingEnvironment.IsHosted)
                            {
                                ProvidersHelper.InstantiateProviders(section.Providers, _providers, typeof(DBBlacklistProvider));
                            }
                            else
                            {
                                foreach (ProviderSettings settings in section.Providers)
                                {
                                    Type c = Type.GetType(settings.Type, true, true);
                                    if (!typeof(DBBlacklistProvider).IsAssignableFrom(c))
                                    {
                                        throw new ArgumentException(string.Format("Provider must implement {0} type", new object[] { typeof(DBBlacklistProvider).ToString() }));
                                    }
                                    
                                    DBBlacklistProvider provider = (DBBlacklistProvider)Activator.CreateInstance(c);
                                    NameValueCollection parameters = settings.Parameters;
                                    NameValueCollection config = new NameValueCollection(parameters.Count, StringComparer.Ordinal);
                                    foreach (string str2 in parameters)
                                    {
                                        config[str2] = parameters[str2];
                                    }
                                    provider.Initialize(settings.Name, config);
                                    _providers.Add(provider);
                                }
                            }
                            _provider = _providers[section.DefaultProvider];
                            if (_provider == null)
                            {
                                throw new ConfigurationErrorsException(string.Format("Default provider not found. {0}. Line number: {1}", section.ElementInformation.Properties["defaultProvider"].Source, section.ElementInformation.Properties["defaultProvider"].LineNumber));
                            }
                            _providers.SetReadOnly();
                        }
                        catch (Exception exception)
                        {
                            _initializeException = exception;
                            throw;
                        }
                        _initialized = true;
                    }
                }
            }
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets a reference to the default provider for the application.
        /// </summary>
        public static DBBlacklistProvider Provider
        {
            get
            {
                Initialize();
                return _provider;
            }
        }
        /// <summary>
        /// Gets a collection of the providers for the application.
        /// </summary>
        public static DBBlacklistProviderCollection Providers
        {
            get
            {
                Initialize();
                return _providers;
            }
        }
        #endregion
    }
}
