/**
 *  Copyright (C) 2022, 2024  Double Bastion LLC
 *
 *  This file is part of Roundpin, which is licensed under the
 *  GNU Affero General Public License Version 3.0. The license terms
 *  are detailed in the "LICENSE.txt" file located in the root directory.
 *
 *  This is a modified version of the original file "cyber_mega_phone.js",
 *  first modified in 2020. The copyright notice for the original
 *  content follows.
 */
///////////////////////////////////////////////////////////////////////////////
//  Cyber Mega Phone 2K
//  Copyright (C) 2017 Digium, Inc.
//
//  This program is free software, distributed under the terms of the
//  MIT License. See the LICENSE file at the top of the source tree.
///////////////////////////////////////////////////////////////////////////////

'use_strict';

let phone;
let strtdUA;
let numPressed = null;
var isFirefox = typeof InstallTrigger !== 'undefined';
let isChrome = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
let currentSession = [];
let userCount = 0;
let cAspectRatio = 1.33;
let mvWidth = 300;
let mvHeight = 226;
let StreamChanTbl = [];
let ExtProNmTbl = [];
let messageWindowState = 'closed';
let messageWindowStatePM = {};
let crVConfUserPrivKey = '';
let currentVconfPrivKey = '';
let splitMessageVC = {};
let splitMessageVCpm = {};
let sendFileCheckVC = 0;
let upFileNameVC = '';
let sendFileChatErrVC = '';
let sendFileCheckVCpm = {};
let upFileNameVCpm = {};
let sendFileChatErrVCpm = {};
let vcDocIsVisible = true;

function ConferencePhone(id, name, password, host, WebSocketPath, StunServer, register, audio=true, video=true) {

	EasyEvent.call(this);

	this.id = id;
	this.name = name;
	this.password = password;
	this.host = host;
        this.WebSocketPath = WebSocketPath;
        this.StunServer = StunServer;
	this.register = register;

	this.audio = audio;
	this.video = video;

	this._locals = new Streams();
	this._locals.bubble("streamAdded", this);
	this._locals.bubble("streamRemoved", this);

	this._remotes = new Streams();
	this._remotes.bubble("streamAdded", this);
	this._remotes.bubble("streamRemoved", this);
};

ConferencePhone.prototype = Object.create(EasyEvent.prototype);
ConferencePhone.prototype.constructor = ConferencePhone;

// This was taken from the WebRTC unified transition guide
function isUnifiedPlanDefault() {
	// Safari supports addTransceiver() but not Unified Plan when
	// currentDirection is not defined.
	if (!('currentDirection' in RTCRtpTransceiver.prototype))
		return false;

	// If Unified Plan is supported, addTransceiver() should not throw.
	const tempPc = new RTCPeerConnection();
	let canAddTransceiver = false;
	try {
		tempPc.addTransceiver('audio');
		canAddTransceiver = true;
	} catch (e) {
	}

	tempPc.close();
	return canAddTransceiver;
}

