using System;
using System.IO;
using LumiSoft.Net.Mime;

namespace LumiSoft.Net.IMAP.Server
{
	/// <summary>
	/// Summary description for FetchHelper.
	/// </summary>
	internal class FetchHelper
	{
		// ToDo: functions to accept MimeParser

		#region function ParseEnvelope

		public static string ParseEnvelope(byte[] data)
		{
			/* Rfc 3501 7.4.2
				ENVELOPE
				A parenthesized list that describes the envelope structure of a
				message.  This is computed by the server by parsing the
				[RFC-2822] header into the component parts, defaulting various
				fields as necessary.

				The fields of the envelope structure are in the following
				order: date, subject, from, sender, reply-to, to, cc, bcc,
				in-reply-to, and message-id.  The date, subject, in-reply-to,
				and message-id fields are strings.  The from, sender, reply-to,
				to, cc, and bcc fields are parenthesized lists of address
				structures.

				An address structure is a parenthesized list that describes an
				electronic mail address.  The fields of an address structure
				are in the following order: personal name, [SMTP]
				at-domain-list (source route), mailbox name, and host name.

				[RFC-2822] group syntax is indicated by a special form of
				address structure in which the host name field is NIL.  If the
				mailbox name field is also NIL, this is an end of group marker
				(semi-colon in RFC 822 syntax).  If the mailbox name field is
				non-NIL, this is a start of group marker, and the mailbox name
				field holds the group name phrase.

				If the Date, Subject, In-Reply-To, and Message-ID header lines
				are absent in the [RFC-2822] header, the corresponding member
				of the envelope is NIL; if these header lines are present but
				empty the corresponding member of the envelope is the empty
				string.
			*/
			// ((sender))
			// ENVELOPE ("date" "subject" from sender reply-to to cc bcc in-reply-to "messageID")

			MimeParser p = new MimeParser(data);

			string envelope  = "ENVELOPE (";
			
			// date
			envelope += "\"" + p.MessageDate.ToString("r",System.Globalization.DateTimeFormatInfo.InvariantInfo) + "\" ";
			
			// subject
			envelope += "\"" + p.Subject + "\" ";

			// from
			// ToDo: May be multiple senders
			LumiSoft.Net.Mime.Parser.eAddress adr = new LumiSoft.Net.Mime.Parser.eAddress(p.From);
			envelope += "((\"" + adr.Name + "\" NIL \"" + adr.Mailbox + "\" \"" + adr.Domain + "\")) ";

			// sender
			// ToDo: May be multiple senders
			envelope += "((\"" + adr.Name + "\" NIL \"" + adr.Mailbox + "\" \"" + adr.Domain + "\")) ";

			// reply-to
			string replyTo = MimeParser.ParseHeaderField("reply-to:",p.Headers);
			if(replyTo.Length > 0){
				envelope += "(";
				foreach(string recipient in replyTo.Split(';')){
					LumiSoft.Net.Mime.Parser.eAddress adrTo = new LumiSoft.Net.Mime.Parser.eAddress(recipient);
					envelope += "(\"" + adrTo.Name + "\" NIL \"" + adrTo.Mailbox + "\" \"" + adrTo.Domain + "\") ";
				}
				envelope = envelope.TrimEnd();
				envelope += ") ";
			}
			else{
				envelope += "NIL ";				
			}

			// to
			string[] to = p.To;
			envelope += "(";
			foreach(string recipient in to){
				LumiSoft.Net.Mime.Parser.eAddress adrTo = new LumiSoft.Net.Mime.Parser.eAddress(recipient);
				envelope += "(\"" + adrTo.Name + "\" NIL \"" + adrTo.Mailbox + "\" \"" + adrTo.Domain + "\") ";
			}
			envelope = envelope.TrimEnd();
			envelope += ") ";

			// cc
			string cc = MimeParser.ParseHeaderField("CC:",p.Headers);
			if(cc.Length > 0){
				envelope += "(";
				foreach(string recipient in cc.Split(';')){
					LumiSoft.Net.Mime.Parser.eAddress adrTo = new LumiSoft.Net.Mime.Parser.eAddress(recipient);
					envelope += "(\"" + adrTo.Name + "\" NIL \"" + adrTo.Mailbox + "\" \"" + adrTo.Domain + "\") ";
				}
				envelope = envelope.TrimEnd();
				envelope += ") ";
			}
			else{
				envelope += "NIL ";				
			}

			// bcc
			string bcc = MimeParser.ParseHeaderField("BCC:",p.Headers);
			if(bcc.Length > 0){
				envelope += "(";
				foreach(string recipient in bcc.Split(';')){
					LumiSoft.Net.Mime.Parser.eAddress adrTo = new LumiSoft.Net.Mime.Parser.eAddress(recipient);
					envelope += "(\"" + adrTo.Name + "\" NIL \"" + adrTo.Mailbox + "\" \"" + adrTo.Domain + "\") ";
				}
				envelope = envelope.TrimEnd();
				envelope += ") ";
			}
			else{
				envelope += "NIL ";				
			}

			// in-reply-to
			string inReplyTo = MimeParser.ParseHeaderField("in-reply-to:",p.Headers);
			if(inReplyTo.Length > 0){
				envelope += "\"" + inReplyTo + "\"";
			}
			else{
				envelope += "NIL ";
			}

			// message-id
			if(p.MessageID.Length > 0){
				envelope += "\"" + p.MessageID + "\"";
			}
			else{
				envelope += "NIL";
			}

			envelope += ")";

			return envelope;
		}

