ttajic
10/11/2016 - 8:09 AM

Adacta.Email Base64 Send Email Attachment, Open Attachment in new window

Adacta.Email Base64 Send Email Attachment, Open Attachment in new window

//require JQuery, Adacta.Email, Notify.js
var Adacta = Adacta || {};
Adacta.Report = {
	GetReportSession: function (reportName, reportID)
	{
		console.log("get report pdf session");
		var url = Xrm.Page.context.getClientUrl() + "/CRMReports/rsviewer/reportviewer.aspx";
		var GUID = Xrm.Page.data.entity.getId().replace('{', "").replace('}', ""); //set this to selected quotation GUID
		var rptPathString = ""; //set this to the CRMF_Filtered parameter
		var retrieveEntityReq = new XMLHttpRequest();

	    var strParameterXML = "<ReportFilter><ReportEntity paramname='P1'><fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'><entity name='ad_reminder'><all-attributes />" +
                      "<filter type='and'><condition attribute='ad_reminderid' operator='eq' " + 
                      "value='" + Xrm.Page.data.entity.getId() + "'/></filter></entity></fetch></ReportEntity></ReportFilter>";
		
		
		retrieveEntityReq.open("POST", url, false);
		retrieveEntityReq.setRequestHeader("Accept", "*/*");
		retrieveEntityReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		rptPathString = "id=%7B" + reportID + "%7D&uniquename=" + Xrm.Page.context.getOrgUniqueName() + "&iscustomreport=true&reportnameonsrs=&reportName=" + reportName + "&isScheduledReport=false" +
		"&CRM_Filter=" + encodeURI(strParameterXML);
		var returnObj = {
			sessionId: null,
			controlId: null,
			success: false
		};
		try
		{
			retrieveEntityReq.send(rptPathString);
			var response = retrieveEntityReq.responseText;
			var StartAfterComment = response.indexOf("e440105867d249ce8a45696677d42bcb") + 32;
			var sessionString = "ReportSession=";
			x = response.indexOf(sessionString, StartAfterComment);
			returnObj.sessionId = x > -1 ? response.substr(x + sessionString.length, response.indexOf("\\u0026", x) - x - sessionString.length) : null; //the session id
			var controlString = "ControlID=";
			x = response.indexOf(controlString, StartAfterComment);
			returnObj.controlId = x > -1 ? response.substr(x + controlString.length, response.indexOf("\\u0026", x) - x - controlString.length) : null; //the control id
			returnObj.success = returnObj.sessionId != null && returnObj.controlId != null;
		}
		catch (err)
		{
			console.log(err);
		}
		return returnObj;
	},
	base64ArrayBuffer: function (arrayBuffer)
	{
		var base64 = '';
		var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
		var bytes = new Uint8Array(arrayBuffer);
		var byteLength = bytes.byteLength;
		var byteRemainder = byteLength % 3;
		var mainLength = byteLength - byteRemainder;
		var a, b, c, d;
		var chunk;
		// Main loop deals with bytes in chunks of 3
		for (var i = 0; i < mainLength; i = i + 3)
		{
			// Combine the three bytes into a single integer
			chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
			// Use bitmasks to extract 6-bit segments from the triplet
			a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18
			b = (chunk & 258048) >> 12; // 258048   = (2^6 - 1) << 12
			c = (chunk & 4032) >> 6; // 4032     = (2^6 - 1) << 6
			d = chunk & 63; // 63       = 2^6 - 1
			// Convert the raw binary segments to the appropriate ASCII encoding
			base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
		}
		// Deal with the remaining bytes and padding
		if (byteRemainder == 1)
		{
			chunk = bytes[mainLength];
			a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2
			// Set the 4 least significant bits to zero
			b = (chunk & 3) << 4; // 3   = 2^2 - 1
			base64 += encodings[a] + encodings[b] + '==';
		}
		else if (byteRemainder == 2)
		{
			chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1];
			a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10
			b = (chunk & 1008) >> 4; // 1008  = (2^6 - 1) << 4
			// Set the 2 least significant bits to zero
			c = (chunk & 15) << 2; // 15    = 2^4 - 1
			base64 += encodings[a] + encodings[b] + encodings[c] + '=';
		}
		return base64;
	},
	GetReportPDF: function (sessionId, controlId, successCallback)
	{
		//GET https://crmdev-lj-03.adacta-group.com/Reserved.ReportViewerWebControl.axd?ReportSession=i422yj45rfckzl55asnrjc45&Culture=1060&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=dd849bde4a1b45ca9a1c9002246e7ebd&OpType=Export&FileName=Opomin+-+SLO&ContentDisposition=OnlyHtmlInline&Format=PDF HTTP/1.1
		console.log("get report pdf");
		var url = Xrm.Page.context.getClientUrl() +
			"/Reserved.ReportViewerWebControl.axd?ReportSession=" + sessionId +
			"&Culture=1060&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + controlId +
			"&OpType=Export&FileName=Public&ContentDisposition=OnlyHtmlInline&Format=PDF";
		var retrieveEntityReq = new XMLHttpRequest();
		retrieveEntityReq.open("GET", url, true);
		retrieveEntityReq.responseType = "arraybuffer";
		retrieveEntityReq.onload = function (e)
		{
			console.log("got report pdf");
			if (retrieveEntityReq.readyState === 4)
			{
				if (retrieveEntityReq.status === 200)
				{
					console.log("got report pdf OK");
					var base64data = Adacta.Report.base64ArrayBuffer(e.currentTarget.response);
					successCallback(base64data);
				}
				else
				{
					console.log("got report pdf FAILED");
					console.error(retrieveEntityReq.statusText);
				}
			}
		};
		retrieveEntityReq.setRequestHeader("Accept", "*/*");
		retrieveEntityReq.send();
	}
};
Adacta.Reminder = {
	failed: [],
	GetAttachmentPromise: function (email, attachment, emailActivitiyId, invoicenumber)
	{
		var deferred = $.Deferred();
		try
		{
			email.CreateEmailAttachment(attachment.DocumentBody, attachment.FileName, attachment.NoteText || "Račun", attachment.MimeType, emailActivitiyId,

			function (r)
			{
				deferred.resolve(invoicenumber);
			},

			function (err)
			{
				Adacta.Reminder.failed.push(invoicenumber);
				deferred.resolve(invoicenumber);
			});
		}
		catch (err)
		{
			Adacta.Reminder.failed.push(invoicenumber);
			deferred.resolve(invoicenumber);
		}
		return deferred.promise();
	},
	GetAttachments: function (successCallback, errorCallback)
	{
		if (!successCallback || typeof successCallback !== 'function')
		{
			console.log('Adacta.Reminder.GetAttachments successCallback function is required');
			return;
		}
		if (!errorCallback || typeof errorCallback !== 'function')
		{
			errorCallback = function (XmlHttpRequest, textStatus, errorThrown)
			{
				//This function will trigger asynchronously if the Retrieve returned an error
				console.log("Adacta.Reminder.GetAttachments failed: " + textStatus);
				console.log(errorThrown);
			};
		}
		if (XrmServiceToolkit === undefined || XrmServiceToolkit === null)
		{
			console.log('XrmServiceToolkit is missing');
			return;
		}
		var fetch = ["<fetch>",
                    "<entity name='invoice' >",
                    "<attribute name='invoicenumber' />",
                    "<link-entity name='ad_ad_reminder_invoice' from='invoiceid' to='invoiceid' link-type='inner' alias='reminder' intersect='true' >",
                    "  <filter>",
                    "	<condition attribute='ad_reminderid' operator='eq' value='" + Xrm.Page.data.entity.getId() + "' />",
                    "  </filter>",
                    "</link-entity>",
                    "<link-entity name='annotation' from='objectid' to='invoiceid' link-type='outer' alias='note' >",
                    "  <attribute name='subject' />",
                    "  <attribute name='mimetype' />",
                    "  <attribute name='documentbody' />",
                    "  <attribute name='notetext' />",
                    "  <attribute name='filename' />",
                    "</link-entity>",
                    "</entity>",
                    "</fetch>"];
		var resultObject = XrmServiceToolkit.Soap.Fetch(fetch.join(""));
		if (resultObject && Array === resultObject.constructor)
		{
			successCallback(resultObject);
			return;
		}
		errorCallback();
	},
	reportPDFDeffered: function (reportSession)
	{
		var d = $.Deferred();
		try
		{
			Adacta.Report.GetReportPDF(reportSession.sessionId, reportSession.controlId, function (pdf)
			{
				d.resolve(pdf);
			});
		}
		catch (err)
		{
			console.log(err);
			d.resolve(err);
		}
		return d.promise();
	},
	SendEmail: function (language)
	{
		Notify.remove();
		Notify.add("Pripravljamo Email s priponkami. Postopek utegne trajati dalj časa.", "INFO", "AttachmentOpen", null, 15);
		var emailBody = ["Spoštovani.",
"",
"Pri pregledu odprtih postavk smo ugotovili, da še vedno niste poravnali zapadlih obveznosti do naše družbe. V priponki vam posredujemo opomin s seznamom vseh neplačanih računov in vas",
"prosimo, da v roku 8 dni poravnate zapadle obveznosti in znesek nakažete na transakcijski račun Odvetniške družbe Rojs, Peljhan, Prelesnik & partnerji, o.p., d.o.o.:",
"",
"BANKA KOPER d.d.",
"Slovenska 52, 1000 Ljubljana",
"IBAN:SI 56 1010 0005 0947 693",
"",
"V kolikor ste zapadle račune že poravnali, smatrajte opomin kot brezpredmeten.",
"",
"Lepo pozdravljeni,"].join("<br>");
		var emailSubject = "Opomin";
		var reportName = "ReminderSLOMain.rdl";
		var reportId = "020685AE-B302-E411-866D-005056AEB690";
		if (language == "EN")
		{
			emailSubject = "Reminder";
			emailBody = ["Dear Sir/Madam",
"",
"Attached please find  a reminder for the following invoices that are still overdue for payment:",
"",
"You are kindly requested to make full payment immediately on the Account:",
"HYPO ALPE ADRIA BANK d.d.",
"Dunajska cesta 117, 1000 Ljubljana, Slovenia",
"IBAN: SI 56 3300 0000 0026 278",
"SWIFT: HAABSI22",
"",
"",
"Please find attached copies of the invoice for your convenience.",
"In case you have any queries, feel  free to contact us.",
"",
"Please ignore this letter, if you have already made the payment.",
"",
"Yours sincerely,"].join("<br>");
			reportName = "ReminderENGMain.rdl";
			reportId = "5AB29541-B402-E411-866D-005056AEB690";
		}
		Adacta.Reminder.failed = [];
		var attachmentPromises = [];
		var reportSession = Adacta.Report.GetReportSession(reportName, reportId);
		var reportPDF;
		if (reportSession.success)
		{
			$.when(Adacta.Reminder.reportPDFDeffered(reportSession)).done(function (pdfdata)
			{
				reportPDF = pdfdata;
				console.log("after get pdf request");
				Adacta.Reminder.GetAttachments(function (data)
				{
					if (data && data.length > 0)
					{
						var to = Xrm.Page.getAttribute("ad_customerid").getValue();
						if (!to || to.length === 0)
						{
							Notify.add("Prosim navedite stranko na opominu", "WARNING", "AttachmentWarning", null, 10);
							return;
						}
						var e = new Adacta.Email();
						e.CreateEmail(emailSubject, emailBody,
						{
							Id: Xrm.Page.data.entity.getId(),
							LogicalName: Xrm.Page.data.entity.getEntityName()
						}, function (result)
						{
							//On Email Success
							e.SetEmailEntity(result);
							e.CreateActivityParty(to[0].id, to[0].entityType, e.GetEmail().ActivityId, e.ParticipationTypeMask.ToRecipient, function ()
							{});
							e.CreateActivityParty(Xrm.Page.context.getUserId(), "systemuser", e.GetEmail().ActivityId, e.ParticipationTypeMask.Sender, function (r)
							{
								//On ActivityParty Success
								var getValue = function (attr)
								{
									if (attr)
									{
										return attr.value;
									}
									return null;
								};
								//create email attachments async
								for (index = 0; index < data.length; ++index)
								{
									var attachment = {
										DocumentBody: getValue(data[index].attributes["note.documentbody"]),
										FileName: getValue(data[index].attributes["note.filename"]),
										NoteText: getValue(data[index].attributes["note.notetext"]),
										MimeType: getValue(data[index].attributes["note.mimetype"])
									};
									attachmentPromises.push(Adacta.Reminder.GetAttachmentPromise(e, attachment, e.GetEmail().ActivityId, getValue(data[index].attributes.invoicenumber)));
								}
								attachmentPromises.push(Adacta.Reminder.GetAttachmentPromise(e,
								{
									DocumentBody: reportPDF,
									FileName: emailSubject + ".pdf",
									NoteText: "",
									MimeType: "application/pdf"
								}, e.GetEmail().ActivityId, "Opomin - poročilo"));
								//wait for attachments to "attach"
								$.when.apply($, attachmentPromises)
									.done(function (data)
								{
									if (Adacta.Reminder.failed.length === 0)
									{
										Notify.add("Email kreiran", "QUESTION", "AttachmentOpen", [
										{
											type: "button",
											text: "Odprem?",
											callback: function ()
											{
												Xrm.Utility.openEntityForm("email", e.GetEmail().ActivityId, null);
											}}]);
									}
									else
									{
										Notify.add("Pri dodajanju nekaterih priponk je prišlo do napake. Preverite: " + Adacta.Reminder.failed.join(), "WARNING", "AttachmentError", [
										{
											type: "button",
											text: "Odprem?",
											callback: function ()
											{
												Xrm.Utility.openEntityForm("email", e.GetEmail().ActivityId, null);
											}}]);
									}
								});
							});
						});
					}
					else Notify.add("Ne najdem računov s priponkami", "INFO", "AttachmentError", null, 10);
				});
			});
		}
	}
};
//require JQuery, Adacta.Email, Notify.js