ConferencePhone.prototype.connect = function () {
	if (this._ua) {
		this._ua.start(); // Just reconnect
		return;
	}

	let that = this;

	let socket = new JsSIP.WebSocketInterface('wss://' + this.host +':'+ this.WebSocketPath);
	let uri = 'sip:' + this.id + '@' + this.host;

	let config = {
		sockets: [ socket ],
		uri: uri,
		contact_uri: uri,
		username: this.name ? this.name : this.id,
		password: this.password,
		register: this.register,
		register_expires : 300,
                sessionDescriptionHandlerFactoryOptions: {
                    peerConnectionOptions : {
                        alwaysAcquireMediaFirst: true,
                        iceCheckingTimeout: 500,
                        rtcConfiguration: {
                            iceServers : [
                                { urls: "stun:" + this.StunServer }
                            ]
                        }
                    }
                }
	};

	this._unified = isUnifiedPlanDefault();

	this._ua = new JsSIP.UA(config);
        strtdUA = this._ua;

	function bubble (obj, name) {
		obj.on(name, function (data) {
			that.raise(name, data);
		});
	};

	bubble(this._ua, 'connected');
	bubble(this._ua, 'disconnected');
	bubble(this._ua, 'registered');
	bubble(this._ua, 'unregistered');
	bubble(this._ua, 'registrationFailed');

	this._ua.on('newRTCSession', function (data) {

                currentSession.push(data.session);

		let rtc = data.session;
		rtc.interop = new SdpInterop.InteropChrome();

		console.log('new session - ' + rtc.direction + ' - ' + rtc);

		rtc.on("confirmed", function () {
			// ACK was received
			let streams = rtc.connection.getLocalStreams();
			for (let i = 0; i < streams.length; ++i) {
				console.log('confirmed: adding local stream ' + streams[i].id);
				streams[i].local = true;
				that._locals.add(streams[i]);
			}
		});

		rtc.on("sdp", function (data) {

			if (isFirefox && data.originator === 'remote') {
				data.sdp = data.sdp.replace(/actpass/g, 'active');
			} else if (isChrome && !that._unified) {
				let desc = new RTCSessionDescription({type:data.type, sdp:data.sdp});
				if (data.originator === 'local') {
					converted = rtc.interop.toUnifiedPlan(desc);
				} else {
					converted = rtc.interop.toPlanB(desc);
				}

				data.sdp = converted.sdp;
			}

                        // Get the channel id and the stream id from the sdp data
	                var sdpLinesinit = data.sdp.split(/\r?\n/);
			var sdpLines = sdpLinesinit.reverse();
                        var labelstreamid = [];

                        for (let i = 0; i < sdpLines.length; i++) {

                             let cline = sdpLines[i];

		             if (cline.indexOf('a=label:') >= 0) {

				 let cLabelarr = cline.split(":");
                                 let clineMsid = sdpLines[parseInt(i)+1];
				 let cStreamIdinit = clineMsid.split(":");
				 let cStreamIdsec = cStreamIdinit[1].split(" ");

                                 let lblstrmObj = {'cLabel' : cLabelarr[1], 'cStreamId' : cStreamIdsec[0] };
                                 labelstreamid.push(lblstrmObj);
		             }
                        }
                         
                        // Store the channel id and the stream id
                        for (let n = 0; n < labelstreamid.length; n++) {

                             let Labelcr = labelstreamid[n]['cLabel'];
                             let StreamIdcr = labelstreamid[n]['cStreamId'];

                             if (Labelcr != '' && StreamIdcr != '' && Labelcr != 'undefined' && StreamIdcr != 'undefined' && Labelcr != null && StreamIdcr != null) {

                                 let streamChanObj = {'streamId': StreamIdcr, 'channelId': Labelcr};
                                 StreamChanTbl.push(streamChanObj);
                             }
                        }

		});

		bubble(rtc, 'muted');
		bubble(rtc, 'unmuted');
		bubble(rtc, 'failed');
		bubble(rtc, 'ended');

		rtc.connection.ontrack = function (event) {

			console.log('ontrack: ' + event.track.kind + ' - ' + event.track.id + ' stream ' + event.streams[0].id);

			if (event.track.kind == 'video') {
				event.track.enabled = false;
			}

			for (let i = 0; i < event.streams.length; ++i) {
				event.streams[i].local = false;
				that._remotes.add(event.streams[i]);
			}

                        ConferencePhone.prototype.resizeVideo(userCount);

			event.track.onended = function() {
                                --userCount;
                                ConferencePhone.prototype.resizeVideo(userCount);

                                console.log('ontrackended: remove stream ' + event.streams[0].id);
                                that._remotes.remove(event.streams[0]);

                                let cstrmId = event.streams[0].id;
                                try {
                                     let crMView = document.getElementById("new-media-view" + cstrmId + "");

                                     let mediaViews = document.getElementById("media-views");
                                     mediaViews.removeChild(crMView);
                                } catch(e) { return; };

			};
		};

		if (data.originator === "remote") {
			that.raise('incoming', data.request.ruri.toAor());
		}

	});

	this._ua.on('newMessage', function (data) {

	    if (data.originator === 'local') {
		return;
	    }

	    /* Grab the Content-Type header from the packet */
	    let ct = data.request.headers['Content-Type'][0].raw;

	    /* Make sure the message is one we care about */
            if (ct === 'application/x-asterisk-confbridge-event+json') {

		/* Parse the body back into an object */
		let msg = JSON.parse(data.request.body);

                var confMessageType = msg.type;
                var msChannels = msg.channels;

                for (let j = 0; j < msChannels.length; j++) {

                     let callerExtension = msChannels[j].caller.number;
                     let channelId = msChannels[j].id;
                     let channelName = msChannels[j].name;
                     localStorage[callerExtension] = channelName;

                     // Store the caller extension
                     if (callerExtension != '' && channelId != '' && callerExtension != 'undefined' && channelId != 'undefined' && callerExtension != null && channelId != null) {

                         let extenProfNmObj = {'channelId': channelId, 'extension': callerExtension};
                         ExtProNmTbl.push(extenProfNmObj);
                     }
                }

                // Highlight the video window of the person who is talking
                let callerExt = msg.channels[0].caller.number;
                if (confMessageType == "ConfbridgeTalking") {

                    let cMediaViewar = document.getElementsByName("cmv_"+callerExt);
                    let cMediaView = cMediaViewar[0];

                    if (cMediaView) {
                        let talkdet = document.getElementById("talk-detect-"+callerExt);
                        if (msg.channels[0].talking_status == "on") {
                            try{ talkdet.style.display = "inline"; } catch(e) { return; }
                        } else { try{ talkdet.style.display = "none"; } catch(e) { return; } }
                    }
                }

                if (confMessageType == "ConfbridgeLeave") {
                    let leaveName = msChannels[0].caller.name;
                    if (leaveName == '') {
                        ConferencePhone.prototype.resizeVideo(userCount);
                    } else { ++userCount; }
                }


            // Receive public conference message
	    } else if (ct === 'application/x-asterisk-confbridge-chat+json') {

		// Parse the body back into an object
		let textMsg = JSON.parse(data.request.body);

                let msTo = textMsg.To;

                if (msTo == '') {

                    let recMessageTime = new Date().toLocaleTimeString();

	            let newPubMessage = document.createElement("div");
                    newPubMessage.id = "recPubMessage";
                    newPubMessage.innerHTML = '<i class="fa fa-commenting" aria-hidden="true" title="New Public Message" style="color: #438be8;"></i>';                             

	            function decryptAES(message, key) {
			       var code = CryptoJS.AES.decrypt(message, key);
			       var decryptedMessage = code.toString(CryptoJS.enc.Utf8);
			       return decryptedMessage;
		    }


		    var encryptedtext = textMsg.Body;

		    var originalMessageArr = encryptedtext.split("|");

		    if (originalMessageArr[3] != '' && typeof originalMessageArr[3] != 'undefined' && originalMessageArr[3] != null) {
			var fileSentDuringChatVC = 1;
			var recFileNameVC = originalMessageArr[3];
		    } else {
			var fileSentDuringChatVC = 0;
			var recFileNameVC = '';
		    }

		    var currentMId = originalMessageArr[0];
		    var totalPieceNo = parseInt(originalMessageArr[1]);
		    var currentPieceNo = parseInt(originalMessageArr[2]);

                    if (encryptedtext != '') {

			// Reassemble the original message and decrypt it
			if (currentPieceNo == 0) {

			    if (splitMessageVC.hasOwnProperty(currentMId)) {

				  if (currentPieceNo == 0) {
				      var aesPayload = originalMessageArr[4];
				      var newdecrypt = new JSEncrypt();
				      newdecrypt.setPrivateKey(currentVconfPrivKey);
				      var decAESKeyCon = newdecrypt.decrypt(aesPayload);
				      splitMessageVC[currentMId].aeskeyandiv = decAESKeyCon;

				  } else {
				      splitMessageVC[currentMId][currentPieceNo] = originalMessageArr[4];
				  }

			    } else {

				  if (currentPieceNo == 0) {
				      var aesPayload = originalMessageArr[4];
				      var newdecrypt = new JSEncrypt();
				      newdecrypt.setPrivateKey(currentVconfPrivKey);
				      var decAESKeyCon = newdecrypt.decrypt(aesPayload);
				      splitMessageVC[currentMId] = { "aeskeyandiv": decAESKeyCon };

				  } else {
				     splitMessageVC[currentMId] = { [currentPieceNo]: originalMessageArr[4] };
				  }

			    }

			    return;

			} else if (currentPieceNo < (totalPieceNo - 1)) {

			       if (splitMessageVC.hasOwnProperty(currentMId)) {
				    splitMessageVC[currentMId][currentPieceNo] = originalMessageArr[4];
			       } else {
				    splitMessageVC[currentMId] = { [currentPieceNo]: originalMessageArr[4] };
			       }

			       return;

			} else if (currentPieceNo == (totalPieceNo - 1)) {

			       if (splitMessageVC.hasOwnProperty(currentMId)) {
				    splitMessageVC[currentMId][currentPieceNo] = originalMessageArr[4];
			       } else {
				    splitMessageVC[currentMId] = { [currentPieceNo]: originalMessageArr[4] };
			       }

			       if (Object.keys(splitMessageVC[currentMId]).length == totalPieceNo) {

				   var decryptAesKey = splitMessageVC[currentMId]["aeskeyandiv"];

				   delete splitMessageVC[currentMId]["aeskeyandiv"];
				   var origMessageEnc = '';
				   var orderedMPieces = Object.keys(splitMessageVC[currentMId]).sort().reduce(function(obj, key) { 
				       obj[key] = splitMessageVC[currentMId][key]; 
				       return obj;
				   },{});

				   Object.keys(orderedMPieces).forEach(function(key, index) {
				       origMessageEnc += splitMessageVC[currentMId][key];
				   });

				   var originalMessage = decryptAES(origMessageEnc, decryptAesKey);

				   delete splitMessageVC[currentMId];

			       } else { return; }
			}

                    }

                    let origMessageFormatted = ConferencePhone.prototype.ReformatVCMessage(originalMessage);

                    if (messageWindowState == 'closed') {

                        // Show a notification when the message arrives
		        if (window.localStorage.getItem("Notifications") == 1) {

			    function vcShowNotification() {
				var noticeOptions = { body: "New Public Message !!!", icon: "../images/notification-logo.svg" }
				var vcNotify = new Notification("Roundpin conference public message", noticeOptions);
				vcNotify.onclick = function() { vcNotify.close(); return; }

				if (vcDocIsVisible) { vcNotify.close(); return; } else { setTimeout(vcShowNotification, 8000); }
			    }

			    vcShowNotification();
		        }


                        $("#textChatBtn").click();

                        // Append the received message
                        if (originalMessage != '') {
                            $("#receiveTextMessage").append("<div class='textMessageReceived textMsgVConf'><span class='recMessageBtn' title='Send Private Message'>"+ textMsg.From +"</span><div class='srMsgVConfcont'>"+ origMessageFormatted +"</div><div class='messageDate'>"+ recMessageTime +"</div></div>");
                        }

                        // If a file is received, add the received file section
                        if (fileSentDuringChatVC == 1 && recFileNameVC != '') {

                            fileSentDuringChatVC = 0;
                            $("#receiveTextMessage").append("<div class='textMessageReceived textMsgVConf'><span class='recMessageBtn' title='Send Private Message'>"+ textMsg.From +"</span><div class='srMsgVConfcont'>Download file: <a href='../src/download-rec-chat-file-ext.php?sipusername="+ sip_username +"&encextenpass="+ encExtenPassEnc +"&recSipUser="+ videoConfExtension +"&recFlNm="+ recFileNameVC +"' target='_blank'>"+ recFileNameVC +"</a></div><div class='messageDate'>" + recMessageTime + "</div></div>");
                        }

                        let crMediaViews = document.getElementsByClassName("media-view");

		        if ($("#recPubMessage").length == 0) { crMediaViews[0].appendChild(newPubMessage); }

                        $("#minimizeImg").click();
                        messageWindowState = 'minimized';

                    } else if (messageWindowState == 'minimized') {

                        // Append the received message
                        if (originalMessage != '') {
                            $("#receiveTextMessage").append("<div class='textMessageReceived textMsgVConf'><span class='recMessageBtn' title='Send Private Message'>"+ textMsg.From +"</span><div class='srMsgVConfcont'>"+ origMessageFormatted +"</div><div class='messageDate'>"+ recMessageTime +"</div></div>");
                        }

                        // If a file is received, add the received file section
                        if (fileSentDuringChatVC == 1 && recFileNameVC != '') {

                            fileSentDuringChatVC = 0;
                            $("#receiveTextMessage").append("<div class='textMessageReceived textMsgVConf'><span class='recMessageBtn' title='Send Private Message'>"+ textMsg.From +"</span><div class='srMsgVConfcont'>Download file: <a href='../src/download-rec-chat-file-ext.php?sipusername="+ sip_username +"&encextenpass="+ encExtenPassEnc +"&recSipUser="+ videoConfExtension +"&recFlNm="+ recFileNameVC +"' target='_blank'>"+ recFileNameVC +"</a></div><div class='messageDate'>"+ recMessageTime +"</div></div>");
                        }

                        let crMediaViews = document.getElementsByClassName("media-view");

		        if ($("#recPubMessage").length == 0) { crMediaViews[0].appendChild(newPubMessage); }

                    } else {

                        // Append the received message
                        if (originalMessage != '') {
                            $("#receiveTextMessage").append("<div class='textMessageReceived textMsgVConf'><span class='recMessageBtn' title='Send Private Message'>"+ textMsg.From +"</span><div class='srMsgVConfcont'>"+ origMessageFormatted +"</div><div class='messageDate'>"+ recMessageTime +"</div></div>");
                        }

                        // If a file is received, add the received file section
                        if (fileSentDuringChatVC == 1 && recFileNameVC != '') {

                            fileSentDuringChatVC = 0;
                            $("#receiveTextMessage").append("<div class='textMessageReceived textMsgVConf'><span class='recMessageBtn' title='Send Private Message'>"+ textMsg.From +"</span><div class='srMsgVConfcont'>Download file: <a href='../src/download-rec-chat-file-ext.php?sipusername="+ sip_username +"&encextenpass="+ encExtenPassEnc +"&recSipUser="+ videoConfExtension +"&recFlNm="+ recFileNameVC +"' target='_blank'>"+ recFileNameVC +"</a></div><div class='messageDate'>"+ recMessageTime +"</div></div>");
                        }
                    }

                    $("#receiveTextMessage").scrollTop($("#receiveTextMessage")[0].scrollHeight);

                    let wTop = parseInt( ($(window).height() / 2) - 290 );
                    let wLeft = parseInt( ($(window).width() / 2) - 280 );
                    $("#recPubMessage").click(function() { $(this).remove(); messageWindowState = 'restored'; $("#publicTextMessages").css({ "width": 620, "height": 500, "top": wTop, "left": wLeft }); $("#restoreImg,#publicMessageImg").hide(); $("#maximizeImg,#pubMTopBar,#minimizeImg,#receiveTextMessage,#sendTMessage").show(); $("#receiveTextMessage").css("height", "54%"); $("#dragPubMessageWindow").css("top", "4px"); });
                }


            // Receive private message
	    } else {

	        let pmtextMsg = JSON.parse(data.request.body);
                let recPrivMessageTime = new Date().toLocaleTimeString();

                let cpmUserExt = data.request.headers.From[0].parsed._uri._user;
                let cpmUserFrom = pmtextMsg.From + " (" + cpmUserExt + ")";

	        let newPrivMessage = document.createElement("div");
                newPrivMessage.id = "recPrivMessage-"+ cpmUserExt +"";
                newPrivMessage.className = "recPrivMessage";
                newPrivMessage.innerHTML = "<i class='fa fa-commenting' aria-hidden='true' title='New Private Message' style='color: #28b6b6;'></i>";                             


	        function decryptAESpm(message, key) {
			       var code = CryptoJS.AES.decrypt(message, key);
			       var decryptedMessage = code.toString(CryptoJS.enc.Utf8);
			       return decryptedMessage;
		}

		var encryptedtextpm = pmtextMsg.Body;

	        var originalMessageArrpm = encryptedtextpm.split("|");

		if (originalMessageArrpm[3] != '' && typeof originalMessageArrpm[3] != 'undefined' && originalMessageArrpm[3] != null) {
			var fileSentDuringChatVCpm = 1;
			var recFileNameVCpm = originalMessageArrpm[3];
		} else {
			var fileSentDuringChatVCpm = 0;
			var recFileNameVCpm = '';
		}

		var currentMIdpm = originalMessageArrpm[0];
		var totalPieceNopm = parseInt(originalMessageArrpm[1]);
		var currentPieceNopm = parseInt(originalMessageArrpm[2]);

                if (encryptedtextpm != '') {

			// Reassemble the original message and decrypt it
			if (currentPieceNopm == 0) {

			    if (splitMessageVCpm.hasOwnProperty(currentMIdpm)) {

				  if (currentPieceNopm == 0) {
				      var aesPayload = originalMessageArrpm[4];
				      var newdecrypt = new JSEncrypt();
				      newdecrypt.setPrivateKey(crVConfUserPrivKey);
				      var decAESKeyCon = newdecrypt.decrypt(aesPayload);
				      splitMessageVCpm[currentMIdpm].aeskeyandiv = decAESKeyCon;

				  } else {
				      splitMessageVCpm[currentMIdpm][currentPieceNopm] = originalMessageArrpm[4];
				  }

			    } else {

				  if (currentPieceNopm == 0) {
				      var aesPayload = originalMessageArrpm[4];
				      var newdecrypt = new JSEncrypt();
				      newdecrypt.setPrivateKey(crVConfUserPrivKey);
				      var decAESKeyCon = newdecrypt.decrypt(aesPayload);
				      splitMessageVCpm[currentMIdpm] = { "aeskeyandiv": decAESKeyCon };

				  } else {
				     splitMessageVCpm[currentMIdpm] = { [currentPieceNopm]: originalMessageArrpm[4] };
				  }

			    }

			    return;

			} else if (currentPieceNopm < (totalPieceNopm - 1)) {

			       if (splitMessageVCpm.hasOwnProperty(currentMIdpm)) {
				    splitMessageVCpm[currentMIdpm][currentPieceNopm] = originalMessageArrpm[4];
			       } else {
				    splitMessageVCpm[currentMIdpm] = { [currentPieceNopm]: originalMessageArrpm[4] };
			       }

			       return;

			} else if (currentPieceNopm == (totalPieceNopm - 1)) {

			       if (splitMessageVCpm.hasOwnProperty(currentMIdpm)) {
				    splitMessageVCpm[currentMIdpm][currentPieceNopm] = originalMessageArrpm[4];
			       } else {
				    splitMessageVCpm[currentMIdpm] = { [currentPieceNopm]: originalMessageArrpm[4] };
			       }

			       if (Object.keys(splitMessageVCpm[currentMIdpm]).length == totalPieceNopm) {

				   var decryptAesKeypm = splitMessageVCpm[currentMIdpm]["aeskeyandiv"];

				   delete splitMessageVCpm[currentMIdpm]["aeskeyandiv"];
				   var origMessageEncpm = '';
				   var orderedMPieces = Object.keys(splitMessageVCpm[currentMIdpm]).sort().reduce(function(obj, key) { 
				       obj[key] = splitMessageVCpm[currentMIdpm][key]; 
				       return obj;
				   },{});

				   Object.keys(orderedMPieces).forEach(function(key, index) {
				       origMessageEncpm += splitMessageVCpm[currentMIdpm][key];
				   });

				   var originalMessagepm = decryptAESpm(origMessageEncpm, decryptAesKeypm);

				   delete splitMessageVCpm[currentMIdpm];

			       } else { return; }
			}

                }

                let origMessageFormattedpm = ConferencePhone.prototype.ReformatVCMessage(originalMessagepm);


                if (typeof messageWindowStatePM[cpmUserExt] == 'undefined' || messageWindowStatePM[cpmUserExt] == null || messageWindowStatePM[cpmUserExt] == 'closed') {

                        // Show a notification when the message arrives
		        if (window.localStorage.getItem("Notifications") == 1) {

			    function vcPMShowNotification() {
				var noteOptions = { body: "New Private Message !!!", icon: "../images/notification-logo.svg" }
				var vcPMNotify = new Notification("Roundpin conference private message", noteOptions);
				vcPMNotify.onclick = function() { vcPMNotify.close(); return; }

				if (vcDocIsVisible) { vcPMNotify.close(); return; } else { setTimeout(vcPMShowNotification, 8000); }
			    }

			    vcPMShowNotification();
		        }


                        ConferencePhone.prototype.openPrivateMessageWindow(cpmUserFrom, cpmUserExt);

                        if (origMessageFormattedpm != '') {
                            $("#receiveTextMessagePM-"+ cpmUserExt +"").append("<div class='textMessageReceivedPM textMsgVConf'><span class='recMessageBtnPM'>" + cpmUserFrom + ":</span><div class='srMsgVConfcont'>" + origMessageFormattedpm + "</div><div class='messageDate'>" + recPrivMessageTime + "</div></div>");
                        }

                        // If a file is received, add the received file section
                        if (fileSentDuringChatVCpm == 1 && recFileNameVCpm != '') {

                            fileSentDuringChatVCpm = 0;
                            $("#receiveTextMessagePM-"+ cpmUserExt +"").append("<div class='textMessageReceivedPM textMsgVConf'><span class='recMessageBtnPM' title='Send Private Message'>"+ cpmUserFrom +":</span><div class='srMsgVConfcont'>Download file: <a href='../src/download-rec-chat-file-pm-ext.php?sipusername="+ sip_username +"&encextenpass="+ encExtenPassEnc +"&conferenceext="+ videoConfExtension +"&recSipUser="+ sip_username +"&recFlNm="+ recFileNameVCpm +"' target='_blank'>"+ recFileNameVCpm +"</a></div><div class='messageDate'>" + recPrivMessageTime + "</div></div>");
                        }

                        let crMediaViews = document.getElementsByClassName("media-view");

		        if ($("#recPrivMessage-"+ cpmUserExt +"").length == 0) { crMediaViews[0].appendChild(newPrivMessage); }

                        $("#minimizeImgPM-"+ cpmUserExt +"").click();
                        messageWindowStatePM[cpmUserExt] = 'minimized';

                } else if (messageWindowStatePM[cpmUserExt] == 'minimized') {

                        if (origMessageFormattedpm != '') {
                            $("#receiveTextMessagePM-"+ cpmUserExt +"").append("<div class='textMessageReceivedPM textMsgVConf'><span class='recMessageBtnPM'>" + cpmUserFrom + ":</span><div class='srMsgVConfcont'>" + origMessageFormattedpm + "</div><div class='messageDate'>" + recPrivMessageTime + "</div></div>");
                        }

                        // If a file is received, add the received file section
                        if (fileSentDuringChatVCpm == 1 && recFileNameVCpm != '') {

                            fileSentDuringChatVCpm = 0;
                            $("#receiveTextMessagePM-"+ cpmUserExt +"").append("<div class='textMessageReceivedPM textMsgVConf'><span class='recMessageBtnPM' title='Send Private Message'>"+ cpmUserFrom +":</span><div class='srMsgVConfcont'>Download file: <a href='../src/download-rec-chat-file-pm-ext.php?sipusername="+ sip_username +"&encextenpass="+ encExtenPassEnc +"&conferenceext="+ videoConfExtension +"&recSipUser="+ sip_username +"&recFlNm="+ recFileNameVCpm +"' target='_blank'>"+ recFileNameVCpm +"</a></div><div class='messageDate'>" + recPrivMessageTime + "</div></div>");
                        }

                        let crMediaViews = document.getElementsByClassName("media-view");

		        if ($("#recPrivMessage-"+ cpmUserExt +"").length == 0) { crMediaViews[0].appendChild(newPrivMessage); }

                } else {

                        if (origMessageFormattedpm != '') {
                            $("#receiveTextMessagePM-"+ cpmUserExt +"").append("<div class='textMessageReceivedPM textMsgVConf'><span class='recMessageBtnPM'>" + cpmUserFrom + ":</span><div class='srMsgVConfcont'>" + origMessageFormattedpm + "</div><div class='messageDate'>" + recPrivMessageTime + "</div></div>");
                        }

                        // If a file is received, add the received file section
                        if (fileSentDuringChatVCpm == 1 && recFileNameVCpm != '') {

                            fileSentDuringChatVCpm = 0;
                            $("#receiveTextMessagePM-"+ cpmUserExt +"").append("<div class='textMessageReceivedPM textMsgVConf'><span class='recMessageBtnPM' title='Send Private Message'>"+ cpmUserFrom +":</span><div class='srMsgVConfcont'>Download file: <a href='../src/download-rec-chat-file-pm-ext.php?sipusername="+ sip_username +"&encextenpass="+ encExtenPassEnc +"&conferenceext="+ videoConfExtension +"&recSipUser="+ sip_username +"&recFlNm="+ recFileNameVCpm +"' target='_blank'>"+ recFileNameVCpm +"</a></div><div class='messageDate'>" + recPrivMessageTime + "</div></div>");
                        }
                }

                $("#receiveTextMessagePM-"+ cpmUserExt +"").scrollTop($("#receiveTextMessagePM-"+ cpmUserExt +"")[0].scrollHeight);

                let pmwTop = parseInt( ($(window).height() / 2) - 305 );
                let pmwLeft = parseInt( ($(window).width() / 2) - 245 );
                $("#recPrivMessage-"+ cpmUserExt +"").click(function() { $(this).remove(); messageWindowStatePM[cpmUserExt] = 'restored'; $("#pmtextMessage-"+ cpmUserExt +"").css({ "width": 610, "height": 490, "top": pmwTop, "left": pmwLeft }); $("#restoreImgPM-"+ cpmUserExt +"").hide(); $("#maximizeImgPM-"+ cpmUserExt +"").show(); $("#minimizeImgPM-"+ cpmUserExt +"").show(); $("#receiveTextMessagePM-"+ cpmUserExt +"").css("height", "54%"); $("#recPrivMessage-"+ cpmUserExt +"").remove(); $("#pmTopBar-"+ cpmUserExt +"").show(); $("#receiveTextMessagePM-"+ cpmUserExt +"").show(); $("#sendTMessagePM-"+ cpmUserExt +"").show(); $("#privateMessageImg-"+ cpmUserExt +"").hide(); $("#topDragArea-"+ cpmUserExt +"").css("top", "4px"); });

            }

	});

	this._ua.start();
};

