context: // ---------------------------------------------------------------------- //
  //                                                                        //
  //                       Copyright (c) 2007-2014                          //
  //                         Digital Beacon, LLC                            //
  //                                                                        //
  // ---------------------------------------------------------------------- //
  
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Net.Mail;
  using System.Xml;
  using System.Xml.XPath;
  using DigitalBeacon.Business;
  using DigitalBeacon.Model;
  using DigitalBeacon.SiteBase.Data;
  using DigitalBeacon.SiteBase.Data.Messaging;
  using DigitalBeacon.SiteBase.Model;
  using DigitalBeacon.SiteBase.Model.Messaging;
  using DigitalBeacon.Util;
  
  namespace DigitalBeacon.SiteBase.Business.Support
  {
  	public class MessageService : BaseService, IMessageService
  	{
  		#region Private Members
  
  		private static readonly IMessageDao MsgDao = ServiceFactory.Instance.GetService<IMessageDao>();
  		private static readonly IFolderDao FolderDao = ServiceFactory.Instance.GetService<IFolderDao>();
  		private static readonly IMessageRecipientDao RecipientDao = ServiceFactory.Instance.GetService<IMessageRecipientDao>();
  		private static readonly IMessageTemplateDao TemplateDao = ServiceFactory.Instance.GetService<IMessageTemplateDao>();
  		private static readonly ILookupService LookupService = ServiceFactory.Instance.GetService<ILookupService>();
  		private static readonly IIdentityService IdentityService = ServiceFactory.Instance.GetService<IIdentityService>();
  		private static readonly IPreferenceService PreferenceService = ServiceFactory.Instance.GetService<IPreferenceService>();
  		private static readonly IQueuedEmailDao QueuedEmailDao = ServiceFactory.Instance.GetService<IQueuedEmailDao>();
  		private static readonly IMailService MailService = ServiceFactory.Instance.GetService<IMailService>();
  
  		#endregion
  
  		#region IMessageService Members
  
  		public FolderEntity GetFolder(long folderId)
  		{
  			return DataAdapter.Fetch<FolderEntity>(folderId);
  		}
  
  		public IList<FolderEntity> GetFolders(long associationId, long userId)
  		{
  			return FolderDao.FetchForDisplay(associationId, FolderType.Message, userId);
  		}
  
  		public IDictionary<FolderEntity, int> GetUnreadMessageCounts(long associationId, long userId)
  		{
  			IDictionary<FolderEntity, int> map = new Dictionary<FolderEntity, int>();
  			IList<FolderEntity> folders = GetFolders(associationId, userId);
  			foreach (FolderEntity folder in folders)
  			{
  				map[folder] = GetUnreadMessageCount(associationId, userId, folder.Id);
  			}
  			return map;
  		}
  
  		public int GetUnreadMessageCount(long associationId, long userId, long folderId)
  		{
  			return MsgDao.FetchUnreadCount(associationId, userId, folderId);
  		}
  
  		public FavoriteRecipients GetFavoriteRecipients(long associationId, long userId)
  		{
  			var fr = new FavoriteRecipients();
  			var up = PreferenceService.GetUserPreference(associationId, userId, MessagingConstants.FavoriteRecipientsKey);
  			if (up != null)
  			{
  				var doc = new XPathDocument(new StringReader(up.Value));
  				var nav = doc.CreateNavigator();
  				var nodes = nav.Select("/FavoriteRecipients/Users/Id");
  				while (nodes.MoveNext())
  				{
  					fr.Users.Add(Convert.ToInt64(nodes.Current.Value));
  				}
  				nodes = nav.Select("/FavoriteRecipients/Roles/Id");
  				while (nodes.MoveNext())
  				{
  					fr.Roles.Add(Convert.ToInt64(nodes.Current.Value));
  				}
  			}
  			return fr;
  		}
  
  		public void SaveFavoriteRecipients(long associationId, long userId, FavoriteRecipients recipients)
  		{
  			var doc = new XmlDocument();
  			XmlNode favoriteRecipients = doc.CreateElement("FavoriteRecipients");
  			doc.AppendChild(favoriteRecipients);
  			XmlNode users = doc.CreateElement("Users");
  			favoriteRecipients.AppendChild(users);
  			if (recipients.Users != null && recipients.Users.Count > 0)
  			{
  				foreach (long id in recipients.Users)
  				{
  					XmlNode ah = doc.CreateElement("Id");
  					ah.InnerText = id.ToString();
  					users.AppendChild(ah);
  				}
  			}
  			XmlNode roles = doc.CreateElement("Roles");
  			favoriteRecipients.AppendChild(roles);
  			if (recipients.Roles != null && recipients.Roles.Count > 0)
  			{
  				foreach (long id in recipients.Roles)
  				{
  					XmlNode ah = doc.CreateElement("Id");
  					ah.InnerText = id.ToString();
  					roles.AppendChild(ah);
  				}
  			}
  			var pref = PreferenceService.GetUserPreference(associationId, userId, MessagingConstants.FavoriteRecipientsKey);
  			if (pref == null)
  			{
  				pref = new PreferenceEntity
  			   {
  				   AssociationId = associationId, 
  				   UserId = userId, 
  				   Key = MessagingConstants.FavoriteRecipientsKey
  			   };
  			}
  			pref.Value = doc.OuterXml;
  			PreferenceService.SaveUserPreference(pref);
  		}
  
  		public void SendMessage(MessageEntity msg)
  		{
  			if (msg.Id > 0 && msg.DateSent != null)
  			{
  				throw new Exception("Can not send a message that was previously sent");
  			}
  			if (msg.SenderId <= 0)
  			{
  				throw new Exception("Message must have a sender.");
  			}
  			if (msg.Recipients == null || msg.Recipients.Count == 0)
  			{
  				throw new Exception("Message has no recipients.");
  			}
  			AssociateExistingRecipients(msg);
  			foreach (MessageRecipientEntity r in msg.Recipients)
  			{
  				if (r.RecipientType == EntityType.Role)
  				{
  					if (msg.Recipients.Count > 1)
  					{
  						throw new Exception("Message can only have one recipient if recipient is a role.");
  					}
  					//UserEntity sender = IdentityService.GetUser(msg.SenderId);
  					if (msg.ExpandRoleRecipient)
  					{
  						// expand role
  						//if (r.Role.Value == Role.PropertyOwner)
  						//{
  						//	if (!msg.Email)
  						//	{
  						//		throw new Exception("Message recipient can only be Property Owners roles when message is sent via Email.");
  						//	}
  						//	IList<PropertyOwnerEntity> owners = _propertyService.FindPropertyOwnersWithEmail(msg.AssociationId, new PropertySearchInfo());
  						//	foreach (PropertyOwnerEntity owner in owners)
  						//	{
  						//		msg.AddPersonRecipient(owner.Id, String.Format("{0} ({1})", owner.DisplayName, owner.Address.Email), false, true);
  						//	}
  						//}
  						//else
  						//{
  							IList<UserEntity> users = IdentityService.GetUsersByRole(msg.AssociationId, (Role)r.RecipientId);
  							foreach (UserEntity user in users)
  							{
  								if (user.Id != msg.SenderId)
  								{
  									msg.AddRecipient(EntityType.User, user.Id, msg.Email ? String.Format("{0} ({1})", user.DisplayName, user.Email) : user.DisplayName, false, true);
  								}
  							}
  						//}
  						r.RecipientType = EntityType.User;
  						r.RecipientId = msg.SenderId;
  						AssociateExistingRecipients(msg);
  					}
  					break;
  				}
  			}
  			if (msg.ReplyToId != null && msg.RelatedId == null)
  			{
  				MessageEntity replyToMsg = MsgDao.Fetch(msg.ReplyToId.Value);
  				if (replyToMsg == null)
  				{
  					throw new Exception("Could not locate replyToMessageId: " + msg.ReplyToId.Value);
  				}
  				if (replyToMsg.RelatedId != null)
  				{
  					msg.RelatedId = replyToMsg.RelatedId;
  				}
  				else
  				{
  					msg.RelatedId = msg.ReplyToId;
  				}
  			}
  			//else if (msg.WorkItemId != null && msg.RelatedId == null)
  			//{
  			//	// set RelatedId to the first message associated with this work item
  			//	List<MessageEntity> relatedMessages = new List<MessageEntity>(GetRelatedMessagesForWorkItem(msg.WorkItemId.Value));
  			//	if (relatedMessages.Count > 0)
  			//	{
  			//		relatedMessages.Sort();
  			//		if (relatedMessages[0].DateSent != null)
  			//		{
  			//			msg.RelatedId = relatedMessages[0].Id;
  			//		}
  			//	}
  			//}
  			msg.DateSent = DateTime.Now;
  			SaveMessage(msg);
  			if (msg.Email)
  			{
  				SendEmail(msg);
  			}
  			else
  			{
  				SendNotifications(msg);
  			}
  		}
  
  		public void SaveDraft(MessageEntity msg)
  		{
  			msg.DateSent = null;
  			AssociateExistingRecipients(msg);
  			SaveMessage(msg);
  		}
  
  		public void DeleteDraft(long messageId)
  		{
  			MessageEntity msg = MsgDao.Fetch(messageId);
  			if (msg == null)
  			{
  				throw new Exception("Could not find message with Id " + messageId);
  			}
  			if (msg.DateSent != null)
  			{
  				throw new Exception(String.Format("Message with Id {0} is not a draft message.", messageId));
  			}
  			DeleteWithAudit<MessageEntity>(messageId);
  		}
  
  		public MessageEntity GetMessage(long messageId)
  		{
  			return MsgDao.Fetch(messageId);
  		}
  
  		public IList<MessageEntity> GetMessages(long associationId, long userId, long folderId)
  		{
  			return MsgDao.Fetch(associationId, userId, folderId);
  		}
  
  		public IList<MessageEntity> GetSentMessages(long associationId, long userId)
  		{
  			return MsgDao.FetchSent(associationId, userId);
  		}
  
  		public IList<MessageEntity> GetDraftMessages(long associationId, long userId)
  		{
  			return MsgDao.FetchDrafts(associationId, userId);
  		}
  
  		public IList<MessageEntity> GetRelatedMessages(long messageId)
  		{
  
gt: 			return GetRelatedMessages(messageId, false);