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

using System;
using System.Collections;
using System.Diagnostics;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Threading;
using System.Web.Mail;
using System.Xml;
using CommunityServer.Configuration;
using MailMessage=System.Net.Mail.MailMessage;

namespace CommunityServer.Components
{
	public class AspNet20EmailJob : IJob
	{
        private int _failureInterval = 15;
        private int _numberOfTries = 10;

	    public void Execute(XmlNode node)
	    {
			// Get the failureInterval setting
			XmlAttribute failureIntervalNode = node.Attributes["failureInterval"];
			XmlAttribute numberOfTriesNode = node.Attributes["numberOfTries"];

			if(failureIntervalNode != null)
			{
				try { _failureInterval = int.Parse(failureIntervalNode.Value); }
				catch { _failureInterval = 15; }
			}

			if(numberOfTriesNode != null)
			{
				try { _numberOfTries = int.Parse(numberOfTriesNode.Value); }
				catch { _numberOfTries = 10; }
			}
          
            SiteSettingsManager.IterateSiteSettings(new SiteSettingsListIterator(SendQueuedEmailJob));
	    }

		public void SendQueuedEmailJob(int settingsID)
        {
            CSContext ctx = CSContext.Create(settingsID);
			CSConfiguration csConfig = CSConfiguration.GetConfig();

			// Test to see if this server or the site has email disabled.  If either the server or the site
			// has disabled email, or if the site specified is null, exit the method without attempting 
			// further work.
			//
			if (csConfig.IsEmailDisabled || ctx.SiteSettings == null || !ctx.SiteSettings.EnableEmail)
				return;

			ArrayList emails = EmailQueueProvider.Instance().DequeueEmail(ctx.SiteSettings.SettingsID);
			ArrayList failure = new ArrayList();

			int port = 25;
			if (!Globals.IsNullorEmpty(ctx.SiteSettings.SmtpPortNumber))
			{
				try
				{
					port = int.Parse(ctx.SiteSettings.SmtpPortNumber);
				}
				catch { }
			}

			SmtpClient smtp = new SmtpClient(ctx.SiteSettings.SmtpServer, port);

			if (ctx.SiteSettings.SmtpServerUsingNtlm)
				smtp.Credentials = CredentialCache.DefaultNetworkCredentials;
			else if (ctx.SiteSettings.SmtpServerRequiredLogin)
				smtp.Credentials = new NetworkCredential(ctx.SiteSettings.SmtpServerUserName, ctx.SiteSettings.SmtpServerPassword);

			int sentCount = 0;
			int totalSent = 0;
			short connectionLimit = csConfig.SmtpServerConnectionLimit;
			foreach (EmailTemplate m in emails)
			{
				try
				{
					MailMessage message = new MailMessage(m.From, m.To, m.Subject, m.Body);
					
					// Other values
					message.IsBodyHtml = (m.BodyFormat == MailFormat.Html);
					
					// Set priority
					switch(m.Priority)
					{
						case System.Web.Mail.MailPriority.High:
							message.Priority = System.Net.Mail.MailPriority.High;
							break;
						case System.Web.Mail.MailPriority.Low:
							message.Priority = System.Net.Mail.MailPriority.Low;
							break;
						default:
						case System.Web.Mail.MailPriority.Normal:
							message.Priority = System.Net.Mail.MailPriority.Normal;
							break;
					}

					// Set the body encoding
					try { message.BodyEncoding = Encoding.GetEncoding(CSContext.Current.SiteSettings.EmailEncoding); }
					catch { message.BodyEncoding = Encoding.UTF8; }

					// Replace any LF characters with CR LF
					message.Body = message.Body.Replace("\r", string.Empty);
					message.Body = message.Body.Replace("\n", "\r\n");

					// Set some CS related headers
					message.Headers.Add("X-CS-EmailID", m.EmailID.ToString());
					message.Headers.Add("X-CS-Attempts", (m.NumberOfTries + 1).ToString());
					message.Headers.Add("X-CS-AppDomain", AppDomain.CurrentDomain.FriendlyName);

					// Send it
					smtp.Send(message);

					// (Ken) Moved the delete command to here
					//       If a number of emails were sent, the command to delete them could timeout and duplicates would be sent on the next run
					EmailQueueProvider.Instance().DeleteQueuedEmail(m.EmailID);

					if (connectionLimit != -1 && ++sentCount >= connectionLimit)
					{
						Thread.Sleep(new TimeSpan(0, 0, 0, 15, 0));
						sentCount = 0;
					}
					// on error, loop so to continue sending other email.
				}
				catch (Exception e)
				{
					Debug.WriteLine(e.Message + " : " + (e.InnerException != null ? e.InnerException.Message : String.Empty));
					CSException fe = new CSException(CSExceptionType.EmailUnableToSend, "SendQueuedEmails Failed To: " + m.To, (e.InnerException != null ? e.InnerException : e));
					fe.Log(ctx.SiteSettings.SettingsID);

					// Add it to the failure list
					failure.Add(m.EmailID);
				}

				++totalSent;

				if (ctx.SiteSettings.EmailThrottle > 0 && totalSent >= ctx.SiteSettings.EmailThrottle)
					break;
			}

			if (failure.Count > 0)
				EmailQueueProvider.Instance().QueueSendingFailure(failure, _failureInterval, _numberOfTries);

			if (totalSent > 0 || failure.Count > 0)
			{
				EventLogEntry entry = new EventLogEntry();
				entry.Message = string.Format("Email Queue:\n Messages Sent: {0}\nMessages Failed: {1}", totalSent, failure.Count);
				entry.Category = "Job Status";
				entry.EventID = 601;
				entry.SettingsID = ctx.SiteSettings.SettingsID;
				EventLogs.Write(entry);
			}
		}
	}
}