ConferencePhone.prototype.disconnect = function () {
	this._locals.removeAll();
	this._remotes.removeAll();
	if (this._ua) {
		this._ua.stop();
	}
};

ConferencePhone.prototype.answer = function () {

	if (!this._ua) {
		return;
	}

	let options = {
		'mediaConstraints': { 'audio': this.audio, 'video': this.video }
	};

	this._rtc.answer(options);
};

ConferencePhone.prototype.call = function (exten) {

	if (!this._ua || !exten) {
		return;
	}

	let options = {
		'mediaConstraints': { 'audio': this.audio, 'video': this.video }
        };

	if (exten.startsWith('sip:')) {
		this._rtc = this._ua.call(exten, options);
	} else {
		this._rtc = this._ua.call('sip:' + exten + '@' + this.host, options);
	}
};

ConferencePhone.prototype.callToKick = function (extentrm, confExtAndChannel) {

	if (!this._ua || !extentrm) {
		return;
	}

	let ctkoptions = {
                'extraHeaders': [ 'X-Removeuser: ' + confExtAndChannel ],
		'mediaConstraints': { 'audio': true, 'video': false }
        };

	if (extentrm.startsWith('sip:')) {
		this._rtc = this._ua.call(extentrm, ctkoptions);
	} else {
		this._rtc = this._ua.call('sip:' + extentrm + '@' + this.host, ctkoptions);
	}
};

