using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Web.Mail;
using Orciid.Core.Util;

namespace Orciid.Core
{
	/// <summary>
	/// Email template
	/// </summary>
	/// <remarks>
	/// This class reads an XML template file and generates an email sender, subject and
	/// body that can then be sent.
	/// </remarks>
	public class EmailTemplate
	{
		private EmailTemplate()
		{
		}

		#region XSD
		private const string EMAILSCHEMA = @"
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema' elementFormDefault='qualified' attributeFormDefault='unqualified'>
	<xs:element name='email'>
		<xs:complexType>
			<xs:sequence>
				<xs:element name='sender' type='xs:string' minOccurs='0'/>
				<xs:element name='subject' type='xs:string'/>
				<xs:element name='body' type='xs:string'/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>
";
		#endregion

		/// <summary>
		/// Generate email from template
		/// </summary>
		/// <remarks>
		/// This method reads a specified template file, merges it with the parameters
		/// that were passed, and returns the sender, subject, and body of the resulting
		/// email.
		/// </remarks>
		/// <param name="template">The name of the email template file</param>
		/// <param name="sender">Holds the sender upon return from the method</param>
		/// <param name="subject">Holds the subject upon return from the method</param>
		/// <param name="body">Holds the body upon return from the method</param>
		/// <param name="parameters">An array of parameters to be inserted in the email</param>
		/// <returns><c>true</c> if the template could be loaded and merged with the data,
		/// <c>false</c> if an error occurred.</returns>
		public static bool GetEmail(string template, 
			out string sender, out string subject, out string body,
			params string[] parameters)
		{
			XmlValidatingReader reader = null;
			string templatepath = Configuration.Instance.GetString("content.templates");
			try
			{
				reader = new XmlValidatingReader(new XmlTextReader(new StreamReader(
					Path.Combine(templatepath, Path.GetFileNameWithoutExtension(template) + ".xml"))));
				XmlSchemaCollection schemas = new XmlSchemaCollection();
				schemas.Add(null, new XmlTextReader(new StringReader(EMAILSCHEMA)));
				reader.ValidationType = ValidationType.Schema;
				reader.Schemas.Add(schemas);
				XmlDocument doc = new XmlDocument();
				doc.Load(reader);
				XmlNode sendernode = doc.SelectSingleNode("/email/sender");
				string f = (sendernode != null ? sendernode.InnerText : Configuration.Instance.GetString("smtp.sender"));
				string s = doc.SelectSingleNode("/email/subject").InnerText;
				string b = doc.SelectSingleNode("/email/body").InnerText;
				sender = String.Format(f, parameters);
				subject = String.Format(s, parameters);
				body = String.Format(b, parameters);
				return true;
			}
			catch (Exception ex)
			{
				TransactionLog.Instance.AddException("Template error", 
					String.Format("Could not read email template '{0}'", template),
					ex);
				sender = null;
				subject = null;
				body = null;
				return false;
			}
		}

		/// <summary>
		/// Initialize email template class
		/// </summary>
		/// <remarks>
		/// Adds a configuration file change event handler to be notified when the configuration
		/// changes.
		/// </remarks>
		[Initialize]
		public static void Initialize()
		{
			Configuration.Instance.OnChange += new OnConfigurationChangeDelegate(Configuration_OnChange);
		}

		private static void Configuration_OnChange(IConfiguration configuration, object arg)
		{
			SmtpMail.SmtpServer = configuration.GetString("smtp.server");
		}
	}
}