var Adacta = Adacta || {};

Adacta.Invoice = {
  AddAttachment: function () {
  	//open add attachment dialog
  	//1090 == invoice ObjectTypeCode
  	parent.Mscrm.RibbonActions.addFileToRecord(1090, Xrm.Page.data.entity.getId());
  },
  GetAttachments: function(successCallback, errorCallback) {
    if (typeof jQuery === 'undefined') {
      console.log('jQuery is missing.')
      return;
    }

    if (!successCallback || typeof successCallback !== 'function') {
      console.log('Adacta.Invoice.GetAttachments successCallback function is required');
      return;
    };

    if (!errorCallback || typeof errorCallback !== 'function') {
      errorCallback = function(XmlHttpRequest, textStatus, errorThrown) {
        //This function will trigger asynchronously if the Retrieve returned an error
        console.log("Adacta.Invoice.GetAttachments failed: " + textStatus);
        console.log(errorThrown);
      };
    }

    // Get CRM Context
    var context = Xrm.Page.context;
    var serverUrl = context.getClientUrl();

    // Cater for URL differences between on-premise and online
    if (serverUrl.match(/\/$/)) {
      serverUrl = serverUrl.substring(0, serverUrl.length - 1);
    }

    // Define ODATA query
    //https://crmdev-lj-03.adacta-group.com/RPPP/XRMServices/2011/OrganizationData.svc/AnnotationSet?$select=FileName,DocumentBody,ObjectId,MimeType&$filter=ObjectId/Id eq (Guid'4677c06d-f070-e511-80cb-001dd8b71c0f')
    var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc";
    var ODATA_EntityCollection = "/AnnotationSet";
    var QUERY = "?$select=NoteText,FileName,DocumentBody,ObjectId,MimeType,CreatedOn&$filter=ObjectId/Id eq (Guid'" + Xrm.Page.data.entity.getId() + "') and MimeType ne null&$orderby=CreatedOn desc";
    var URL = serverUrl + ODATA_ENDPOINT + ODATA_EntityCollection + QUERY;
    
    //Asynchronous AJAX call
    $.ajax({
      type: "GET",
      contentType: "application/json; charset=utf-8",
      datatype: "json",
      url: URL,
      beforeSend: function(XMLHttpRequest) {
        //Specifying this header ensures that the results will be returned as JSON.
        XMLHttpRequest.setRequestHeader("Accept", "application/json");
      },
      success: successCallback,
      error: errorCallback
    });
  },
  isIE: function () {
  	var userAgent = userAgent || window.navigator.userAgent;
  	return userAgent.indexOf("MSIE ") > -1 || userAgent.indexOf("Trident/") > -1 || userAgent.indexOf("Edge/") > -1;
  },
  formatDate: function(date) {
  	if (date && date instanceof Date) {
  		return  date.getDate() + "." + (date.getMonth() + 1) + "." + date.getFullYear();
  	}
  	return "";
  },
  OpenAttachmentInNewWindow: function() {
    Notify.remove();
    Adacta.Invoice.GetAttachments(function(data, textStatus, XmlHttpRequest) {
      if (data && data.d && data.d.results && data.d.results.length > 0) {
        var attachment = data.d.results[0];
        if (attachment && attachment.DocumentBody) {
        	if (Adacta.Invoice.isIE() && window.navigator.msSaveOrOpenBlob) {
        			//Notify.add("Internet Explorer ne podpira odpiranje PDF datoteke, zato vam je ponujeno shranjevanje priponke", "INFO", "AttachmentOpen", null, 10);
        			Notify.add("Internet Explorer ne podpira odpiranja datotek na odjemalski strani.", "INFO", "AttachmentOpen", null, 10);
      			
        			// convert base64 to raw binary data held in a string
					var byteString = window.atob(attachment.DocumentBody);
					// write the bytes of the string to an ArrayBuffer
					var ab = new ArrayBuffer(byteString.length);
					var ia = new Uint8Array(ab);
					for (var i = 0; i < byteString.length; i++) {
						ia[i] = byteString.charCodeAt(i);
					}
					// write the ArrayBuffer to a blob, and you're done  			        			
        			var blob = new Blob([ia],{ type: attachment.MimeType });
        			navigator.msSaveOrOpenBlob(blob, attachment.FileName);        			
        	}
        	else
        		window.open("data:" + attachment.MimeType + ";base64," + attachment.DocumentBody);          
          	return;
        }        
     }
     Notify.add("Ne najdem opombe s priponko", "INFO", "AttachmentError", null, 10);
   }, function (err) { console.log("OpenAttachmentInNewWindow"); console.log(err); });
  },
  SendEmail: function(language) {
    Notify.remove();

	var to = Xrm.Page.getAttribute("ad_administratorid").getValue();
	if (!to || to.length == 0) {
		Notify.add("Prosim navedite skrbnika na računu", "WARNING", "AttachmentWarning", null, 10);
		return;
	}
    
    var invoiceNo =  Xrm.Page.getAttribute("name").getValue();
    var toDate =  Xrm.Page.getAttribute("datedelivered").getValue();    
    
    if (!invoiceNo || !(toDate instanceof Date)) {
		Notify.add("Prosim navedite številko računa ter datum dostave (Date Delivered) na računu", "WARNING", "AttachmentWarning", null, 10);
		return;
	}

    var fromDate =  new Date(toDate.getFullYear(), toDate.getMonth(), 1);
    
    var emailBody = ["Spoštovani.", "", "V prilogi vam posredujemo račun št. " + invoiceNo, "za opravljene odvetniške storitve v obdobju od " + Adacta.Invoice.formatDate(fromDate) + " do " + Adacta.Invoice.formatDate(toDate) + ".", "", "Sestavni del računa je priloženi stroškovnik.",
    "", "Lepo pozdravljeni."].join("<br>");
	var emailSubject = "Račun št. " + invoiceNo;
    if (language == "EN") {
      emailSubject = "Invoice no. " + invoiceNo;
      emailBody = ["Dear Sir/Madam", "", "Attached please find Invoice no. " + invoiceNo, "for our legal services performed from " + Adacta.Invoice.formatDate(fromDate) + " until " + Adacta.Invoice.formatDate(toDate) + ".", "", "Attached Statement of Fees makes part of the Invoice.",
    	"", "Kind regards."].join("<br>");
    }

	Notify.add("Pripravljamo Email. Prosimo počakajte ...", "INFO", "AttachmentOpen", null, 10);

    Adacta.Invoice.GetAttachments(function(data, textStatus, XmlHttpRequest) {
      if (data && data.d && data.d.results && data.d.results.length > 0) {
        var attachment = data.d.results[0];
        if (!attachment) {
          Notify.add("Ne najdem opombe s priponko", "INFO", "AttachmentError", null, 10);
          return;
        }

        var e = new Adacta.Email();
        e.CreateEmail(emailSubject, emailBody, {
          Id: Xrm.Page.data.entity.getId(),
          LogicalName: Xrm.Page.data.entity.getEntityName()
        }, function(result) {
          e.SetEmailEntity(result);
          e.CreateActivityParty(to[0].id, to[0].entityType, e.GetEmail().ActivityId, e.ParticipationTypeMask.ToRecipient, function () {});
          e.CreateActivityParty(Xrm.Page.context.getUserId(), "systemuser", e.GetEmail().ActivityId, e.ParticipationTypeMask.Sender, function(r) {
            e.CreateEmailAttachment(attachment.DocumentBody, attachment.FileName, attachment.NoteText || "Račun", attachment.MimeType, e.GetEmail().ActivityId,
              function() {
                Notify.add("Email kreiran", "QUESTION", "AttachmentOpen", [{
                  type: "button",
                  text: "Odprem?",
                  callback: function() {
                    Xrm.Utility.openEntityForm("email", e.GetEmail().ActivityId, null);
                  }
                }]);
              });
          });
        })
      } else Notify.add("Ne najdem opombe s priponko", "INFO", "AttachmentError", null, 10);
    });
  }
}
var Adacta = Adacta || {};

