//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Web;
using System.Web.Caching;
using System.Xml;
using System.Xml.Serialization;
using CommunityServer.Components;

namespace CommunityServer.Configuration {

    // *********************************************************************
    //  ForumConfiguration
    //
    /// <summary>
    /// Class used to represent the configuration data for the ASP.NET Forums
    /// </summary>
    /// 
    // ***********************************************************************/
    public class CSConfiguration {

		public static readonly string CacheKey = "CSConfiguration";

		#region private members
        Hashtable providers = new Hashtable();
		Hashtable extensions = new Hashtable();
        string defaultLanguage;
        string filesPath;
		bool disableBackgroundThreads = false;
		bool disableIndexing = false;
		bool disableEmail = false;
		short smtpServerConnectionLimit = -1;
		bool enableLatestVersionCheck = true;
        private AppLocation app = null;
        private string applicationOverride = null;
        private int threadCount = 2;
        private SystemType systemType = SystemType.Self;
        bool backwardsCompatiblePasswords = false;
		SSLSettings _ssl = SSLSettings.Ignore;
		private string[] _defaultRoles = new string[]{"Everyone", "Registered Users"};
		private string applicationKeyOverride = null;
		private WWWStatus _wwwStatus = WWWStatus.Remove;
		private bool enableProductListing = true;
		private bool enableUsersOnline = true;
		private string announcementRssUrl = String.Empty;
		private ArrayList filterLanguages = new ArrayList();
		private ArrayList editors = null;
		private string proxyHost = string.Empty;
		private int proxyPort = 80;
		private string proxyUsername = string.Empty;
		private string proxyPassword = string.Empty;
		private string proxyBypassList = string.Empty;
    	private bool proxyBypassOnLocal = true;

        private RolesConfiguration roleConfiguration= null;
		private int cacheFactor = 5;
		private XmlDocument XmlDoc = null;
		private bool _enableVirtualization = false;
		#endregion

		#region cnstr
		public CSConfiguration(XmlDocument doc)
		{
			XmlDoc = doc;
			LoadValuesFromConfigurationXml();
		}
		#endregion

		#region GetXML

		/// <summary>
		/// Enables reading of the configuration file's XML without reloading the file
		/// </summary>
		/// <param name="nodePath"></param>
		/// <returns></returns>
		public XmlNode GetConfigSection(string nodePath)
		{
			return XmlDoc.SelectSingleNode(nodePath);
		}

		#endregion

		#region GetConfig
        public static CSConfiguration GetConfig() 
		{
			CSConfiguration config = CSCache.Get(CacheKey) as CSConfiguration;
			if(config == null)
			{
				string path = null;
                HttpContext context = HttpContext.Current;
				if(context != null)
					path = context.Server.MapPath("~/communityserver.config");
				else
					path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,  "communityserver.config");

				XmlDocument doc = new XmlDocument();
				doc.Load(path);
				config = new CSConfiguration(doc);
				CSCache.Max(CacheKey,config,new CacheDependency(path));

				CSCache.ReSetFactor(config.CacheFactor);

                //CSEvents.PostConfigurationInitialized(config);
			}
			return config;
            
        }

        #endregion

