//------------------------------------------------------------------------------
// 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.Data;
using System.Data.Common;
using System.Globalization;
using System.Text;
using System.Configuration;
using System.Configuration.Provider;
using System.Web.Hosting;
using System.Web.Configuration;
using System.Collections.Specialized;

namespace NopSolutions.NopCommerce.DataAccess.Templates
{
    /// <summary>
    /// Acts as a base class for deriving custom template provider
    /// </summary>
    public abstract class DBTemplateProvider : ProviderBase
    {
        #region Fields
        private static bool s_Initialized;
        private static Exception s_InitializeException;
        private static object s_lock;
        private static DBTemplateProvider s_Provider;
        private static DBTemplateProviderCollection s_Providers;
        #endregion

        #region Ctor
        /// <summary>
        /// Initializes a new instance of the DBTemplateProvider class.
        /// </summary>
        static DBTemplateProvider()
        {
            s_lock = new object();
            s_Initialized = false;
            s_InitializeException = null;
        }
        #endregion

        #region Methods

        /// <summary>
        /// Deletes a category template
        /// </summary>
        /// <param name="CategoryTemplateID">Category template identifier</param>
        public abstract void DeleteCategoryTemplate(int CategoryTemplateID);

        /// <summary>
        /// Gets all category templates
        /// </summary>
        /// <returns>Category template collection</returns>
        public abstract DBCategoryTemplateCollection GetAllCategoryTemplates();

        /// <summary>
        /// Gets a category template
        /// </summary>
        /// <param name="CategoryTemplateID">Category template identifier</param>
        /// <returns>A category template</returns>
        public abstract DBCategoryTemplate GetCategoryTemplateByID(int CategoryTemplateID);

        /// <summary>
        /// Inserts a category template
        /// </summary>
        /// <param name="Name">The name</param>
        /// <param name="TemplatePath">The template path</param>
        /// <param name="DisplayOrder">The display order</param>
        /// <param name="CreatedOn">The date and time of instance creation</param>
        /// <param name="UpdatedOn">The date and time of instance update</param>
        /// <returns>A category template</returns>
        public abstract DBCategoryTemplate InsertCategoryTemplate(string Name, string TemplatePath,
            int DisplayOrder, DateTime CreatedOn, DateTime UpdatedOn);

        /// <summary>
        /// Updates the category template
        /// </summary>
        /// <param name="CategoryTemplateID">Category template identifier</param>
        /// <param name="Name">The name</param>
        /// <param name="TemplatePath">The template path</param>
        /// <param name="DisplayOrder">The display order</param>
        /// <param name="CreatedOn">The date and time of instance creation</param>
        /// <param name="UpdatedOn">The date and time of instance update</param>
        /// <returns>A category template</returns>
        public abstract DBCategoryTemplate UpdateCategoryTemplate(int CategoryTemplateID, string Name, string TemplatePath,
            int DisplayOrder, DateTime CreatedOn, DateTime UpdatedOn);

        /// <summary>
        /// Deletes a manufacturer template
        /// </summary>
        /// <param name="ManufacturerTemplateID">Manufacturer template identifier</param>
        public abstract void DeleteManufacturerTemplate(int ManufacturerTemplateID);

        /// <summary>
        /// Gets all manufacturer templates
        /// </summary>
        /// <returns>Manufacturer template collection</returns>
        public abstract DBManufacturerTemplateCollection GetAllManufacturerTemplates();

        /// <summary>
        /// Gets a manufacturer template
        /// </summary>
        /// <param name="ManufacturerTemplateID">Manufacturer template identifier</param>
        /// <returns>Manufacturer template</returns>
        public abstract DBManufacturerTemplate GetManufacturerTemplateByID(int ManufacturerTemplateID);

        /// <summary>
        /// Inserts a manufacturer template
        /// </summary>
        /// <param name="Name">The manufacturer template identifier</param>
        /// <param name="TemplatePath">The template path</param>
        /// <param name="DisplayOrder">The display order</param>
        /// <param name="CreatedOn">The date and time of instance creation</param>
        /// <param name="UpdatedOn">The date and time of instance update</param>
        /// <returns>Manufacturer template</returns>
        public abstract DBManufacturerTemplate InsertManufacturerTemplate(string Name, string TemplatePath,
            int DisplayOrder, DateTime CreatedOn, DateTime UpdatedOn);

        /// <summary>
        /// Updates the manufacturer template
        /// </summary>
        /// <param name="ManufacturerTemplateID">Manufacturer template identifer</param>
        /// <param name="Name">The manufacturer template identifier</param>
        /// <param name="TemplatePath">The template path</param>
        /// <param name="DisplayOrder">The display order</param>
        /// <param name="CreatedOn">The date and time of instance creation</param>
        /// <param name="UpdatedOn">The date and time of instance update</param>
        /// <returns>Manufacturer template</returns>
        public abstract DBManufacturerTemplate UpdateManufacturerTemplate(int ManufacturerTemplateID, string Name, string TemplatePath,
            int DisplayOrder, DateTime CreatedOn, DateTime UpdatedOn);