		#endregion

		#region function ParseHeaderFields

		/// <summary>
		/// Returns requested header fields lines.
		/// </summary>
		/// <param name="fieldsStr">Header fields to get.</param>
		/// <param name="data">Message data.</param>
		/// <returns></returns>
		public static string ParseHeaderFields(string fieldsStr,byte[] data)
		{
			string retVal = "";

			string[] fields = fieldsStr.Split(' ');
            using(MemoryStream mStrm = new MemoryStream(data)){
				TextReader r = new StreamReader(mStrm);
				string line = r.ReadLine();
				
				bool fieldFound = false;
				// Loop all header lines
				while(line != null){ 
					// End of header
					if(line.Length == 0){
						break;
					}

					// Field continues
					if(fieldFound && line.StartsWith("\t")){
						retVal += line + "\r\n";
					}
					else{
						fieldFound = false;

						// Check if wanted field
						foreach(string field in fields){
							if(line.Trim().ToLower().StartsWith(field.Trim().ToLower())){
								retVal += line + "\r\n";
								fieldFound = true;
							}
						}
					}

					line = r.ReadLine();
				}
			}

			return retVal;
		}

		#endregion

		#region function ParseHeaderFieldsNot

		/// <summary>
		/// Returns header fields lines except requested.
		/// </summary>
		/// <param name="fieldsStr">Header fields to skip.</param>
		/// <param name="data">Message data.</param>
		/// <returns></returns>
		public static string ParseHeaderFieldsNot(string fieldsStr,byte[] data)
		{
			string retVal = "";

			string[] fields = fieldsStr.Split(' ');
            using(MemoryStream mStrm = new MemoryStream(data)){
				TextReader r = new StreamReader(mStrm);
				string line = r.ReadLine();
				
				bool fieldFound = false;
				// Loop all header lines
				while(line != null){ 
					// End of header
					if(line.Length == 0){
						break;
					}

					// Filed continues
					if(fieldFound && line.StartsWith("\t")){
						retVal += line + "\r\n";
					}
					else{
						fieldFound = false;

						// Check if wanted field
						foreach(string field in fields){
							if(line.Trim().ToLower().StartsWith(field.Trim().ToLower())){								
								fieldFound = true;
							}
						}

						if(!fieldFound){
							retVal += line + "\r\n";
						}
					}

					line = r.ReadLine();
				}
			}

			return retVal;
		}

		#endregion

		#region function ParseText

		/// <summary>
		/// Parses body text from message
		/// </summary>
		/// <param name="data"></param>
		/// <returns></returns>
		public static string ParseText(byte[] data)
		{
			MimeParser p = new MimeParser(data);

			return p.BodyText;
		}

		#endregion

		#region function ParseMimeEntry

		/// <summary>
		/// Returns requested mime entry data.
		/// </summary>
		/// <param name="message"></param>
		/// <param name="mimeEntryNo"></param>
		/// <returns>Returns requested mime entry data or NULL if requested entri doesn't exist.</returns>
		public static byte[] ParseMimeEntry(byte[] message,int mimeEntryNo)
		{
			MimeParser p = new MimeParser(message);

			if(mimeEntryNo > 0 && mimeEntryNo <= p.MimeEntries.Count){
				return ((MimeEntry)p.MimeEntries[mimeEntryNo - 1]).Data;
			}

			return null;
		}

		#endregion

	}
}