        // *********************************************************************
        //  LoadValuesFromConfigurationXml
        //
        /// <summary>
        /// Loads the forums configuration values.
        /// </summary>
        /// 
        // ***********************************************************************/
		internal void LoadValuesFromConfigurationXml()
        {
        	XmlNode node = GetConfigSection("CommunityServer/Core");

        	XmlAttributeCollection attributeCollection = node.Attributes;


        	// Get the default language
        	//

        	XmlAttribute att = attributeCollection["defaultLanguage"];
        	if (att != null)
        		defaultLanguage = att.Value;
        	else
        		defaultLanguage = "en-US";

        	att = attributeCollection["enableProductListing"];
        	if (att != null)
        		enableProductListing = bool.Parse(att.Value);

        	att = attributeCollection["enableUsersOnline"];
        	if (att != null)
        		enableUsersOnline = bool.Parse(att.Value);

        	att = attributeCollection["announcementRssUrl"];
        	if (att != null)
        		announcementRssUrl = att.Value;

        	//			att = attributeCollection["filesPath"];
        	//			if(att != null)
        	//				filesPath = att.Value;
        	//			else

        	//Changing this value is not supported in CS 1.x
        	filesPath = "/";

        	att = attributeCollection["applicationKeyOverride"];
        	if (att != null)
        		applicationKeyOverride = att.Value;

        	att = attributeCollection["disableThreading"];
        	if (att != null)
        		disableBackgroundThreads = bool.Parse(att.Value);

        	att = attributeCollection["disableIndexing"];
        	if (att != null)
        		disableIndexing = bool.Parse(att.Value);


        	att = attributeCollection["cacheFactor"];
        	if (att != null)
        		cacheFactor = Int32.Parse(att.Value);
        	else
        		cacheFactor = 5;

        	att = attributeCollection["disableEmail"];
        	if (att != null)
        		disableEmail = bool.Parse(att.Value);


        	att = attributeCollection["smtpServerConnectionLimit"];
        	if (att != null)
        		smtpServerConnectionLimit = short.Parse(att.Value);
        	else
        		smtpServerConnectionLimit = -1;

        	att = attributeCollection["enableLatestVersionCheck"];
        	if (att != null)
        		enableLatestVersionCheck = bool.Parse(att.Value);

        	att = attributeCollection["backwardsCompatiblePasswords"];
        	if (att != null)
        		backwardsCompatiblePasswords = bool.Parse(att.Value);

        	att = attributeCollection["enableVirtualization"];
        	if (att != null)
        		_enableVirtualization = bool.Parse(att.Value);


        	att = attributeCollection["applicationOverride"];
        	if (att != null)
        		applicationOverride = att.Value;
        	else
        		applicationOverride = null;

        	att = attributeCollection["systemType"];
        	if (att != null)
        		systemType = (SystemType)Enum.Parse(typeof(SystemType), attributeCollection["systemType"].Value);
        	else
        		systemType = SystemType.Self;

        	att = attributeCollection["wwwStatus"];
        	if (att != null)
        		_wwwStatus = (WWWStatus)Enum.Parse(typeof(WWWStatus), attributeCollection["wwwStatus"].Value);


        	att = attributeCollection["ssl"];
        	if (att != null)
        		_ssl = (SSLSettings)Enum.Parse(typeof(SSLSettings), att.Value, true);

        	if (_ssl == SSLSettings.Ignore && att == null)
        	{
        		att = attributeCollection["requireSSL"];
        		if (att != null && att.Value == "true")
        			_ssl = SSLSettings.Password;
        	}

        	att = attributeCollection["proxyHost"];
        	if (att != null)
        		proxyHost = att.Value;

        	att = attributeCollection["proxyPort"];
        	if (att != null)
        		if(att.Value != string.Empty)
	        		proxyPort = int.Parse(att.Value);

        	att = attributeCollection["proxyUsername"];
        	if (att != null)
        		proxyUsername = att.Value;

        	att = attributeCollection["proxyPassword"];
        	if (att != null)
        		proxyPassword = att.Value;

        	att = attributeCollection["proxyBypassList"];
        	if (att != null)
        		proxyBypassList = att.Value;

			att = attributeCollection["proxyBypassOnLocal"];
			if (att != null)
				if(att.Value != string.Empty)
					proxyBypassOnLocal = bool.Parse(att.Value);

        	XmlAttribute roles = attributeCollection["defaultRoles"];
        	if (roles != null)
        	{
        		_defaultRoles = roles.Value.Split(';');
        	}

        	// Read child nodes
        	//
        	foreach (XmlNode child in node.ChildNodes)
        	{

        		if (child.Name == "providers")
        			GetProviders(child, providers);

        		if (child.Name == "appLocation")
        			GetAppLocation(child);

        		if (child.Name == "extensionModules")
        			GetProviders(child, extensions);

        		if (child.Name == "roleConfiguration")
        			GetRoleConfiguration(child);

        		if (child.Name == "filterLanguages")
        			GetFilterLanguages(child);

        		if (child.Name == "editors")
        			GetEditors(child);
        	}

        	//if we do not have an application, create the default one
        	if (app == null)
        	{
        		app = AppLocation.Default();
        	}

        	if (roleConfiguration == null)
        	{
        		roleConfiguration = new RolesConfiguration();
        	}
        }