        /// <summary>
        /// Deletes a product template
        /// </summary>
        /// <param name="ProductTemplateID">Product template identifier</param>
        public abstract void DeleteProductTemplate(int ProductTemplateID);

        /// <summary>
        /// Gets all product templates
        /// </summary>
        /// <returns>Product template collection</returns>
        public abstract DBProductTemplateCollection GetAllProductTemplates();

        /// <summary>
        /// Gets a product template
        /// </summary>
        /// <param name="ProductTemplateID">Product template identifier</param>
        /// <returns>Product template</returns>
        public abstract DBProductTemplate GetProductTemplateByID(int ProductTemplateID);

        /// <summary>
        /// Inserts a product template
        /// </summary>
        /// <param name="Name">The name</param>
        /// <param name="TemplatePath">The template path</param>
        /// <param name="DisplayOrder">The display order</param>
        /// <param name="CreatedOn">The date and time of instance creation</param>
        /// <param name="UpdatedOn">The date and time of instance update</param>
        /// <returns>Product template</returns>
        public abstract DBProductTemplate InsertProductTemplate(string Name, string TemplatePath,
            int DisplayOrder, DateTime CreatedOn, DateTime UpdatedOn);

        /// <summary>
        /// Updates the product template
        /// </summary>
        /// <param name="ProductTemplateID">The product template identifier</param>
        /// <param name="Name">The name</param>
        /// <param name="TemplatePath">The template path</param>
        /// <param name="DisplayOrder">The display order</param>
        /// <param name="CreatedOn">The date and time of instance creation</param>
        /// <param name="UpdatedOn">The date and time of instance update</param>
        /// <returns>Product template</returns>
        public abstract DBProductTemplate UpdateProductTemplate(int ProductTemplateID, string Name, string TemplatePath,
            int DisplayOrder, DateTime CreatedOn, DateTime UpdatedOn);
        #endregion

        #region Utilities
        /// <summary>
        /// Returns the configuration section.
        /// </summary>
        /// <returns>The ConfigurationSection object.</returns>
        private static DBTemplateProviderSection GetSection()
        {
            return (DBTemplateProviderSection)ConfigurationManager.GetSection("nopDataProviders/TemplateProvider");
        }
        private static void Initialize()
        {
            if (s_Initialized)
            {
                if (s_InitializeException != null)
                {
                    throw s_InitializeException;
                }
            }
            else
            {
                if (s_InitializeException != null)
                {
                    throw s_InitializeException;
                }
                lock (s_lock)
                {
                    if (s_Initialized)
                    {
                        if (s_InitializeException != null)
                        {
                            throw s_InitializeException;
                        }
                    }
                    else
                    {
                        try
                        {
                            DBTemplateProviderSection section = GetSection();
                            if (((section.DefaultProvider == null) || (section.Providers == null)) || (section.Providers.Count < 1))
                            {
                                throw new ProviderException("Default provider not specified");
                            }
                            s_Providers = new DBTemplateProviderCollection();
                            if (HostingEnvironment.IsHosted)
                            {
                                ProvidersHelper.InstantiateProviders(section.Providers, s_Providers, typeof(DBTemplateProvider));
                            }
                            else
                            {
                                foreach (ProviderSettings settings in section.Providers)
                                {
                                    Type c = Type.GetType(settings.Type, true, true);
                                    if (!typeof(DBTemplateProvider).IsAssignableFrom(c))
                                    {
                                        throw new ArgumentException(string.Format("Provider must implement {0} type", new object[] { typeof(DBTemplateProvider).ToString() }));
                                    }
                                    DBTemplateProvider provider = (DBTemplateProvider)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);
                                    s_Providers.Add(provider);
                                }
                            }
                            s_Provider = s_Providers[section.DefaultProvider];
                            if (s_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));
                            }
                            s_Providers.SetReadOnly();
                        }
                        catch (Exception exception)
                        {
                            s_InitializeException = exception;
                            throw;
                        }
                        s_Initialized = true;
                    }
                }
            }
        }

        #endregion

        #region Properties
        /// <summary>
        /// Gets a reference to the default provider for the application.
        /// </summary>
        public static DBTemplateProvider Provider
        {
            get
            {
                Initialize();
                return s_Provider;
            }
        }
        /// <summary>
        /// Gets a collection of the providers for the application.
        /// </summary>
        public static DBTemplateProviderCollection Providers
        {
            get
            {
                Initialize();
                return s_Providers;
            }
        }

        #endregion
    }
}