ConferencePhone.prototype.terminate = function () {
	this._locals.removeAll();
	this._remotes.removeAll();
	if (this._ua) {
		this._rtc.terminate();
	}
};

// Send message to all video conference participants (public message)
ConferencePhone.prototype.sendConfMessage = function (messageString, options) {

    function splitString(str, size) {
        const vcnfmPieces = Math.ceil(str.length / size);
        const vcnfpiecesArr = [];

        for (let i = 0, s = 0; i < vcnfmPieces; ++i, s += size) {
             vcnfpiecesArr[i] = str.substr(s, size);
        }
        return vcnfpiecesArr;
    }

    function generateAESKey(passphrase) {
        const salt = CryptoJS.lib.WordArray.random(128 / 8);
        const key256Bits = CryptoJS.PBKDF2(passphrase, salt, {
          keySize: 256 / 32,
          iterations: 100,
        });
        return key256Bits;
    }

    function encryptAES(message, key) {
        var message = CryptoJS.AES.encrypt(message, key);
        return message.toString();
    }

    // Encrypt the message
    var genCnfPassphr = Date.now() + Math.floor(Math.random()*10000).toString(6).toUpperCase();
    var confAESKey = String(generateAESKey(genCnfPassphr));
    var encryptedConfMes = encryptAES(messageString, confAESKey);

    // Split the encrypted message into smaller pieces to fit the 1024 byte limit for SIP messages, which is hard-coded in Asterisk
    var messageprevcnfarr = splitString(encryptedConfMes, 850);

    var genMessageId = Date.now() + Math.floor(Math.random()*10000).toString(16).toUpperCase();
    var messageIdent = genMessageId + sip_username;

    // Get the public key of the current video conference extension
    $.ajax({
      type: "POST",
      url: "../src/get-text-chat-vconf-pub-key-ext.php",
      dataType: "JSON",
      data: {
	     crntvconfext: videoConfExtension,
	     vconfextension: sip_username,
	     encextenpass: encExtenPass
      },
      success: function(result) {

                if (result.resmessage == 'success') {

                    var destExtChatRSAPubKey = "`" + result.chatkey.join("") + "`";

		    // Encrypt the AES key with RSA
		    var newvcnfencrypt = new JSEncrypt();
		    newvcnfencrypt.setPublicKey(destExtChatRSAPubKey);
		    var encvcnfmIdAesKey = newvcnfencrypt.encrypt(confAESKey);

		    // Add the encrypted AES key as the first element of the array of message pieces
		    messageprevcnfarr.unshift(encvcnfmIdAesKey);

		    // Send the message pieces
		    for (var k = 0; k < messageprevcnfarr.length; k++) {

		         if (k == 0) {
			     // Send the RSA-encrypted AES key as the first piece of the message
			     var messagePiece = messageIdent + "|" + messageprevcnfarr.length + "|" + parseInt(k) + "||" + messageprevcnfarr[k];	
			 } else if (sendFileCheckVC == 0 && messageprevcnfarr[k] != '') {
			     var messagePiece = messageIdent + "|" + messageprevcnfarr.length + "|" + parseInt(k) + "||" + messageprevcnfarr[k];
			 } else if (sendFileCheckVC == 1 && sendFileChatErrVC == '') {
			     var messagePiece = messageIdent + "|" + messageprevcnfarr.length + "|" + parseInt(k) + "|" + upFileNameVC + "|" + messageprevcnfarr[k];
			 } else if (sendFileCheckVC == 1 && sendFileChatErrVC != '') {
			     $("#sendFileFormChatVC").remove();
			     sendFileChatErrVC = '';
			     sendFileCheckVC = 0;
			     return;
			 }

			 let msg = {
				'From': options.From,
				'To': options.To,
				'Body': messagePiece
			 };

			 let msgBody = JSON.stringify(msg);

			 let extraHeaders = [ 'Content-Type: application/x-asterisk-confbridge-chat+json' ];

			 currentSession[0].sendRequest(JsSIP.C.MESSAGE, {
				extraHeaders,
				body: msgBody,
				eventHandlers: options.handlers
			 });

		    }

                } else {
                        alert('An error occurred while retrieving the public key for text chat!');
                }

                sendFileCheckVC = 0;
                $("#receiveTextMessage").scrollTop($("#receiveTextMessage")[0].scrollHeight);
      },
      error: function(result) {
                      alert('An error occurred while attempting to retrieve the public key for text chat!');
      }
    });
 
}