        // *********************************************************************
        //  GetRoleConfiguration
        //
        /// <summary>
        /// Internal class used to populate default role changes.
        /// </summary>
        /// <param name="node">XmlNode of the configurations.</param>
        /// 
        // ***********************************************************************/
        internal void GetRoleConfiguration(XmlNode node)
        {
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof (RolesConfiguration));
                roleConfiguration = serializer.Deserialize(new XmlNodeReader(node)) as RolesConfiguration;
            }
            catch
            {
                //Should we let exception go?
                roleConfiguration = new RolesConfiguration();
            }
        }

		internal void GetFilterLanguages(XmlNode node)
		{
			filterLanguages = new ArrayList();

			foreach(XmlNode child in node.ChildNodes)
			{
				if(child.Name == "filterLanguage")
				{
					XmlAttributeCollection csAtt = child.Attributes;
					if(csAtt != null)
					{
						if (csAtt["enabled"] == null || bool.Parse(csAtt["enabled"].Value))
							filterLanguages.Add(new FilterLanguage(csAtt["key"].Value, csAtt["name"].Value));
					}
				}
			}
		}

		internal void GetEditors(XmlNode node)
		{
			editors = new ArrayList();
			foreach(XmlNode child in node.ChildNodes)
			{
				if (child.Name == "editor")
				{
					XmlAttributeCollection csAtt = child.Attributes;
					if (csAtt != null)
					{
						editors.Add(new SelectableEditor(csAtt["name"].Value, csAtt["skinName"].Value, (csAtt["default"] != null && bool.Parse(csAtt["default"].Value))));
					}
				}
			}
		}

        // *********************************************************************
        //  GetProviders
        //
        /// <summary>
        /// Internal class used to populate the available providers.
        /// </summary>
        /// <param name="node">XmlNode of the providers to add/remove/clear.</param>
        /// 
        // ***********************************************************************/
        internal void GetProviders(XmlNode node, Hashtable table) {

            foreach (XmlNode provider in node.ChildNodes) {

                switch (provider.Name) {
                    case "add" :
                        table.Add(provider.Attributes["name"].Value, new Provider(provider.Attributes) );
                        break;

                    case "remove" :
                        table.Remove(provider.Attributes["name"].Value);
                        break;

                    case "clear" :
                        table.Clear();
                        break;

                }

            }

        }

        internal void GetAppLocation(XmlNode node)
        {
            app = AppLocation.Create(node);
        }

		private bool defaultLanguageHasBeenValidated = false;
        // Properties
        //
        public string DefaultLanguage 
		{ 
			get
			{
				if(!defaultLanguageHasBeenValidated)
					defaultLanguage = ResourceManager.GetSupportedLanguage(defaultLanguage, "en-US");
					
				return defaultLanguage;
			} 
		}
        public string FilesPath { get { return filesPath; } }
        public Hashtable Providers { get { return providers; } } 
		public Hashtable Extensions { get { return extensions; } } 
		public bool IsBackgroundThreadingDisabled { get { return disableBackgroundThreads; } }
		public bool IsIndexingDisabled { get { return disableIndexing; } }
        public RolesConfiguration RolesConfiguration{get { return roleConfiguration;} }
        public string ApplicationOverride {get {return applicationOverride;} }
        public int QueuedThreads { get { return threadCount; }}
		public int CacheFactor { get  {  return cacheFactor;  } }
		public SSLSettings SSL { get {return _ssl;}}
		public WWWStatus WWWStatus { get { return _wwwStatus;}}
		public string ProxyHost { get { return proxyHost; } }
		public int ProxyPort { get { return proxyPort; } }
		public string ProxyUsername { get { return proxyUsername; } }
		public string ProxyPassword { get { return proxyPassword; } }
		public string ProxyBypassList { get { return proxyBypassList; } }
		public bool ProxyBypassOnLocal { get { return proxyBypassOnLocal; } }
		public bool EnableVirtualization{ get {return _enableVirtualization;}}
		public bool EnableProductListing{ get {return enableProductListing; }}
		public bool EnableUsersOnline{ get {return enableUsersOnline; }}
		public string AnnouncementRssUrl{ get { return announcementRssUrl; }}
		public string ApplicationKeyOverride
		{
			get{ return applicationKeyOverride;}
		}

		public ArrayList FilterLanguages { get { return filterLanguages; }}

		public FilterLanguage DefaultFilterLanguage
		{
			get
			{
				return GetFilterLanguage(this.DefaultLanguage);
			}
		}

		public FilterLanguage GetFilterLanguage(string key)
		{
			FilterLanguage fl = FindFilterLanguage(key);
			if (fl != null)
				return fl;

			if (key.IndexOf("-") > -1)
				fl = FindFilterLanguage(key.Substring(0, key.IndexOf("-")));
			else
				fl = FindFilterLanguage(key + "-" + key);

			return fl;
		}

		private FilterLanguage FindFilterLanguage(string key)
		{
			foreach (FilterLanguage fl in FilterLanguages)
			{
				if (fl.Key == key)
					return fl;
			}

			return null;
		}

		public ArrayList Editors
		{
			get { return editors; }
		}

		public SelectableEditor DefaultEditor
		{
			get 
			{
				foreach (SelectableEditor editor in Editors)
				{
					if (editor.IsDefault)
						return editor;
				}

				if (Editors.Count > 0)
					return (SelectableEditor) Editors[0];

				return null;
			}
		}

        public AppLocation AppLocation
        {
            get{return app;}
        }

		public bool IsEmailDisabled { 
			get { 
				return disableEmail;
			}
		}

		public short SmtpServerConnectionLimit {
			get {
				return smtpServerConnectionLimit; 
			}
		}

		public bool EnableLatestVersionCheck {
			get {
				return enableLatestVersionCheck;
			}
		}

        public bool BackwardsCompatiblePasswords 
        {
            get 
            {
                return backwardsCompatiblePasswords;
            }
        }

		public string[] DefaultRoles
		{
			get{return _defaultRoles;}
		}

        

        public SystemType SystemType {get{ return systemType;}}
	}

	public class Provider 
	{
        string name;
		ExtensionType extensionType;
        string providerType;
        NameValueCollection providerAttributes = new NameValueCollection();

		public Provider (XmlAttributeCollection attributes) 
		{

            // Set the name of the provider
            //
            name = attributes["name"].Value;

            if (attributes["extensionType"] != null)
            {
                // Set the extension type
                //
                try
                {
                    extensionType = (ExtensionType)Enum.Parse(typeof(ExtensionType), attributes["extensionType"].Value, true);
                }
                catch
                {
                    // Occassionally get an exception on parsing the extensiontype, so set it to Unknown
                    extensionType = ExtensionType.Unknown;
                }
            }
            // Set the type of the provider
            //
            providerType = attributes["type"].Value;

            // Store all the attributes in the attributes bucket
            //
			foreach (XmlAttribute attribute in attributes) 
			{
                if ( (attribute.Name != "name") && (attribute.Name != "type") )
                    providerAttributes.Add(attribute.Name, attribute.Value);
            }
        }

        public string Name {
            get {
                return name;
            }
        }

		public ExtensionType ExtensionType
		{
			get { return extensionType; }
		}

        public string Type {
            get {
                return providerType;
            }
        }

        public NameValueCollection Attributes {
            get {
                return providerAttributes;
            }
        }

    }
}
