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

using System;
using System.Collections;
using System.Web.Caching;
using CommunityServer.Components;
using CommunityServer.Configuration;

namespace CommunityServer.Spam
{
	/// <summary>
	/// Summary description for SpamRules.
	/// </summary>
	public class SpamRules
	{
		private static readonly string RulesCacheKey = "SpamRules";
		private static readonly object RulesSync = new object();
		private static readonly string SelectedRulesCacheKey = "SelectedSpamRules";
		private static readonly object SelectedRulesSync = new object();

		public SpamRules()
		{
		}

		public static ArrayList SearchForRules()
		{
			ArrayList rules = CSCache.Get(RulesCacheKey) as ArrayList;
			if(rules == null)
			{
				lock(RulesSync)
				{
					rules = CSCache.Get(RulesCacheKey) as ArrayList;
					if(rules == null)
					{
						RuleLoader loader = new RuleLoader();
						rules = loader.LoadRules();
					}
					CacheDependency dep = new CacheDependency(null, new string[]{CSConfiguration.CacheKey});
					CSCache.Max(RulesCacheKey, rules, dep);
				}
			}

			return rules;
		}

		public static ArrayList GetSelectedRules()
		{
			ArrayList rules = CSCache.Get(SelectedRulesCacheKey) as ArrayList;
			if (rules == null)
			{
				lock(SelectedRulesSync)
				{
					rules = CSCache.Get(SelectedRulesCacheKey) as ArrayList;
					if (rules == null)
					{
						ArrayList selectedRules = new ArrayList();
						string[] RuleNames = SpamConfiguration.Instance().Rules;
						if (RuleNames != null)
						{
							foreach (string name in RuleNames)
							{
								try
								{
									Type type = Type.GetType(name);
									SpamRule rule = Activator.CreateInstance(type) as SpamRule;
									selectedRules.Add(rule);
								}
								catch
								{
									// Ignore
								}
							}
						}
						rules = selectedRules;
					}
					CacheDependency dep = new CacheDependency(null, new string[]{CSConfiguration.CacheKey});
					CSCache.Max(SelectedRulesCacheKey, rules, dep);
				}
			}

			return rules;
		}

		public static SpamRule GetRule(Guid ruleID)
		{
			ArrayList rules = SearchForRules();
			foreach (SpamRule rule in rules)
			{
				if (rule.RuleID == ruleID)
					return rule;
			}
			return null;
		}


		public static void SaveRules(ArrayList rules)
		{
			SaveRules(rules, SpamConfiguration.Instance(false));
		}

		public static void SaveRules(ArrayList rules, SpamConfiguration config)
		{
			// Reset the Cache
			lock(SelectedRulesSync)
			{
				CSCache.Remove(SelectedRulesCacheKey);
				CacheDependency dep = new CacheDependency(null, new string[]{CSConfiguration.CacheKey});
				CSCache.Max(SelectedRulesCacheKey, rules, dep);
			}

			// Save to config
			string[] RuleNames = new string[rules.Count];
			for (int i = 0; i < rules.Count; i++)
			{
				RuleNames[i] = ((SpamRule)rules[i]).TypeName;
			}

			config.Rules = RuleNames;
			config.Save();
		}

		public static Hashtable GetRuleSettings(Guid ruleID)
		{
			Hashtable ruleSettings = new Hashtable();
			RuleSetting[] allSettings = SpamConfiguration.Instance().RuleSettings;

			if (allSettings != null)
			{
				foreach (RuleSetting setting in allSettings)
				{
					if (setting.RuleID == ruleID)
					{
						ruleSettings.Add(setting.Key, setting);
					}
				}
			}
			return ruleSettings;
		}

		public static void MergeSettings(SpamConfiguration configuration, IList settings)
		{
			ArrayList mergedSettings = new ArrayList();

			// Add existing settings from other rules
			if (configuration.RuleSettings != null)
			{
				foreach (RuleSetting setting in configuration.RuleSettings)
					mergedSettings.Add(setting);
			}

			// Loop thru new settings to save
			foreach (RuleSetting newSetting in settings)
			{
				// Check if this rule setting already exists
				bool settingExists = false;
				foreach (RuleSetting rs in mergedSettings)
				{
					if (rs.RuleID == newSetting.RuleID && rs.Key == newSetting.Key)
					{
						rs.Value = newSetting.Value;
						settingExists = true;
						break;
					}
				}

				// Add setting if it's new
				if (!settingExists)
					mergedSettings.Add(newSetting);
			}

			configuration.RuleSettings = (RuleSetting[])mergedSettings.ToArray(typeof(RuleSetting));
		}

		public static void ClearRulesCache()
		{
			CSCache.Remove(RulesCacheKey);
		}
	}
}