// Open private message window
ConferencePhone.prototype.openPrivateMessageWindow = function (privMessageUser, privMExten) {

                                   sendFileCheckVCpm[privMExten] = 0;
                                   upFileNameVCpm[privMExten] = '';

				   var privchathtml = "<div id='pmtextMessage-"+ privMExten +"' class='textMessagesPM'>";
                                   privchathtml += "<div id='windowCtrlsPM-"+ privMExten +"' class='windowCtrlsPM'><img id='closeImgPM-"+ privMExten +"' class='closeImgPM' src='../images/3_close.svg' title='Close'><img id='maximizeImgPM-"+ privMExten +"' class='maximizeImgPM' src='../images/2_maximize.svg' title='Maximize'><img id='restoreImgPM-"+ privMExten +"' class='restoreImgPM' src='../images/4_restore.svg' title='Restore'><img id='minimizeImgPM-"+ privMExten +"' class='minimizeImgPM' src='../images/1_minimize.svg' title='Minimize'><img id='privateMessageImg-"+ privMExten +"' class='privateMessageImg' src='../images/PrivateMessage.svg' title='Private Message'></div>"; 
                                   privchathtml += "<div id='topDragArea-"+ privMExten +"' style=\"display:block;position:absolute;width:100%;height:10px;top:4px;text-align:center;z-index:20;\"><i id=\"dragPrivMessageWindow\" class=\"fa fa-ellipsis-h\" aria-hidden=\"true\" title=\"Drag Button\" style=\"display:block;position:relative;margin: 0px auto;color:#d0d0d0;font-size:17px;cursor:grab;\"></i></div>";
				   privchathtml += "<div id='pmTopBar-"+ privMExten +"' class='pmTopBar'><img src='../images/small-logo.svg' style='display:block;position:relative;margin: 7px auto 0px auto;padding-left:80px;user-select: none;pointer-events: none;'><span style='display:inline-block;margin: 0px;font-weight:600;color:#248d8d;user-select: none;'>Private Text Messaging - "+ privMessageUser +"</span></div>";
				   privchathtml += "<div id='receiveTextMessagePM-"+ privMExten +"' class='receiveTextMessagePM'><div id='downloadVConfHst-"+ privMExten +"' class='downloadVConfHstPM' title='Download Text Conversation'><i class='fa fa-download'></i></div></div>";
                                   privchathtml += "<div id='emojiMenuPM-"+ privMExten +"' class='emojiMenuPM'></div>";
                                   privchathtml += "<div id='sendTMessagePM-"+ privMExten +"' class='sendTMessagePM'><table cellspacing='0' cellpadding='0' class='sendMessageTblPM'><tr><td style='height: 100%;width: 100%;'><textarea id='sendTextMessagePM-"+ privMExten +"' class='chatMessagePM' placeholder='Type the message here, then click the paper plane button or press Ctrl + Enter to send it.'></textarea></td>";
                                   privchathtml += "<td style='display:block;width:36px;margin:0px;'><button id='sendTextChatBtnPM-"+ privMExten +"' class='roundButtonsSpec' title='Send Message'><i class='fa fa-paper-plane-o' aria-hidden='true'></i></button>";
                                   privchathtml += "<button id='selectEmoticonPM-"+ privMExten +"' class='roundButtonsSpec' title='Select Emoticon'><i class='fa fa-smile-o'></i></button>";
                                   privchathtml += "<button id='sendFileVCPM-"+ privMExten +"' class='roundButtonsSpec' title='Send File'><i class='fa fa-file-text-o'></i></button></td></tr></table></div>";
				   privchathtml += "</div>";

                                   $("#media-views").append(privchathtml);
                                   $("#pmtextMessage-"+ privMExten +"").css("display", "block");

                                   $("#restoreImgPM-"+ privMExten +"").hide();
				   $("#sendTextMessagePM-"+ privMExten +"").focus();
                                   messageWindowStatePM[privMExten] = 'restored';
                                   $("#publicTextMessages").css("z-index", 18);

                                   // Bring window forward when clicking on it
                                   $('[id^="pmtextMessage-"]').click(function() { 
                                      $(".textMessagesPM").each(function() { $(this).css("z-index", 19); });
                                      $("#publicTextMessages").css("z-index", 18);
                                      $(this).css("z-index", 20);
                                   });

                                   // Make the window draggable
				   function makeDraggable(e){

				       window.pmdragging = {};
				       pmdragging.pageX0 = e.pageX;
				       pmdragging.pageY0 = e.pageY;
                                       pmdragging.elem = $("#pmtextMessage-"+ privMExten +"");
                                       pmdragging.offset0 = $("#pmtextMessage-"+ privMExten +"").offset();

				       function handle_dragging(e) {
					   var left = pmdragging.offset0.left + (e.pageX - pmdragging.pageX0);
					   var top = pmdragging.offset0.top + (e.pageY - pmdragging.pageY0);
					   $(pmdragging.elem).offset({top: top, left: left});
				       }

				       function handle_mouseup(e) {
					   $('body').off('mousemove', handle_dragging).off('mouseup', handle_mouseup);
				       }

				       $('body').on('mouseup', handle_mouseup).on('mousemove', handle_dragging);
				   }

                                   $("#topDragArea-"+ privMExten +"").mousedown(makeDraggable);

                                   // Show emoji menu
                                   $("#selectEmoticonPM-"+ privMExten +"").click(function() {

				       var messageContainerPM = $("#emojiMenuPM-"+ privMExten +"");
				       var textareaPM = $("#sendTextMessagePM-"+ privMExten +"");

				       if (messageContainerPM.is(":visible")) { messageContainerPM.hide(); } else { messageContainerPM.show(); }

				       var menuBarPM = $("<div>");
				       menuBarPM.prop("class", "emojiButton")
				       var emojisPM = ["😀","😁","😂","😃","😄","😅","😆","😊","😦","😉","😊","😋","😌","😍","😎","😏","😐","😑","😒","😓","😔","😕","😖","😗","😘","😙","😚","😛","😜","😝","😞","😟","😠","😡","😢","😣","😤","😥","😦","😧","😨","😩","😪","😫","😬","😭","😮","😯","😰","😱","😲","😳","😴","😵","😶","😷","🙁","🙂","🙃","🙄","🤐","🤑","🤒","🤓","🤔","🤕","🤠","🤡","🤢","🤣","🤤","🤥","🤧","🤨","🤩","🤪","🤫","🤬","🤭","🤯","🤗","🧐"];
				       $.each(emojisPM, function(i,e){
					       var emojiPM = $("<button>");
					       emojiPM.html(e);
					       emojiPM.on('click', function() {
						    var i = textareaPM.prop('selectionStart');
						    var v = textareaPM.val();
						    textareaPM.val(v.substring(0, i) + " " + $(this).html() + v.substring(i, v.length) + " ");

						    messageContainerPM.hide();
						    textareaPM.focus();
					       });
					       menuBarPM.append(emojiPM);
				       });

				       $("#sendTextMessagePM-"+ privMExten +",#receiveTextMessagePM-"+ privMExten +"").on('click', function() {
				          messageContainerPM.hide();
				       });

				       messageContainerPM.empty();
				       messageContainerPM.append(menuBarPM);
                                   });

				   // Show the 'Download Text Conversation' button
				   $("#receiveTextMessagePM-"+ privMExten +"").mouseenter(function() {
				      $("#downloadVConfHst-"+ privMExten +"").css("display", "block");
				   });
				   $("#receiveTextMessagePM-"+ privMExten +"").mouseleave(function() {
				      $("#downloadVConfHst-"+ privMExten +"").css("display", "none");
				   });

				   // Download chat history
				   $("#downloadVConfHst-"+ privMExten +"").click(function() { phone.DownloadChatHistoryVCPM(videoConfExtension, videoConfTag, privMExten, privMessageUser); });

				   function splitString(str, size) {
					const vcnfmPieces = Math.ceil(str.length / size);
					const vcnfpiecesArr = [];

					for (let i = 0, s = 0; i < vcnfmPieces; ++i, s += size) {
					     vcnfpiecesArr[i] = str.substr(s, size);
					}
					return vcnfpiecesArr;
				   }

				   function generateAESKey(passphrase) {
					const salt = CryptoJS.lib.WordArray.random(128 / 8);
					const key256Bits = CryptoJS.PBKDF2(passphrase, salt, {
					  keySize: 256 / 32,
					  iterations: 100,
					});
					return key256Bits;
				   }

				   function encryptAES(message, key) {
					var message = CryptoJS.AES.encrypt(message, key);
					return message.toString();
				   }

				   function sendPrivMessage(targetUserPM, textToSendPM) {

			               // When a file is sent
                                       if (sendFileCheckVCpm[privMExten] == 1) {

                                             sendFileChatErrVCpm[privMExten] = '';

                                             $("#sendFileFormChatVCPM-"+ privMExten +"").on('submit', function(ev) {

				                   ev.preventDefault();

                                                   $("#receiveTextMessagePM-"+ privMExten +"").after("<span id='sendFileLoaderVCPM'></span>");

						   $.ajax({
							type: 'POST',
							url: '../src/text-chat-vconf-upload-file-pm-ext.php',
							data: new FormData(this),
							dataType: "JSON",
							contentType: false,
							cache: false,
							processData: false,
							success: function(respdata) { 

								   if (respdata.error != '') {

                                                                       sendFileChatErrVCpm[privMExten] = respdata.error;
								       $("#sendFileFormChatVCPM-"+ privMExten +"").remove();
								       $("#sendFileLoaderVCPM").remove();
								       sendFileCheckVCpm[privMExten] = 0;
								       alert("Error: " + respdata.error);

								   } else {

								       // Encrypt the message
								       var genCnfPassphr = Date.now() + Math.floor(Math.random()*10000).toString(6).toUpperCase();
								       var confAESKey = String(generateAESKey(genCnfPassphr));
								       var encryptedConfMes = encryptAES(textToSendPM, confAESKey);

								       // Split the encrypted message into smaller pieces to fit the 1024 byte limit for SIP messages, which is hard-coded in Asterisk
								       var messageprevcnfarrpm = [];
								       var messageprevcnfarrpm = splitString(encryptedConfMes, 850);

								       var genMessageIdpm = Date.now() + Math.floor(Math.random()*10000).toString(16).toUpperCase();
								       var messageIdentpm = genMessageIdpm + privMExten;

								       // Get the public key of the other conference participant
								       $.ajax({
									 type: "POST",
									 url: "../src/get-text-chat-pub-key-ext.php",
									 dataType: "JSON",
									 data: { 
									     recsendsipuser: privMExten,
	                                                                     vconfextension: sip_username,
	                                                                     encextenpass: encExtenPass,
                                                                             conferenceext: videoConfExtension
									 },
									 success: function(result) {

										    if (result.resmessage == 'success') {

											var destExtRSAPubKey = "`" + result.chatkey.join("") + "`";

											// Encrypt the AES key with RSA
											var newvcnfencryptpm = new JSEncrypt();
											newvcnfencryptpm.setPublicKey(destExtRSAPubKey);
											var encvcnfmIdAesKeypm = newvcnfencryptpm.encrypt(confAESKey);

											// Add the encrypted AES key as the first element of the array of message pieces
											messageprevcnfarrpm.unshift(encvcnfmIdAesKeypm);

											// Send the message pieces
											for (var k = 0; k < messageprevcnfarrpm.length; k++) {

											     if (k == 0) {
												 // Send the RSA-encrypted AES key as the first piece of the message
												 var messagePiecePM = messageIdentpm + "|" + messageprevcnfarrpm.length + "|" + parseInt(k) + "||" + messageprevcnfarrpm[k];
											     } else if (sendFileChatErrVCpm[privMExten] == '') {
												 var messagePiecePM = messageIdentpm + "|" + messageprevcnfarrpm.length + "|" + parseInt(k) + "|" + upFileNameVCpm[privMExten] + "|" + messageprevcnfarrpm[k];
											     } else if (sendFileChatErrVCpm[privMExten] != '') {
												 $("#sendFileFormChatVCPM-"+ privMExten +"").remove();
												 sendFileChatErrVCpm[privMExten] = '';
												 sendFileCheckVCpm[privMExten] = 0;
												 return;
											     }

					                                                     let messageincfrObj = { "From": profileName, "Body": messagePiecePM };
					                                                     let messageincfr = JSON.stringify(messageincfrObj);
											     strtdUA.sendMessage(targetUserPM, messageincfr);
								                        }


										        if (textToSendPM.trim() != '' && sendFileChatErrVCpm[privMExten] == '') {
                                      
											    let currentTimePM = new Date().toLocaleTimeString();
											    $("#sendTextMessagePM-"+ privMExten +"").val("");
											    $("#receiveTextMessagePM-"+ privMExten +"").append("<div class='textMessageSentPM textMsgVConf'><span class='sentMessageBtnPM'>" + profileName + " (" + sip_username + "):</span><div class='srMsgVConfcont'>" + textToSendPM + "</div><div class='messageDate'>" + currentTimePM + "<i class='fa fa-check sentMsTick' title='No errors on message sending'></i></div></div>");

											    // Append the 'Download file' section
											    let currentflTimePM = new Date().toLocaleTimeString();
											    $("#receiveTextMessagePM-"+ privMExten +"").append("<div class='textMessageSentPM textMsgVConf'><span class='sentMessageBtnPM'>"+ profileName +" ("+ sip_username +"):</span><div class='srMsgVConfcont'>Download file: <a href='../src/download-sent-chat-file-pm-ext.php?sipusername="+ sip_username +"&encextenpass="+ encExtenPassEnc +"&conferenceext="+ videoConfExtension +"&destSipUser="+ privMExten +"&sentFlNm="+ upFileNameVCpm[privMExten] +"' target='_blank'>"+ upFileNameVCpm[privMExten] +"</a></div><div class='messageDate'>"+ currentflTimePM +"</div></div>");

											    $("#sendFileFormChatVCPM-"+ privMExten +"").remove();
											    $("#sendFileLoaderVCPM").remove();

										        } else if (textToSendPM.trim() == '' && sendFileChatErrVCpm[privMExten] == '') {

											    // Append the 'Download file' section
											    let currentflTimePM = new Date().toLocaleTimeString();
											    $("#receiveTextMessagePM-"+ privMExten +"").append("<div class='textMessageSentPM textMsgVConf'><span class='sentMessageBtnPM'>"+ profileName +" ("+ sip_username +"):</span><div class='srMsgVConfcont'>Download file: <a href='../src/download-sent-chat-file-pm-ext.php?sipusername="+ sip_username +"&encextenpass="+ encExtenPassEnc +"&conferenceext="+ videoConfExtension +"&destSipUser="+ privMExten +"&sentFlNm="+ upFileNameVCpm[privMExten] +"' target='_blank'>"+ upFileNameVCpm[privMExten] +"</a></div><div class='messageDate'>"+ currentflTimePM +"</div></div>");

											    $("#sendFileFormChatVCPM-"+ privMExten +"").remove();
											    $("#sendFileLoaderVCPM").remove();
										        }

											$("#receiveTextMessagePM-"+ privMExten +"").scrollTop($("#receiveTextMessagePM-"+ privMExten +"")[0].scrollHeight);
										        $("#sendFileLoaderVCPM").remove();
											
										    } else {
											alert('An error occurred while retrieving the public key for text chat!');
										    }

								                    sendFileCheckVCpm[privMExten] = 0;
									 },
									 error: function(result) {
								                        alert('An error occurred while attempting to retrieve the public key for text chat!');
									 }
								       });

                                                                       $("#sendFileFormChatVCPM-"+ privMExten +"").remove();
                                                                       $("#sendFileLoaderVCPM").remove();
                                                                   }

							},
							error: function(respdata) {
								    $("#sendFileFormChatVCPM-"+ privMExten +"").remove();
								    $("#sendFileLoaderVCPM").remove();
								    alert("An error occurred while sending the file!");
							}  
						   });

                                             });

                                             $("#sendFileFormChatVCPM-"+ privMExten +"").submit();

                                       } else {

					       // Encrypt the message
					       var genCnfPassphr = Date.now() + Math.floor(Math.random()*10000).toString(6).toUpperCase();
					       var confAESKey = String(generateAESKey(genCnfPassphr));
					       var encryptedConfMes = encryptAES(textToSendPM, confAESKey);

					       // Split the encrypted message into smaller pieces to fit the 1024 byte limit for SIP messages, which is hard-coded in Asterisk
					       var messageprevcnfarrpm = [];
					       var messageprevcnfarrpm = splitString(encryptedConfMes, 850);

					       var genMessageIdpm = Date.now() + Math.floor(Math.random()*10000).toString(16).toUpperCase();
					       var messageIdentpm = genMessageIdpm + privMExten;

					       // Get the public key of the other conference participant
					       $.ajax({
						 type: "POST",
						 url: "../src/get-text-chat-pub-key-ext.php",
						 dataType: "JSON",
						 data: { 
						     recsendsipuser: privMExten,
			                             vconfextension: sip_username,
			                             encextenpass: encExtenPass,
                                                     conferenceext: videoConfExtension
						 },
						 success: function(result) {

							    if (result.resmessage == 'success') {

								var destExtRSAPubKey = "`" + result.chatkey.join("") + "`";

								// Encrypt the AES key with RSA
								var newvcnfencryptpm = new JSEncrypt();
								newvcnfencryptpm.setPublicKey(destExtRSAPubKey);
								var encvcnfmIdAesKeypm = newvcnfencryptpm.encrypt(confAESKey);

								// Add the encrypted AES key as the first element of the array of message pieces
								messageprevcnfarrpm.unshift(encvcnfmIdAesKeypm);

								// Send the message pieces

                                                                if (textToSendPM.trim() != '') {

                                                                    let privMsErrWf = 0;

								    for (var k = 0; k < messageprevcnfarrpm.length; k++) {

								         if (k == 0) {
									     // Send the RSA-encrypted AES key as the first piece of the message
									     var messagePiecePM = messageIdentpm + "|" + messageprevcnfarrpm.length + "|" + parseInt(k) + "||" + messageprevcnfarrpm[k];	
								         } else if (messageprevcnfarrpm[k] != '') {
									     var messagePiecePM = messageIdentpm + "|" + messageprevcnfarrpm.length + "|" + parseInt(k) + "||" + messageprevcnfarrpm[k];
								         }

					                                 let messageincfrObj = { "From": profileName, "Body": messagePiecePM };
					                                 let messageincfr = JSON.stringify(messageincfrObj);
								         try { strtdUA.sendMessage(targetUserPM, messageincfr); } catch(ersm) { privMsErrWf++; alert("Error when sending message: "+ ersm); }
		                                                    }

                                                                    if (privMsErrWf == 0) {
                                                                        let currentTimePM = new Date().toLocaleTimeString();
                                                                        $("#sendTextMessagePM-"+ privMExten +"").val("");
                                                                        $("#receiveTextMessagePM-"+ privMExten +"").append("<div class='textMessageSentPM textMsgVConf'><span class='sentMessageBtnPM'>" + profileName + " (" + sip_username + "):</span><div class='srMsgVConfcont'>" + textToSendPM + "</div><div class='messageDate'>" + currentTimePM + "<i class='fa fa-check sentMsTick' title='No errors on message sending'></i></div></div>"); 
                                                                        $("#receiveTextMessagePM-"+ privMExten +"").scrollTop($("#receiveTextMessagePM-"+ privMExten +"")[0].scrollHeight);
                                                                    }
                                                                }
								
							    } else {
								alert('An error occurred while retrieving the public key for text chat!');
							    }
						 },
						 error: function(result) {
		                                                alert('An error occurred while attempting to retrieve the public key for text chat!');
						 }
					       });

                                       }

				   }

                                   // Send private message by clicking the "Send Message" button
				   $("#sendTextChatBtnPM-"+ privMExten +"").click(function() {

                                      var textToSendPM = $("#sendTextMessagePM-"+ privMExten +"").val();
                                      var targetUserPM = "sip:"+ privMExten +"@"+ wss_server +"";

                                      sendPrivMessage(targetUserPM, textToSendPM);

                                   });

                                   // Send private message by pressing Ctrl + Enter
                                   $("#sendTextMessagePM-"+ privMExten +"").keydown(function() {
				       var keycode = (event.keyCode ? event.keyCode : event.which);
				       if (keycode == '13') {
				           if (event.ctrlKey) {

                                               var textToSendPM = $("#sendTextMessagePM-"+ privMExten +"").val();
                                               var targetUserPM = "sip:"+ privMExten +"@"+ wss_server +"";

                                               sendPrivMessage(targetUserPM, textToSendPM);
				           }
				       }
                                   });


                                   // Select the file to send
                                   $("#sendFileVCPM-"+ privMExten +"").click(function() {

				      $("#selectedFileVCPM-"+ privMExten +"").val('');
				      $("#upFileVCPM-"+ privMExten +"").empty();

				      var uploadfilevcpm = '<form id="sendFileFormChatVCPM-'+ privMExten +'" class="fileSendVCPM" enctype="multipart/form-data">';
				      uploadfilevcpm += '<input type="hidden" name="MAX_FILE_SIZE" value="786432000" />';
				      uploadfilevcpm += '<input type="hidden" name="vcextensionpm" value="'+ privMExten +'" />';
				      uploadfilevcpm += '<input type="hidden" name="sipusername" value="'+ sip_username +'" />';
				      uploadfilevcpm += '<input type="hidden" name="encextenpass" value="'+ encExtenPass +'" />';
				      uploadfilevcpm += '<input type="hidden" name="conferenceext" value="'+ videoConfExtension +'" />';
				      uploadfilevcpm += '<label for="selectedFileVCPM-'+ privMExten +'" class="customBrowseButtonVCpm">Select File</label>';
				      uploadfilevcpm += '<span id="upFileVCPM-'+ privMExten +'" class="uploadedFlVCpm" ></span>';
				      uploadfilevcpm += '<input type="file" id="selectedFileVCPM-'+ privMExten +'" name="uploadedFileVCPM" />';
				      uploadfilevcpm += '<input type="submit" id="submitFileChatVCPM-'+ privMExten +'" value="Send File" style="visibility:hidden;"/>';
				      uploadfilevcpm += '</form>';


				      if ($("#sendFileFormChatVCPM-"+ privMExten +"").is(":visible")) {
					  $("#sendFileFormChatVCPM-"+ privMExten +"").remove();
					  sendFileCheckVCpm[privMExten] = 0;
				      } else {
                                          sendFileCheckVCpm[privMExten] = 1;
					  $("#sendTextMessagePM-"+ privMExten +"").before(uploadfilevcpm);
					  $("#sendFileFormChatVCPM-"+ privMExten +"").css("display", "block");

					  $("#selectedFileVCPM-"+ privMExten +"").bind("change", function() {
					     upFileNameVCpm[privMExten] = $(this).val().split('\\').pop();
					     if (/^[a-zA-Z0-9\-\_\.]+$/.test(upFileNameVCpm[privMExten])) {
                                                 $("#upFileVCPM-"+ privMExten +"").css("display", "inline-block");
						 $("#upFileVCPM-"+ privMExten +"").html(upFileNameVCpm[privMExten]);
					     } else { 
						   $("#sendFileFormChatVCPM-"+ privMExten +"").remove();
						   sendFileCheckVCpm[privMExten] = 0;
						   alert("The name of the uploaded file is not valid!");
					     }
					  });
				      }

                                   });


                                   // Set window position
			           let maxHeightPm = parseInt(0.88 * $(window).height());
			           let maxWidthPm = parseInt(maxHeightPm * 1.24);
                                   let pmwTop = parseInt( ($(window).height() / 2) - 305 );
                                   let pmwLeft = parseInt( ($(window).width() / 2) - 245 );
                                   $("#privateMessageImg-"+ privMExten +"").hide();

			           if (maxWidthPm < 610 || maxHeightPm < 490) { 
			               $("#pmtextMessage-"+ privMExten +"").css({ "width": maxWidthPm, "height": maxHeightPm, "top": pmwTop, "left": pmwLeft });
			               $("#maximizeImgPM-"+ privMExten +"").hide();
                                       $("#restoreImgPM-"+ privMExten +"").hide();
                                   } else {
			               $("#pmtextMessage-"+ privMExten +"").css({ "width": 610, "height": 490, "top": pmwTop, "left": pmwLeft });
                                       $("#minimizeImgPM-"+ privMExten +"").show();
			               $("#maximizeImgPM-"+ privMExten +"").show();
                                       $("#restoreImgPM-"+ privMExten +"").hide();
			           }

			           $(window).resize(function() {

			             let maxHeightPm = parseInt(0.88 * $(window).height());
			             let maxWidthPm = parseInt(maxHeightPm * 1.24);
                                     let pmwTop = parseInt( ($(window).height() / 2) - 305 );
                                     let pmwLeft = parseInt( ($(window).width() / 2) - 245 );
                                     $("#receiveTextMessagePM-"+ privMExten +"").show();
                                     $("#sendTMessagePM-"+ privMExten +"").show();
                                     $("#pmTopBar-"+ privMExten +"").show();
                                     $("#privateMessageImg-"+ privMExten +"").hide();

			             if (maxWidthPm < 610 || maxHeightPm < 490) { 
				         $("#pmtextMessage-"+ privMExten +"").css({ "width": maxWidthPm, "height": maxHeightPm, "top": pmwTop, "left": pmwLeft });
				         $("#maximizeImgPM-"+ privMExten +"").hide();
                                         $("#restoreImgPM-"+ privMExten +"").hide();
			             } else { 
				         $("#pmtextMessage-"+ privMExten +"").css({ "width": 610, "height": 490, "top": pmwTop, "left": pmwLeft });
       				         $("#minimizeImgPM-"+ privMExten +"").show();
				         $("#maximizeImgPM-"+ privMExten +"").show();
                                         $("#restoreImgPM-"+ privMExten +"").hide();
			             }

			           });

			           $("#maximizeImgPM-"+ privMExten +"").click(function() { messageWindowStatePM[privMExten] = 'maximized'; $("#pmtextMessage-"+ privMExten +"").css({ "width": maxWidthPm, "height": maxHeightPm, "top": pmwTop - 40, "left": pmwLeft - 40}); $("#maximizeImgPM-"+ privMExten +"").hide(); $("#minimizeImgPM-"+ privMExten +"").show(); $("#restoreImgPM-"+ privMExten +"").show(); $("#receiveTextMessagePM-"+ privMExten +"").css("height", "66%"); $("#recPrivMessage-"+ privMExten +"").remove(); $("#pmTopBar-"+ privMExten +"").show(); $("#receiveTextMessagePM-"+ privMExten +"").show(); $("#sendTMessagePM-"+ privMExten +"").show(); $("#privateMessageImg-"+ privMExten +"").hide(); $("#topDragArea-"+ privMExten +"").css("top", "4px"); });
                                   $("#minimizeImgPM-"+ privMExten +"").click(function() { messageWindowStatePM[privMExten] = 'minimized'; $("#pmtextMessage-"+ privMExten +"").css({ "display": "block", "position": "fixed", "width": 218, "height": 34, "inset": "auto auto 2px 232px" }); $("#minimizeImgPM-"+ privMExten +",#pmTopBar-"+ privMExten +",#receiveTextMessagePM-"+ privMExten +",#sendTMessagePM-"+ privMExten +"").hide(); $("#maximizeImgPM-"+ privMExten +",#restoreImgPM-"+ privMExten +",#privateMessageImg-"+ privMExten +"").show(); $("#windowCtrlsPM-"+ privMExten +"").css("margin", "10px 10px 0px 0px"); $("#topDragArea-"+ privMExten +"").css("top", "-1px"); });
                                   $("#restoreImgPM-"+ privMExten +"").click(function() { messageWindowStatePM[privMExten] = 'restored'; $("#pmtextMessage-"+ privMExten +"").css({ "width": 610, "height": 490, "top": pmwTop, "left": pmwLeft }); $("#restoreImgPM-"+ privMExten +"").hide(); $("#maximizeImgPM-"+ privMExten +"").show(); $("#minimizeImgPM-"+ privMExten +"").show(); $("#receiveTextMessagePM-"+ privMExten +"").css("height", "54%"); $("#recPrivMessage-"+ privMExten +"").remove(); $("#pmTopBar-"+ privMExten +"").show(); $("#receiveTextMessagePM-"+ privMExten +"").show(); $("#sendTMessagePM-"+ privMExten +"").show(); $("#privateMessageImg-"+ privMExten +"").hide(); $("#topDragArea-"+ privMExten +"").css("top", "4px"); });
			           $("#closeImgPM-"+ privMExten +"").click(function() { messageWindowStatePM[privMExten] = 'closed'; $("#pmtextMessage-"+ privMExten +"").remove(); $("#recPrivMessage-"+ privMExten +"").remove(); });

			           $(window).on('keydown', function(event) { if (event.key == "Escape") { messageWindowStatePM[privMExten] = 'closed'; $("#pmtextMessage-"+ privMExten +"").remove(); $("#recPrivMessage-"+ privMExten +"").remove(); } });

}