// Dependency on SDK.REST


var Base64 = {


    _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",


    encode: function(input) {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;

        input = Base64._utf8_encode(input);

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

        }

        return output;
    },


    decode: function(input) {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        while (i < input.length) {

            enc1 = this._keyStr.indexOf(input.charAt(i++));
            enc2 = this._keyStr.indexOf(input.charAt(i++));
            enc3 = this._keyStr.indexOf(input.charAt(i++));
            enc4 = this._keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }

        }

        output = Base64._utf8_decode(output);

        return output;

    },

    _utf8_encode: function(string) {
        string = string.replace(/\r\n/g, "\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if ((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    },

    _utf8_decode: function(utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;

        while (i < utftext.length) {

            c = utftext.charCodeAt(i);

            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            }
            else if ((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i + 1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i + 1);
                c3 = utftext.charCodeAt(i + 2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        }

        return string;
    }

};

Adacta.Email = function () {
		var self = this;
		var emailEntity = null;
		var EmailException = function (message) {
   			this.message = message;
   			this.name = "EmailException";
		};
		return {
		ParticipationTypeMask: Object.freeze({
		    "Sender":1,
		    "ToRecipient":2,
		    "CCRecipient":3,
		    "BccRecipient": 4,
		    "RequiredAttendee":5,
		    "OptionalAttendee":6,
		    "Organizer":7,
		    "Regarding": 8,
		    "Owner": 9,
		    "Resource": 10,
		    "Customer": 11
		}),
		GetEmail: function () {
			return self.emailEntity;
		},
		SetEmailEntity: function (entity) {
			self.emailEntity = entity;
		},
	    CreateEmailAttachment: function(body, fileName, subject, mimeType, emailActivityId, successCallback, errorCallback) 
        {  
			if (!emailActivityId) {
				throw new self.EmailException('Cannot attach a file to an non-existing email activity. Use CreateEmail or get the email id and pass it into CreateEmailAttachment.');
			}

			if (!body || !fileName) {
				throw new self.EmailException('Cannot attach an empty file or file without name.');
			}

	  		if (!successCallback) {
	  			successCallback = function (result) {};
	  		}
	  		
	  		if (!errorCallback || typeof errorCallback !== 'function') {
	  			errorCallback = function (error) { console.log(error); };
	  		}  
	  
	        //Email attachment parameters  
	        var activitymimeattachment = new Object();  
	        activitymimeattachment.ObjectId = new Object();  
	        activitymimeattachment.ObjectId.LogicalName = "email";  
	        activitymimeattachment.ObjectId.Id = emailActivityId;  
	        activitymimeattachment.ObjectTypeCode = "email",  
	        activitymimeattachment.Subject = subject;  
	        activitymimeattachment.Body = body;  
	        activitymimeattachment.FileName = fileName;  
	        activitymimeattachment.MimeType = mimeType ? mimeType : "application/pdf";  
	  		
	        SDK.REST.createRecord(activitymimeattachment, "ActivityMimeAttachment", successCallback, errorCallback);

        }, 
		CreateActivityParty: function (partyid, partyLogicalName, emailActivityId, participationTypeMask, successCallback, errorCallback) {
			if (!partyid || !partyLogicalName || !emailActivityId || !participationTypeMask)
				throw new self.EmailException('To Add an ActivityParty to an email partyid, partyLogicalName, emailActivityId, participationTypeMask should not be empty');
			
			if (!successCallback || typeof successCallback !== 'function') {
	  			successCallback = function (result) {};
	  		}
	  		
	  		if (!errorCallback || typeof errorCallback !== 'function') {
	  			errorCallback = function (error) { console.log(error); };
	  		}  
	  		
		    var activityParty = new Object();  
		    
		    //Set the "party" of the ActivityParty // EntityReference of an entity this activityparty relatated to.   
		    activityParty.PartyId = {  
		        Id: partyid, // id of the the current user which becomes the sender  
		        LogicalName: partyLogicalName  
		    };  
		    
		    //Set the "activity" of the ActivityParty EntityReference.  
		    activityParty.ActivityId =  
		    {  
		        Id: emailActivityId,  
		        LogicalName: "email"  
		    };
		    
		    //Set the participation type (what role the party has on the activity).  
		    activityParty.ParticipationTypeMask =  
		    {  
		        Value: participationTypeMask 
		    }; // 1 mean Sender  
			  
		    SDK.REST.createRecord(activityParty, "ActivityParty", successCallback, errorCallback);  		
		},
		CreateEmail: function(subject, body, regardingObject, successCallback, errorCallback) {  
			if (!successCallback || typeof successCallback !== 'function') {
	  			successCallback = function (result) {};
	  		}
	  		
	  		if (!errorCallback || typeof errorCallback !== 'function') {
	  			errorCallback = function (error) { console.log(error); };
	  		}  		

	        var email = new Object();   
	        email.Subject = subject;
	        email.Description = body;
	        if (regardingObject)
	        	email.RegardingObjectId = regardingObject;
	        SDK.REST.createRecord(email, "Email", successCallback, errorCallback);  
	    }
	    }
};