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

using System.Collections;
using System.Collections.Specialized;
using System.Web.Caching;
using System.Xml;
using CommunityServer.Configuration;

namespace CommunityServer.Components 
{

    /// <summary>
    /// Public class to load all language XML files into cache for quick access.
    /// </summary>
    public class ResourceManager {

        enum ResourceManagerType {
            String,
            ErrorMessage,
			Template
        }

        public static NameValueCollection GetSupportedLanguages () {
            CSContext csContext = CSContext.Current;
            
            string cacheKey = "Forums-SupportedLanguages";

            NameValueCollection supportedLanguages = CSCache.Get(cacheKey) as NameValueCollection;
            if (supportedLanguages == null) {
                string filePath = csContext.MapPath("~/Languages/languages.xml");
            	CacheDependency dp = new CacheDependency(filePath);
                supportedLanguages = new NameValueCollection();

            	XmlDocument d = new XmlDocument();
                d.Load( filePath );

                foreach (XmlNode n in d.SelectSingleNode("root").ChildNodes) {
                    if (n.NodeType != XmlNodeType.Comment) {
                        supportedLanguages.Add(n.Attributes["key"].Value, n.Attributes["name"].Value);
                    }
                }

                CSCache.Max(cacheKey, supportedLanguages, dp);
            }

            return supportedLanguages;
        }

		public static NameValueCollection GetLanguageCharsets()
		{
			CSContext csContext = CSContext.Current;

			string cacheKey = "LanguageCharsets";

			NameValueCollection languageCharsets = CSCache.Get(cacheKey) as NameValueCollection;
			if (languageCharsets == null)
			{
				string filePath = csContext.MapPath("~/Languages/languages.xml");
				CacheDependency dp = new CacheDependency(filePath);
				languageCharsets = new NameValueCollection();

				XmlDocument d = new XmlDocument();
				d.Load(filePath);

				foreach (XmlNode n in d.SelectSingleNode("root").ChildNodes)
				{
					if (n.NodeType != XmlNodeType.Comment)
					{
						if (n.Attributes["emailCharset"] == null)
							continue;
						string codepage = n.Attributes["emailCharset"].Value;
						if (n.Attributes["emailSubjectCharset"] != null)
							codepage += "," + n.Attributes["emailSubjectCharset"].Value;
						
						languageCharsets.Add(n.Attributes["key"].Value, codepage);
					}
				}

				CSCache.Max(cacheKey, languageCharsets, dp);
			}

			return languageCharsets;
		}

		/// <summary>
		/// Checks to see if the current language key is in the supported languages, if not it returns the default language
		/// </summary>
		/// <param name="language">The language key to validate</param>
		/// <returns>A valid language key</returns>
		public static string GetSupportedLanguage(string language)
		{
			return GetSupportedLanguage(language, CSContext.Current.Config.DefaultLanguage);
		}

		/// <summary>
		/// Checks to see if the current language key is in the supported languages, if not it returns the default language
		/// </summary>
		/// <param name="language">The language key to validate</param>
		/// <param name="languageDefault">the language to return if the specified language is not found
		/// </param>
		/// <returns>A valid language key</returns>
		public static string GetSupportedLanguage(string language, string languageDefault)
		{
			NameValueCollection supportedLanguages = GetSupportedLanguages();
			string supportedLanguage = supportedLanguages[language];
			if(!Globals.IsNullorEmpty(supportedLanguage))
				return language;
			else
				return languageDefault;
		}
		

        public static string GetString(string name) {

           return GetString(name, false);
        }

        public static string GetString(string name, bool defaultOnly)
        {
            return GetString(name,"Resources.xml",defaultOnly);
        }

        public static string GetString(string name, string fileName)
        {
            return GetString(name,fileName,false);
        }

        public static string GetString(string name, string fileName, bool defaultOnly) 
        {

        	Hashtable resources = null;
			CSContext cSContext = CSContext.Current;
			string userLanguage = cSContext.User.Profile.Language;
            
            if (fileName != null && fileName != "")
                resources = GetResource (ResourceManagerType.String,userLanguage,fileName,defaultOnly);
            else
                resources = GetResource (ResourceManagerType.String,userLanguage,"Resources.xml",defaultOnly);

            string text = resources[name] as string;

			//try the standard file if we passed a file that didnt have the key we were looking for
			if (text == null && fileName != null && fileName != "") 
			{
				resources = GetResource (ResourceManagerType.String,userLanguage,"Resources.xml",false);

				text = resources[name] as string;
			}

			if (text == null) 
			{
            #if DEBUG
                            text = string.Format("<strong><FONT color=#ff0000 size=5>Missing Resource: {0}</FONT></strong>",name);
							EventLogs.Debug(string.Format("Missing Resource: {0} Page: {1}",name, cSContext.RawUrl), "Resource Manager", 0, cSContext.SettingsID) ;
            #else
                            text = string.Empty;
            #endif
            }
            return text;
        }    