// Reformat the message to include new lines and emojis
ConferencePhone.prototype.ReformatVCMessage = function (str) {
	var msg = str;
	msg = msg.replace(/</gi, "&lt;");
	msg = msg.replace(/>/gi, "&gt;");
	msg = msg.replace(/\n/gi, "<br>");
	msg = msg.replace(/(:\)|:\-\)|:o\))/g, String.fromCodePoint(0x1F642));     // :) :-) :o)
	msg = msg.replace(/(:\(|:\-\(|:o\()/g, String.fromCodePoint(0x1F641));     // :( :-( :o(
	msg = msg.replace(/(;\)|;\-\)|;o\))/g, String.fromCodePoint(0x1F609));     // ;) ;-) ;o)
	msg = msg.replace(/(:'\(|:'\-\()/g, String.fromCodePoint(0x1F62A));        // :'( :'‑(
	msg = msg.replace(/(:'\(|:'\-\()/g, String.fromCodePoint(0x1F602));        // :') :'‑)
	msg = msg.replace(/(:\$)/g, String.fromCodePoint(0x1F633));                // :$
	msg = msg.replace(/(>:\()/g, String.fromCodePoint(0x1F623));               // >:(
	msg = msg.replace(/(:\×)/g, String.fromCodePoint(0x1F618));                // :×
	msg = msg.replace(/(:\O|:\‑O)/g, String.fromCodePoint(0x1F632));           // :O :‑O
	msg = msg.replace(/(:P|:\-P|:p|:\-p)/g, String.fromCodePoint(0x1F61B));    // :P :-P :p :-p
	msg = msg.replace(/(;P|;\-P|;p|;\-p)/g, String.fromCodePoint(0x1F61C));    // ;P ;-P ;p ;-p
	msg = msg.replace(/(:D|:\-D)/g, String.fromCodePoint(0x1F60D));            // :D :-D
	msg = msg.replace(/(\(like\))/g, String.fromCodePoint(0x1F44D));           // (like)

	return msg;
}

// Download text of public chat
ConferencePhone.prototype.DownloadChatHistoryVC = function(vidConfExtension, crVConfTag) {

    var presDateVC = moment().format("YYYY-MM-DD_HH-mm-ss");
    var wholeChatTextTitleVC = "\n" + "Roundpin Video Conference Chat History - Room: "+ crVConfTag +" ("+ vidConfExtension +"), saved on " + moment().format("YYYY-MM-DD HH:mm:ss") + "\n\n\n\n";
    var wholeChatTextVC = "";

    $("#receiveTextMessage .textMsgVConf").each(function() {
       if ($(this).find(".recMessageBtn").length != 0) {
           wholeChatTextVC += "\n" + $(this).find(".recMessageBtn").text().slice(0, -2) +" ("+ $(this).find(".messageDate").text() +"):\n  "+ $(this).find(".srMsgVConfcont").text() +"\n\n";
       } else {
           wholeChatTextVC += "\n" + $(this).find(".sentMessageBtn").text().slice(0, -1) +" ("+ $(this).find(".messageDate").text() +"):\n  "+ $(this).find(".srMsgVConfcont").text() +"\n\n";
       }
    });

    if (wholeChatTextVC == "") { alert("There is no chat history to save ! "); return; }
    var wholeChatConcVC = wholeChatTextTitleVC + wholeChatTextVC;
    var crVConfTagMod = crVConfTag.replace(" ", "_");
    var downFilenameVC = 'Roundpin_Video_Conference_Chat_History_Room_'+ crVConfTagMod +"_"+ vidConfExtension +"_"+ presDateVC;
    var downlinkVC = document.createElement('a');
    var mimeTypeVC = 'text/plain';

    downlinkVC.setAttribute('download', downFilenameVC);
    downlinkVC.setAttribute('href', 'data:' + mimeTypeVC + ';charset=utf-8,' + encodeURIComponent(wholeChatConcVC));
    downlinkVC.click();
}

// Download text of private chat
ConferencePhone.prototype.DownloadChatHistoryVCPM = function(vidConfExtension, crVConfTag, privateMExten, privMssgUserName) {

    var presDateVC = moment().format("YYYY-MM-DD_HH-mm-ss");
    var wholeChatTextTitleVC = "\n" + "Roundpin Video Conference Private Chat History - Room: "+ crVConfTag +" ("+ vidConfExtension +"), Interlocutor: "+ privMssgUserName +", saved on " + moment().format("YYYY-MM-DD HH:mm:ss") + "\n\n\n\n";
    var wholeChatTextVC = "";

    $("#receiveTextMessagePM-"+ privateMExten +" .textMsgVConf").each(function() {
       if ($(this).find(".recMessageBtnPM").length != 0) {
           wholeChatTextVC += "\n" + $(this).find(".recMessageBtnPM").text().slice(0, -1) +" ("+ $(this).find(".messageDate").text() +"):\n  "+ $(this).find(".srMsgVConfcont").text() +"\n\n";
       } else {
           wholeChatTextVC += "\n" + $(this).find(".sentMessageBtnPM").text().slice(0, -1) +" ("+ $(this).find(".messageDate").text() +"):\n  "+ $(this).find(".srMsgVConfcont").text() +"\n\n";
       }
    });

    if (wholeChatTextVC == "") { alert("There is no chat history to save ! "); return; }
    var wholeChatConcVC = wholeChatTextTitleVC + wholeChatTextVC;
    var privMssgUserNameArr = privMssgUserName.split(" ");
    privMssgUserNameArr.pop();
    var privMssgUserNameUs = privMssgUserNameArr.join("_");
    var crVConfTagMod = crVConfTag.replace(" ", "_");
    var downFilenameVC = 'Roundpin_Video_Conference_Private_Chat_History_Room_'+ crVConfTagMod +"_"+ vidConfExtension +"_User_"+ privMssgUserNameUs +"_"+ privateMExten +"_"+ presDateVC;
    var downlinkVC = document.createElement('a');
    var mimeTypeVC = 'text/plain';

    downlinkVC.setAttribute('download', downFilenameVC);
    downlinkVC.setAttribute('href', 'data:' + mimeTypeVC + ';charset=utf-8,' + encodeURIComponent(wholeChatConcVC));
    downlinkVC.click();
}

// Record the video conference
ConferencePhone.prototype.recordVideoConference = function () {

	function saveFile(recordedChunks) {

	    const rawblob = new Blob(recordedChunks, { type: 'video/webm' });
            let duration = recordedChunks.length * 200;

            // Add duration to the media blob, so that the final webm file becomes seekable
            ysFixWebmDuration(rawblob, duration, function(fixedBlob) {

	        let filename = window.prompt('Enter the name of the video file:');
	        let downloadLink = document.createElement('a');
	        downloadLink.href = URL.createObjectURL(fixedBlob);
	        downloadLink.download = `${filename}.webm`;

	        document.body.appendChild(downloadLink);
	        downloadLink.click();
	        URL.revokeObjectURL(fixedBlob);
	        document.body.removeChild(downloadLink);

            });
	}

        if (confirm("To record the video conference, at the next step, select 'Entire screen'.")) {} else { return; }

        let screenCaptureConstraints = { audio: true, video: true };

        navigator.mediaDevices.getDisplayMedia(screenCaptureConstraints).then(function(recordStream) {

                let pc = currentSession[0].connection;
		pc.getReceivers().forEach(function (RTCRtpReceiver) {
		    if(RTCRtpReceiver.track && RTCRtpReceiver.track.kind == "audio") {
		        console.log("Adding receiver audio track to record: ", RTCRtpReceiver.track.label);
		        recordStream.addTrack(RTCRtpReceiver.track);
		    }
                });

		let mediaRecorder = new MediaRecorder(recordStream, { mimeType: 'video/webm' });
		let recordedChunks = [];

		mediaRecorder.ondataavailable = function (e) {
		      if (e.data.size > 0) {
			  recordedChunks.push(e.data);
		      }  
		};

		mediaRecorder.onstop = function () {
		      saveFile(recordedChunks);
		      recordedChunks = [];
		};

                // Record in chunks of 200 milliseconds
		mediaRecorder.start(200);

		let stopRec = document.createElement("div");
                stopRec.id = "stopConfRec";
                stopRec.innerHTML = '<i id="dragRecConfBtn" class="fa fa-ellipsis-v" aria-hidden="true" title="Drag Window" style="margin: 0px 8px 0px 4px;cursor:grab;color:#7a7a7a;"></i><button id="stopConfBtn">Stop Recording</button>';
                              
                let crMediaView = document.getElementsByClassName("media-view");
		crMediaView[0].appendChild(stopRec);

		// Make the 'Record Conference' button draggable
		function recConfBtnDraggable(e){

		       window.rcdragging = {};
		       rcdragging.pageX0 = e.pageX;
		       rcdragging.pageY0 = e.pageY;
                       rcdragging.elem = $("#stopConfRec");
                       rcdragging.offset0 = $("#stopConfRec").offset();

		       function handle_dragging(e){
			   var left = rcdragging.offset0.left + (e.pageX - rcdragging.pageX0);
			   var top = rcdragging.offset0.top + (e.pageY - rcdragging.pageY0);
			   $(rcdragging.elem).offset({top: top, left: left});
		       }

		       function handle_mouseup(e){
			   $('body').off('mousemove', handle_dragging).off('mouseup', handle_mouseup);
		       }

		       $('body').on('mouseup', handle_mouseup).on('mousemove', handle_dragging);
		}

                $("#dragRecConfBtn").mousedown(recConfBtnDraggable);

                // Stop recording
                let crStopCnf = document.getElementById("stopConfRec");
                let stopCnfrcBtn = document.getElementById("stopConfBtn");
                stopCnfrcBtn.onclick = function() {
		       mediaRecorder.stop();
                       crMediaView[0].removeChild(crStopCnf);
                };

        });
}

ConferencePhone.prototype.ShareScreen = function () {

    var localStream = new MediaStream();
    var pc = currentSession.connection;

    var screenShareConstraints = { video: true, audio: false };

    navigator.mediaDevices.getDisplayMedia(screenShareConstraints).then(function(newStream) {

            var newMediaTrack = newStream.getVideoTracks()[0];
            pc.getSenders().forEach(function (RTCRtpSender) {
                if (RTCRtpSender.track && RTCRtpSender.track.kind == "video") {
                    RTCRtpSender.replaceTrack(newMediaTrack);
                    localStream.addTrack(newMediaTrack);
                }
            });

            var localVideo = $('[id*="locVideo"]').get(0);
            localVideo.autoplay = true;
            localVideo.srcObject = localStream;

            var VidView = $('[id*="video-view"]').get(0);
            VidView.append(localVideo);
            $('[id*="new-media-view"]').get(0).append(VidView);
          
    }).catch(function() { console.error(e); });
}

ConferencePhone.prototype.ShareVideo = function () {

    var localStream = new MediaStream();
    var pc = currentSession.connection;

    var videoShareConstraints = { video: true, audio: true };
    navigator.mediaDevices.getUserMedia(videoShareConstraints).then(function(newStream) {

            var newMediaTrack = newStream.getVideoTracks()[0];
            pc.getSenders().forEach(function (RTCRtpSender) {
                if (RTCRtpSender.track && RTCRtpSender.track.kind == "video") {
                    RTCRtpSender.replaceTrack(newMediaTrack);
                    localStream.addTrack(newMediaTrack);
                }
            });

            var localVideo = $('[id*="locVideo"]').get(0);
            localVideo.autoplay = true;
            localVideo.srcObject = localStream;

            var VidView = $('[id*="video-view"]').get(0);
            VidView.append(localVideo);
            $('[id*="new-media-view"]').get(0).append(VidView);
         
    }).catch(function() { console.error(e); });
}


// Resize video windows when participants join or leave the conference
ConferencePhone.prototype.resizeVideo = function (userCount) {

                let cWidth = window.innerWidth || document.body.clientWidth;
                let cHeight = window.innerHeight || document.body.clientHeight;
                let allMediaViews = document.getElementsByClassName("media-view");
                let allVideo = document.getElementsByClassName("videoElem");

                document.getElementById("media-frame").style.height = cHeight +"px";

		    let screenArea = cWidth * cHeight;
                    let indVideoArea = parseInt((screenArea / userCount).toFixed(2));
                    mvWidth = parseInt(parseFloat(Math.sqrt(indVideoArea * cAspectRatio))); 
                    mvHeight = parseInt((1/cAspectRatio) * mvWidth);

                    for (let n = 0; n < allMediaViews.length; n++) {
                         allMediaViews[n].style.width = mvWidth + "px";
                         allMediaViews[n].style.height = mvHeight + "px";
                         allVideo[n].style.width = mvWidth + "px";
                         allVideo[n].style.height = mvHeight + "px";
                    }

		    function vwindowsResize() {
			 let mdview = document.getElementById("media-views");
			 let boundrect = mdview.getBoundingClientRect();

			 if (boundrect.top >= 0 && boundrect.left >= 0 && boundrect.right <= (window.innerWidth || document.body.clientWidth) && boundrect.bottom <= (window.innerHeight || document.body.clientHeight)) {
			     return 1;
			 } else {
		             return 0;
			 }
		    }

                    function recalcWidth(nwcWidth) {
                         mvWidth = nwcWidth;
                         mvHeight = parseInt((1/cAspectRatio) * mvWidth);
                    }


                    if (userCount == 3 || userCount == 4) {

                        let spcCheck = 0;

                        while (spcCheck == 0) {

                              if (((mvHeight * 2) < (cHeight - 10))  && ((mvWidth * 2) < (cWidth - 10))) {
                                    for (let j = 0; j < allMediaViews.length; j++) {
                                         allMediaViews[j].style.width = mvWidth + "px";
                                         allMediaViews[j].style.height = mvHeight + "px";
                                         allVideo[j].style.width = mvWidth + "px";
                                         allVideo[j].style.height = mvHeight + "px";
                                    }

                                    document.getElementById("media-frame").setAttribute("style", "width: "+ parseInt((mvWidth * 2) + 4) +"px; height: "+ parseInt((mvHeight * 2) + 4) +"px; margin: auto;");

                                    spcCheck = 1;

                              } else {
                                    var rclcWidth = mvWidth - 1;
                                    recalcWidth(rclcWidth);
                              }
                        }
                    
                    } else {

                       let wivpCheck = 0;

                       while (wivpCheck == 0) {

                              mvWidth = mvWidth - 2;
                              mvHeight = parseInt((1/cAspectRatio) * mvWidth);

                              for (let j = 0; j < allMediaViews.length; j++) {
                                   allMediaViews[j].style.width = mvWidth + "px";
                                   allMediaViews[j].style.height = mvHeight + "px";
                                   allVideo[j].style.width = mvWidth + "px";
                                   allVideo[j].style.height = mvHeight + "px";
                              }

                              document.getElementById("media-frame").setAttribute("style", "width: unset; height: "+ cHeight +"px; margin: unset;");
                              wivpCheck = vwindowsResize();
                       }
                    }

                if (mvWidth <= 150) {
                    let allUserDesc = document.getElementsByClassName("user-desc");
                    for (let d = 0; d < allMediaViews.length; d++) {
                         allUserDesc[d].style = "font-size: 8px";
                    }
                }
}

ConferencePhone.prototype.dtmfSend = function (numPressed) {
    var pc = currentSession[0].connection;
    var dtmfSender = pc.getSenders()[0].dtmf;
    dtmfSender.insertDTMF(numPressed);
    $("#dialText").val(numPressed);
}

///////////////////////////////////////////////////////////////////////////////

function mute(stream, options) {

	function setTracks(tracks, val) {
		if (!tracks) {
			return;
		}

		for (let i = 0; i < tracks.length; ++i) {
			if (tracks[i].enabled == val) {
				tracks[i].enabled = !val;
			}
		}
	};

	options = options || { audio: true, video: true };

	if (typeof options.audio != 'undefined') {
		setTracks(stream.getAudioTracks(), options.audio);
	}

	if (typeof options.video != 'undefined') {
		setTracks(stream.getVideoTracks(), options.video);
	}
}

function unmute(stream, options) {
	let opts = options || { audio: false, video: false };
	mute(stream, opts);
}

///////////////////////////////////////////////////////////////////////////////

function Streams () {
	EasyEvent.call(this);
	this._streams = [];
};

Streams.prototype = Object.create(EasyEvent.prototype);
Streams.prototype.constructor = Streams;

Streams.prototype.add = function (stream) {
	if (this._streams.indexOf(stream) == -1) {
		this._streams.push(stream);
		console.log('Streams: added ' + stream.id);
		this.raise('streamAdded', stream);
	}
};

Streams.prototype.remove = function (stream) {
	let index = typeof stream == 'number' ? stream : this._streams.indexOf(stream);

	if (index == -1) {
		return;
	}

	let removed = this._streams.splice(index, 1);
};

Streams.prototype.removeAll = function () {
	for (let i = this._streams.length - 1; i >= 0 ; --i) {
		this.remove(i);
	}
};

///////////////////////////////////////////////////////////////////////////////

function EasyEvent () {
	this._events = {};
};

EasyEvent.prototype.handle = function (name, fun) {
	if (name in this._events) {
		this._events[name].push(fun);
	} else {
		this._events[name] = [fun];
	}
};

EasyEvent.prototype.raise = function (name) {
	if (name in this._events) {
		for (let i = 0; i < this._events[name].length; ++i) {
			this._events[name][i].apply(this,
					Array.prototype.slice.call(arguments, 1));
		}
	}
};

EasyEvent.prototype.bubble = function (name, obj) {
	this.handle(name, function (data) {
		obj.raise(name, data);
	});
};

EasyEvent.prototype.raiseForEach = function (name, array) {
	if (name in this._events) {
		for (let i = 0; i < array.length; ++i) {
			this.raise(name, array[i], i);
		}
	}
};