        #region GetMessage
        public static Message GetMessage (CSExceptionType exceptionType) 
        {

            Hashtable resources = GetResource (ResourceManagerType.ErrorMessage, CSContext.Current.User.Profile.Language, "Messages.xml",false);

            if (resources[(int) exceptionType] == null) {
                // LN 6/9/04: Changed to throw a forums exception 
                throw new CSException(CSExceptionType.ResourceNotFound, "Value not found in Messages.xml for: " + exceptionType);
            }

            return (Message) resources[(int) exceptionType];
        }
        #endregion

		public static ArrayList GetTemplates(TemplateType type)
		{
			Hashtable resources = GetResource(ResourceManagerType.Template, CSContext.Current.User.Profile.Language, "Templates.xml",false);

			ArrayList templates = new ArrayList();
			foreach (object key in resources.Keys)
			{
				Template template = resources[key] as Template;
				if ((template != null) && (template.Type == type))
					templates.Add(template);
			}

			templates.Sort();

			return templates;
		}

		public static Template GetTemplate(int templateID)
		{
			Hashtable resources = GetResource(ResourceManagerType.Template, CSContext.Current.User.Profile.Language, "Templates.xml",false);

			if (resources[templateID] == null)
			{
				throw new CSException(CSExceptionType.ResourceNotFound, "Value not found in Templates.xml for: " + templateID);
			}

			return (Template)resources[templateID];
		}

        private static Hashtable GetResource (ResourceManagerType resourceType, string userLanguage, string fileName, bool defaultOnly) {
            
            
            string defaultLanguage = CSConfiguration.GetConfig().DefaultLanguage;
            string cacheKey = resourceType.ToString() + defaultLanguage + userLanguage + fileName;

            // Ensure the user has a language set
            //
            if (Globals.IsNullorEmpty(userLanguage) || defaultOnly )
                userLanguage = defaultLanguage;

            // Attempt to get the resources from the Cache
            //
            Hashtable resources = CSCache.Get(cacheKey) as Hashtable;

            if (resources == null) 
            {
                resources = new Hashtable();

                // First load the English resouce, changed from loading the default language
				// since the userLanguage is set to the defaultLanguage if the userLanguage
				// is unassigned. We load the english language always just to ensure we have
				// a resource loaded just incase the userLanguage doesn't have a translated
				// string for this English resource.
                //
                resources = LoadResource(resourceType, resources, "en-US", cacheKey,fileName);

                // If the user language is different load it
                //
                if ("en-US" != userLanguage)
                    resources= LoadResource(resourceType, resources, userLanguage, cacheKey,fileName);

            }

            return resources;
        }

		private static Hashtable LoadResource (ResourceManagerType resourceType, Hashtable target, string language, string cacheKey, string fileName) {
			string filePath = CSContext.Current.PhysicalPath("Languages\\" + language + "\\" + fileName);

//			switch (resourceType) {
//				case ResourceManagerType.ErrorMessage:
//					filePath = string.Format(filePath, "Messages.xml");
//					break;
//
//				default:
//					filePath = string.Format(filePath, "Resources.xml");
//					break;
//			}

			CacheDependency dp = new CacheDependency(filePath);

			XmlDocument d = new XmlDocument();
			try {
				d.Load( filePath );
			} catch {
				return target;
			}

			foreach (XmlNode n in d.SelectSingleNode("root").ChildNodes) {
				if (n.NodeType != XmlNodeType.Comment) {
					switch (resourceType) {
						case ResourceManagerType.ErrorMessage:
					        Message m = new Message(n);
							target[m.MessageID] = m;
							break;

						case ResourceManagerType.String:
							if (target[n.Attributes["name"].Value] == null)
								target.Add(n.Attributes["name"].Value, n.InnerText);
							else
								target[n.Attributes["name"].Value] = n.InnerText;
							break;

						case ResourceManagerType.Template:
							Template t = new Template(n);
							target[t.TemplateID] = t;
							break;
					}
				}
			}

			// Create a new cache dependency and set it to never expire
			// unless the underlying file changes
			//
			// 7/26/2004 Terry Denham
			// We should only keep the default language cached forever, not every language.
			//DateTime cacheUntil;
			if( language == CSConfiguration.GetConfig().DefaultLanguage ) {
                CSCache.Max(cacheKey,target,dp);
			}
			else {
                CSCache.Insert(cacheKey,target,dp,CSCache.MinuteFactor * 5);
			}

            return target;

        }

    }
}
