/* Minification failed. Returning unminified contents.
(425,35-36): run-time error JS1195: Expected expression: >
 */
(function ($) {
	$.fn.emoji = function (params) {
		var defaults = {
			button: '&#x1F642;',
			place: 'before',
			emojis: ['&#x1F642;', '&#x1F641;', '&#x1f600;', '&#x1f601;', '&#x1f602;', '&#x1f603;', '&#x1f604;', '&#x1f605;', '&#x1f606;', '&#x1f607;', '&#x1f608;', '&#x1f609;', '&#x1f60a;', '&#x1f60b;', '&#x1f60c;', '&#x1f60d;', '&#x1f60e;', '&#x1f60f;', '&#x1f610;', '&#x1f611;', '&#x1f612;', '&#x1f613;', '&#x1f614;', '&#x1f615;', '&#x1f616;', '&#x1f617;', '&#x1f618;', '&#x1f619;', '&#x1f61a;', '&#x1f61b;', '&#x1f61c;', '&#x1f61d;', '&#x1f61e;', '&#x1f61f;', '&#x1f620;', '&#x1f621;', '&#x1f622;', '&#x1f623;', '&#x1f624;', '&#x1f625;', '&#x1f626;', '&#x1f627;', '&#x1f628;', '&#x1f629;', '&#x1f62a;', '&#x1f62b;', '&#x1f62c;', '&#x1f62d;', '&#x1f62e;', '&#x1f62f;', '&#x1f630;', '&#x1f631;', '&#x1f632;', '&#x1f633;', '&#x1f634;', '&#x1f635;', '&#x1f636;', '&#x1f637;', '&#x1f638;', '&#x1f639;', '&#x1f63a;', '&#x1f63b;', '&#x1f63c;', '&#x1f63d;', '&#x1f63e;', '&#x1f63f;', '&#x1f640;', '&#x1f643;', '&#x1f4a9;', '&#x1f644;', '&#x2620;', '&#x1F44C;','&#x1F44D;', '&#x1F44E;', '&#x1F648;', '&#x1F649;', '&#x1F64A;'],
			fontSize: '20px',
			listCSS: {position: 'absolute', border: '1px solid gray', 'background-color': '#fff', display: 'none'},
			rowSize: 10,
		};
		var settings = {};
		if (!params) {
			settings = defaults;
		} else {
			for (var n in defaults) {
				settings[n] = params[n] ? params[n] : defaults[n];
			}
		}

		this.each(function (n, input) {
			var $input = $(input);

			function showEmoji() {
				$list.show();
				$input.focus();
				setTimeout(function () {
				    $(document).on('click', closeEmoji);
				    $button.off('click', showEmoji);
				}, 1);
			}

			function closeEmoji() {
			    $list.hide();
			    $button.on('click', showEmoji);
				$(document).off('click', closeEmoji);
			}

			function clickEmoji(ev) {
				if (input.selectionStart || input.selectionStart == '0') {
					var startPos = input.selectionStart;
					var endPos = input.selectionEnd;
					input.value = input.value.substring(0, startPos)
						+ ev.currentTarget.innerHTML
						+ input.value.substring(endPos, input.value.length);
				} else {
					input.value += ev.currentTarget.innerHTML;
				}

				closeEmoji();
				$input.focus();
				input.selectionStart = startPos + 2;
				input.selectionEnd = endPos + 2;
			}

			var $button = $("<span>").html(settings.button).css({cursor: 'pointer', 'font-size': settings.fontSize}).on('click', showEmoji);
			var $list = $('<div>').css(defaults.listCSS).css(settings.listCSS);
			for (var n in settings.emojis) {
				if (n > 0 && n % settings.rowSize == 0) {
					$("<br>").appendTo($list);
				}
				$("<span>").html(settings.emojis[n]).css({cursor: 'pointer', 'font-size': settings.fontSize}).on('click', clickEmoji).appendTo($list);
			}

			if (settings.place === 'before') {
				$button.insertBefore(this);
			} else {
				$button.insertAfter(this);
			}
			$list.insertAfter($input);
		});
		return this;
	};
}
)(jQuery);
;
+function (window, jQuery, moment) {
    'use strict';

    var ContractFX = window.ContractFX = window.ContractFX || {};
    ContractFX.Controls = ContractFX.Controls || {};
    var ERFx = ContractFX.Controls.ERFx = ContractFX.Controls.ERFx || {};

    ERFx.OnlineChat = function (containerId, chatId, isAuth, domainUrl, channelName, ownerID, userId, moderatorId) {

        this.containerId = containerId;
        this.container = jQuery('#' + containerId);
        this.chatId = chatId;
        this.isConnected = false;
        this.isTheEnd = false;
        this.isFirstLoad = true;
        this.isLoadingMessages = false;
        this.isMyMessage = false;
        this.isRepliedMessageClicked = false;
        this.RepliedToMessageID = 0;
        var self = this;
        this.isAuth = isAuth.toLowerCase();
        this.channelName = channelName;
        this.ownerID = ownerID;
        this.userId = userId;
        this.moderatorId = moderatorId;
        this.notificationMessageId = 0;
        this.notificationRepliesId = 0
        this.chat = jQuery.connection.chatHub;
        this.messageCount = 30;
        this.repliesCount = 10;
        this.isErrorLoad = false;
        this.isLoadBottomEnd = false;

        
        this.clientTZOffset = new Date().getTimezoneOffset();
        this.clientTZHour = this.clientTZOffset / 60;
        this.months = ["Jan", "Feb", "Mar","Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

        jQuery(function () {

            //var signInMsg = "You must sign in to use chat feature.";
            function SignInAndUpBtn() {
                var fragment = document.createDocumentFragment();
                var parentDiv = document.createElement("div");
                var wrapDiv = document.createElement("div");
                wrapDiv.setAttribute("class", "d-flex align-items-center");
                var anchorSignIn = document.createElement("A");
                anchorSignIn.setAttribute("href", "#");
                anchorSignIn.setAttribute("onclick", "k12PopupEFX.Hide(); ShowLoginPopup(ContractFX.Controls.Auth.LoginPopup.TYPE_CLIENT); return false;");
                anchorSignIn.setAttribute("style", "margin-right: 4px; padding:10px 0; font-size: 16px;");
                anchorSignIn.innerText = "Sign In";
                var anchorSignUp = document.createElement("A");
                anchorSignUp.setAttribute("href", "#");
                if (window.location.pathname.indexOf('view') !== -1) {
                    anchorSignUp.setAttribute("onclick", "k12PopupEFX.Hide(); window.location.href = window.location.origin + '/AttendeeReg.aspx?rs=1&view=' +   window.location.pathname.replace('/view/', '')");
                }
                else
                    anchorSignUp.setAttribute("onclick", "k12PopupEFX.Hide(); window.location.href = window.location.origin + '/AttendeeReg.aspx'");
                anchorSignUp.setAttribute("style", "margin-left: 4px; padding: 10px 0; font-size: 16px;");
                anchorSignUp.innerText = "Sign Up ";
                var firstPartMsg = document.createElement("span");
                firstPartMsg.innerHTML = "You must ";
                var secondPartMsg = document.createElement("span");
                secondPartMsg.innerHTML = " to use chat feature.";
                var separator = document.createElement("span");
                separator.innerText = "/";

                wrapDiv.appendChild(firstPartMsg);
                wrapDiv.appendChild(anchorSignUp);
                wrapDiv.appendChild(separator);
                wrapDiv.appendChild(anchorSignIn);
                wrapDiv.appendChild(secondPartMsg);
                fragment.appendChild(wrapDiv);
                parentDiv.appendChild(fragment);
                return parentDiv.children;
            }

            //Check cooldown on sendQuestion btn
            var timeNow = Math.round(new Date() / 1000);
            var cooldown = window.localStorage.getItem('Cooldown');
            if( cooldown > timeNow){
                var duration = cooldown - timeNow;
                self.StartCooldown(duration);
            }
            else{
                window.localStorage.removeItem('Cooldown');
            }
            
            if (isAuth.toLowerCase() === "false") {
                self.container.find('.txt-message-wrapper').click(function () {
                    k12PopupEFX.btnContinue.SetText("Ok");
                    k12PopupEFX.Alert(SignInAndUpBtn(), undefined, 360);                    
                });
            }
            else
                self.container.find('.js--txt-chat-message').emoji();

              //self.ShowNoMessagesLabel();

            // Create a function that the hub can call to broadcast messages.
            self.chat.client.broadcastMessage = function (message, system) {
                if(message.FK_OnlineChatMessageReplyTo > 0){
                    var fromHub = true;
                    self.addRepliesToChat(message, true, message.FK_OnlineChatMessageReplyTo, fromHub);
                }
                else
                {
                    if(!self.isLoadBottomEnd && self.isMyMessage){
                            self.loadAllMessage();
                        }
                    else{

                        self.addMessageObj(message, false, system);
                        if (message.IsQuestion) {
                            self.addQuestionMessage(message, false, system);
                        }
                        if (self.isMyMessage)
                            self.isMyMessage = false;
                    }
                }
            };

            // Create a function that the hub can call to delete messages.
            self.chat.client.deleteMessage = function (message) {
                self.deleteMessageObj(message, false);
                if (self.isMyMessage)
                    self.isMyMessage = false;
            };

            self.chat.client.banUser = function (message) {
                self.banUserObj(message, false);
                if (self.isMyMessage)
                    self.isMyMessage = false;
            };

            self.chat.client.unBlockUser = function (message) {
                self.unBlockUserObj(message, false);
                if (self.isMyMessage)
                    self.isMyMessage = false;
            };

            self.chat.client.answer = function (message) {
                self.answerObj(message, false);
                if (self.isMyMessage)
                    self.isMyMessage = false;
            };

            self.chat.client.promoteUserToModerator = function(message){
                self.promoteUserToModeratorObj(message, false);
                if (self.isMyMessage)
                    self.isMyMessage = false;
            }

            self.chat.client.promoteToModerator = function(message){
                self.promoteToModeratorObj(message, false);
                if (self.isMyMessage)
                    self.isMyMessage = false;
            }

            self.chat.client.demoteUserFromModerator = function(message){
                self.demoteUserFromModeratorObj(message, false);
                if (self.isMyMessage)
                    self.isMyMessage = false;
            }

            self.chat.client.demoteFromModerator = function(message){
                self.demoteFromModeratorObj(message, false);
                if (self.isMyMessage)
                    self.isMyMessage = false;
            }

            self.chat.client.clearInput = function(isQuestion){
                self.ClearInput();
                if(isQuestion){
                    if (!self.container.find('.js--btn-chat-send-question').hasClass('disabled-btn')) {
                        var timeNow = Math.round(new Date() / 1000);
                        var cooldown = window.localStorage.getItem('Cooldown');

                        if (cooldown < timeNow)
                            self.StartCooldown(90); //<--- set btn cooldown in seconds
                    } else {
                        return;
                    }
                }
            }

            self.chat.client.joined = function (isConnected) {
                self.isConnected = isConnected;

                self.InitLoadingMessages();
            }

            self.chat.client.disabledChatFunc = function(){
                self.DisabledChatFuncObj();
            }

            self.chat.client.errorOccured = function (message) {
                k12PopupEFX.Alert(message);
            }

            // Start the connection.
            var connectionStart = jQuery.connection.hub.start({ transport: ['serverSentEvents', 'foreverFrame', 'longPolling'] });
            connectionStart.done(function () {
                // Call the Send method on the hub. 
                self.chat.server.joinChat(self.chatId);

                self.container.find('.js--btn-chat-send-message').click(function () {
                    if (self.isConnected) {
                        if (self.IsValidMessage()) {
                            //added to scroll down after your message was successfully sent to other users
                            self.isMyMessage = true;
                            let chatReplySection = self.container.find('.chat-reply-to-section');
                            let replyToMessageId = chatReplySection.attr('data-message-id');
                          
                            // Call the Send method on the hub.
                            self.chat.server.send(self.container.find('.js--txt-chat-message').val(), replyToMessageId, channelName);
                            // Clear text box and reset focus for next comment. 
                            //self.ClearInput();
                            chatReplySection.attr('data-message-id', 0);
                            chatReplySection.hide();
                        } else {
                            if (isAuth.toLowerCase() === "false") {
                                k12PopupEFX.btnContinue.SetText("Ok");
                                k12PopupEFX.Alert(SignInAndUpBtn(), undefined, 360);
                            }
                            else
                                k12PopupEFX.Alert("Please, Enter Your Message.");
                        }
                    } else {
                        k12PopupEFX.btnContinue.SetText("Ok");
                        k12PopupEFX.Alert("Please, wait you're not connected to the server yet. <br />If you're waiting too long then try to refresh the page.");
                    }
                });

                self.container.find('.js--txt-chat-message').keypress(function(event){
                    var keycode = (event.keyCode ? event.keyCode : event.which);
                    
                    if(keycode == '13' && (!event.shiftKey && !event.ctrlKey)){
                        if (self.isConnected) {
                            if (self.IsValidMessage()) {
                                //added to scroll down after your message was successfully sent to other users
                                self.isMyMessage = true;
                                let chatReplySection = self.container.find('.chat-reply-to-section');
                                let replyToMessageId = chatReplySection.attr('data-message-id');
                          
                                // Call the Send method on the hub.
                                self.chat.server.send(self.container.find('.js--txt-chat-message').val(), replyToMessageId, channelName);
                                // Clear text box and reset focus for next comment. 
                                //self.ClearInput();
                                chatReplySection.attr('data-message-id', 0);
                                chatReplySection.hide();
                            } else {
                                if (isAuth.toLowerCase() === "false") {
                                    k12PopupEFX.btnContinue.SetText("Ok");
                                    k12PopupEFX.Alert(SignInAndUpBtn(), undefined, 360);
                                }
                                else
                                    k12PopupEFX.Alert("Please, Enter Your Message.");
                            }
                        } else {
                            k12PopupEFX.btnContinue.SetText("Ok");
                            k12PopupEFX.Alert("Please, wait you're not connected to the server yet. <br />If you're waiting too long then try to refresh the page.");
                        } 
                    }
                });

                //Send Question button
                self.container.find('.js--btn-chat-send-question').click(function () {
                    if (self.isConnected) {

                        if (self.IsValidMessage()) {

                            //added to scroll down after your message was successfully sent to other users
                            self.isMyMessage = true;

                            // Call the Send method on the hub.
                            self.chat.server.question(self.container.find('.js--txt-chat-message').val(), channelName);

                            // Clear text box and reset focus for next comment. 
                            //self.ClearInput();
                            //if (!self.container.find('.js--btn-chat-send-question').hasClass('disabled-btn')) {
                            //    var timeNow = Math.round(new Date() / 1000);
                            //    var cooldown = window.localStorage.getItem('Cooldown');

                            //    if (cooldown < timeNow)
                            //        self.StartCooldown(90); //<--- set btn cooldown in seconds
                            //} else {
                            //    return;
                            //}
                        } else {
                            if (isAuth.toLowerCase() === "false") {
                                k12PopupEFX.btnContinue.SetText("Ok");
                                k12PopupEFX.Alert(SignInAndUpBtn(), undefined, 360);
                            }
                            else
                                k12PopupEFX.Alert("Please, Enter Your Message.");
                        }
                    } else {
                        k12PopupEFX.btnContinue.SetText("Ok");
                        k12PopupEFX.Alert("Please, wait you're not connected to the server yet. <br />If you're waiting too long then try to refresh the page.");
                    }
                });
            });

            //scroll to bottom button
            self.container.find('.scroll-to-bottom-btn').click(function () {
                if(self.isLoadBottomEnd){
                    self.ScrollBottomAnimated();
                }
                else {
                    self.loadAllMessage();
                }
            });

            connectionStart.fail(function (reason) {
                //k12PopupEFX.Alert("Chat Connection Failed.");
                console.log(reason);
                self.InitLoadingMessages();
                self.container.find('.js--btn-chat-send-message').click(function () {
                    k12PopupEFX.btnContinue.SetText("Ok");
                    k12PopupEFX.Alert(SignInAndUpBtn(), undefined, 360);
                });
                self.container.find('.js--btn-chat-send-question').click(function () {
                    k12PopupEFX.btnContinue.SetText("Ok");
                    k12PopupEFX.Alert(SignInAndUpBtn(), undefined, 360);
                });
            });

            let cancelReplyToBtn = self.container.find('.js-chat-reply-to-cancel-btn');
            cancelReplyToBtn.click(function () {
                let replyToSection = self.container.find('.chat-reply-to-section');
                replyToSection.attr('data-message-id', '0');
                replyToSection.hide();
            });
    });

        this.timeZoneAbbreviated = function() {
            //let { 1: tz } 
            let tz = new Date().toString().match(/\((.+)\)/);

            // In Chrome browser, new Date().toString() is
            // "Thu Aug 06 2020 16:21:38 GMT+0530 (India Standard Time)"

            // In Safari browser, new Date().toString() is
            // "Thu Aug 06 2020 16:24:03 GMT+0530 (IST)"

            if (tz.includes(" ")) {
                return tz
                  .split(" ")
                  .map(([first]) => first)
                  .join("");
            } else {
                return tz;
            }
        };

        this.getUsersLocalTime = function(dateInUsersTimeZone) {
            var res = "";
            var dateNow = new Date();

            var clientTZHourStr = " " + self.clientTZHour;

            if(self.clientTZHour < 0) {
                clientTZHourStr = " +" + Math.abs(self.clientTZHour);
            }
            else if(self.clientTZHour == 0) {
                clientTZHourStr = "";
            }
            else{
                clientTZHourStr = " -" + self.clientTZHour;
            }
            if(dateNow.getDate() == dateInUsersTimeZone.getDate()) {
                res = this.custTime(dateInUsersTimeZone.getHours(), dateInUsersTimeZone.getMinutes(), dateInUsersTimeZone.getSeconds()) + " (GMT" + clientTZHourStr + ")";
            } else if(dateNow.getFullYear() == dateInUsersTimeZone.getFullYear()) {
                res = dateInUsersTimeZone.getDate() + " " + this.months[dateInUsersTimeZone.getMonth()] + " " +
                this.custTime(dateInUsersTimeZone.getHours(), dateInUsersTimeZone.getMinutes(), dateInUsersTimeZone.getSeconds()) + " (GMT" + clientTZHourStr + ")";
            } else {
                res = dateInUsersTimeZone.getDate() + " " + this.months[dateInUsersTimeZone.getMonth()] + " " + dateInUsersTimeZone.getFullYear() + ", " + 
                this.custTime(dateInUsersTimeZone.getHours(), dateInUsersTimeZone.getMinutes(), dateInUsersTimeZone.getSeconds()) + " (GMT" + clientTZHourStr + ")";
            }

            return res;
        }

        this.custTime = function (h, m, s){
            return ("0" + h).slice(-2) + ":" + ("0" + m).slice(-2) + ":" + ("0" + s).slice(-2); 
        }

        this.addMessageObj = function (message, isToTop, SystemMessage) {
            var isRepliesLoad = false;
            var isRepliesEnd = true;
            var messageContainer = self.container.find('.js--chat-message-container');
            var messageBase = self.initMessageField(message, 'message');
            //System messages should be displayed without the author and visible only fow owner and moderators
            if (message.IsSystemMessage || SystemMessage) {
                if (self.userId == self.ownerID || self.userId == self.moderatorId) {
                    messageBase.find('.chat-message-text > span').addClass("messageFromServer"); // add Class to change message style
                    messageBase.find('.chat-message-author-name').attr('hidden', "hidden");
                    messageBase.find('.chat-message-sent-date').attr('hidden', "hidden");
                    messageBase.find('.chat-message-header-line-commands').attr('hidden', "hidden");
                }
                else
                    return;
            }
         
            //reply message
            let messageReplyToBtn = messageBase.find('.chat-message-header-line-reply-to-btn');
            messageReplyToBtn.attr('data-message-id', message.ID);
            messageReplyToBtn.find('.chat-message-header-line').attr('data-user-id', message.FK_GlobalAccess);
            messageReplyToBtn.click(function (ev) {
                let clickedObj = jQuery(this);
                let clickedMessageId = clickedObj.attr('data-message-id');
                self.ReplyTo(clickedMessageId);
            });

            // delete message
            let messageSelectToBtn = messageBase.find('.js-delete-btn');
            messageSelectToBtn.attr('data-message-id', message.ID);
            messageSelectToBtn.click(function (ev) {
                let clickedObj = jQuery(this);
                self.deleteMessage(clickedObj);
            });

            //Ban user
            let banUserToBtn = messageBase.find('.js-ban-btn');
            banUserToBtn.attr('data-message-id', message.ID);
            banUserToBtn.click(function (ev) {
                let clickedObj = jQuery(this);
                self.banUser(clickedObj);
            });

            //Unblock user
            let unBlockUserToBtn = messageBase.find('.js-unblock-btn');
            unBlockUserToBtn.attr('data-message-id', message.ID);
            unBlockUserToBtn.click(function (ev) {
                let clickedObj = jQuery(this);
                self.unblockUser(clickedObj);
            });

            //load more replies
            let loadMoreMessage = messageBase.find('.js-load-more-replies');
            loadMoreMessage.attr('data-message-id', message.ID);
            loadMoreMessage.click(function (ev) {
                let clickedObj = jQuery(this);
                self.loadMoreReplies(clickedObj);
            });

            //Promote to moderator
            let promoteToModerator = messageBase.find('.js-moderator-btn');
            promoteToModerator.attr('data-message-id', message.ID);
            promoteToModerator.click(function (ev) {
                let clickedObj = jQuery(this);
                self.promoteToModerator(clickedObj);
            });

            //Demote from moderator
            let demoteFromModerator = messageBase.find('.js-demote-moderator-btn');
            demoteFromModerator.attr('data-message-id', message.ID);
            demoteFromModerator.click(function (ev) {
                let clickedObj = jQuery(this);
                self.demoteFromModerator(clickedObj);
            });
           
            //Show Hide replies
            if(message.HasReplies){
                messageBase.find('.js-chat-reply').show();
            }

            var isFirstLoad = true;

            //Show hide replies
            let toggleRepliensToBtn = messageBase.find('.js-toggle-replies');
            toggleRepliensToBtn.click(function(ev){
                self.showReplies(message.ID, isFirstLoad);
                isFirstLoad = false;
            });

            messageBase.show();

            if (self.isNoMessagesLabelVisible())
                self.HideNoMessagesLabel();

            if (isToTop)
                messageContainer.prepend(messageBase);
            else
                messageContainer.append(messageBase);

            // if scroll to the bottom, we will scroll to new messages
            if ((messageContainer[0].scrollHeight - messageContainer[0].scrollTop) < messageContainer[0].clientHeight + 250 || self.isMyMessage )
            {
                if(self.isLoadBottomEnd)
                    self.ScrollBottom();
            }
        }

        this.addRepliesToChat = function(message, isToTop, originalMessageId, fromHub, isTheRepliesEnd){
            let messageRow = self.findMessage(originalMessageId);
            var replyContainer = messageRow.find('.js-reply-container').first();
            var messageBase = self.initMessageField(message, 'replies');
           
            // delete message
            let messageSelectToBtn = messageBase.find('.js-delete-btn');
            messageSelectToBtn.attr('data-message-id', message.ID);
            messageSelectToBtn.click(function (ev) {
                let clickedObj = jQuery(this);
                self.deleteMessage(clickedObj);
            });

            //Ban user
            let banUserToBtn = messageBase.find('.js-ban-btn');
            banUserToBtn.attr('data-message-id', message.ID);
            banUserToBtn.click(function (ev) {
                let clickedObj = jQuery(this);
                self.banUser(clickedObj);
            });

            //Unblock user
            let unBlockUserToBtn = messageBase.find('.js-unblock-btn');
            unBlockUserToBtn.attr('data-message-id', message.ID);
            unBlockUserToBtn.click(function (ev) {
                let clickedObj = jQuery(this);
                self.unblockUser(clickedObj);
            });

            //Promote to moderator
            let promoteToModerator = messageBase.find('.js-moderator-btn');
            promoteToModerator.attr('data-message-id', message.ID);
            promoteToModerator.click(function (ev) {
                let clickedObj = jQuery(this);
                self.promoteToModerator(clickedObj);
            });

            //Demote from moderator
            let demoteFromModerator = messageBase.find('.js-demote-moderator-btn');
            demoteFromModerator.attr('data-message-id', message.ID);
            demoteFromModerator.click(function (ev) {
                let clickedObj = jQuery(this);
                self.demoteFromModerator(clickedObj);
            });
            
            if(isTheRepliesEnd){
                messageRow.find('.js-load-more-replies').hide();
            }
            if(isTheRepliesEnd == false){
                messageRow.find('.js-load-more-replies').show();
            }

            messageBase.show();

            if (!isToTop){
                replyContainer.prepend(messageBase);
            }
            else{
                if(fromHub){ // if the message comes from js, we only need to display a new message, without a reply container
                    if(messageRow.find('.js-chat-reply').css('display') == 'none'){
                        messageRow.find('.js-chat-reply').show();
                        messageRow.find('.js-toggle-replies').hide();
                    }
                    var replyContainerFromHub = messageRow.find('.js-reply-container-fromHub').last();
                    replyContainerFromHub.append(messageBase);
                    messageRow.find('.js-replies').show();
                    replyContainerFromHub.show();
                }
                else{
                replyContainer.append(messageBase);
                replyContainer.show();
                }
            }

            var messageContainer = self.container.find('.js--chat-message-container');
            // if scroll to the bottom, we will scroll to new messages
            if ((messageContainer[0].scrollHeight - messageContainer[0].scrollTop) < messageContainer[0].clientHeight + 250)
            {
                self.ScrollBottom();
            }
        }

        this.addQuestionMessage = function (message, isToTop, SystemMessage) {
            var messageContainer = self.container.find('.js--chat-question-container');
            var messageBase = self.container.find('.js--chat-question-base').clone();
            messageBase.find('.chat-message-author-name > span').text(message.Author);
            messageBase.find('.chat-message-text > span').html(message.MessageText);
            messageBase.removeClass("js--chat-question-base");
            messageBase.attr('data-question-id', message.ID);
            messageBase.find('.chat-message-header-line').attr('data-user-id', message.FK_GlobalAccess);

            // skip deleted message
            if (message.IsDeleted) {
                return;
            }

            //reply to question
            let messageReplyToBtn = messageBase.find('.chat-message-header-line-reply-to-btn');
            messageReplyToBtn.attr('data-message-id', message.ID);
            messageReplyToBtn.find('.chat-message-header-line').attr('data-user-id', message.FK_GlobalAccess);
            messageReplyToBtn.click(function (ev) {
                let clickedObj = jQuery(this);
                let clickedMessageId = clickedObj.attr('data-message-id');
                self.ReplyTo(clickedMessageId);
            });

            //close question
            let closeQuestionToBtn = messageBase.find('.js-chat-question-to-cancel-btn');
            closeQuestionToBtn.attr('data-message-id', message.ID);
            closeQuestionToBtn.click(function (ev) {
                let clickedObj = jQuery(this);
                let clickedMessageId = clickedObj.attr('data-message-id');

                k12PopupEFX.Confirm('Close this question?', function () {
                    if (self.isConnected) {
                        if (clickedMessageId > 0) {
                            // Call the delete method on the hub.
                            self.chat.server.answer(clickedMessageId, self.ownerID, self.userId);
                        } else {
                            k12PopupEFX.Alert("Please, Select Message");
                        }
                    } else {
                        k12PopupEFX.btnContinue.SetText("Ok");
                        k12PopupEFX.Alert("Please, wait you're not connected to the server yet. <br />If you're waiting too long then try to refresh the page.");
                    }
                });
            });

            //scroll to message in chat
            let questionMesage = messageBase.find('.chat-message-text');
            questionMesage.attr('data-message-id', message.ID);
            questionMesage.click(function (ev) {
                let questionMesage = self.container.find('.chat-message[data-question-id=' + message.ID + ']');
                if (questionMesage != null && questionMesage.length > 0) {
                    self.ScrollToMessage(message.ID);
                } 
            });

            messageBase.show();

            if (isToTop)
                messageContainer.prepend(messageBase);
            else
                messageContainer.append(messageBase);

            if (userId == ownerID) {
            self.ScrollBottomQuestion();
            }

            self.container.find('.chat-question-body').show();

        }


        this.deleteMessage = function(clickedObj){
            let clickedMessageId = clickedObj.attr('data-message-id');
            k12PopupEFX.Confirm('Do you want to delete this message?', function () {
                if (self.isConnected) {
                    if (clickedMessageId > 0) {
                        // Call the delete method on the hub.
                        self.chat.server.delete(clickedMessageId, channelName, userId);
                    } else {
                        k12PopupEFX.Alert("Please, Select Message");
                    }
                } else {
                    k12PopupEFX.btnContinue.SetText("Ok");
                    k12PopupEFX.Alert("Please, wait you're not connected to the server yet. <br />If you're waiting too long then try to refresh the page.");
                }
            });
        }
        
        this.banUser = function(clickedObj){

            let clickedMessageId = clickedObj.attr('data-message-id');
            k12PopupEFX.Confirm('Do you want to ban this user?', function () {
                if (self.isConnected) {
                    if (clickedMessageId > 0) {
                        // Call the Ban method on the hub.
                        self.chat.server.banUser(channelName, clickedMessageId, userId);
                    } else {
                        k12PopupEFX.Alert("Please, Select Message");
                    }
                } else {
                    k12PopupEFX.btnContinue.SetText("Ok");
                    k12PopupEFX.Alert("Please, wait you're not connected to the server yet. <br />If you're waiting too long then try to refresh the page.");
                }
            });
        }

        this.unblockUser = function(clickedObj){
            let clickedMessageId = clickedObj.attr('data-message-id');
            k12PopupEFX.Confirm('Unblock this user?', function () {
                if (self.isConnected) {
                    if (clickedMessageId > 0) {
                        // Call the unBlock method on the hub.
                        self.chat.server.unBlockUser(channelName, clickedMessageId, userId);
                    } else {
                        k12PopupEFX.Alert("Please, Select Message");
                    }
                } else {
                    k12PopupEFX.btnContinue.SetText("Ok");
                    k12PopupEFX.Alert("Please, wait you're not connected to the server yet. <br />If you're waiting too long then try to refresh the page.");
                }
            });
        }

        this.loadMoreReplies = function(clickedObj){
            let clickedMessageId = clickedObj.attr('data-message-id');
            let selectedMessage = self.findMessage(clickedMessageId);
            let replyContainer = selectedMessage.find('.js-reply-container').first();
            var lastMessage = replyContainer.find('.chat-message').last();
            var lastMessageId = lastMessage.attr('data-message-id');
            var replyContainerFromHub = selectedMessage.find('.js-reply-container-fromHub').last();
            replyContainerFromHub.find('.chat-message').remove();

            self.GetRepliedMessages(clickedMessageId, lastMessageId, 0);
            selectedMessage.find('.js-toggle-replies-bottom').show();
        }

        this.promoteToModerator = function(clickedObj){

            let clickedMessageId = clickedObj.attr('data-message-id');
            k12PopupEFX.Confirm('Do you want to promote this user to moderator?', function () {
                if (self.isConnected) {
                    if (clickedMessageId > 0) {
                        // Call the promoteToModerator method on the hub.
                        self.chat.server.promoteToModerator(channelName, clickedMessageId, userId);
                    } else {
                        k12PopupEFX.Alert("Please, Select Message");
                    }
                } else {
                    k12PopupEFX.btnContinue.SetText("Ok");
                    k12PopupEFX.Alert("Please, wait you're not connected to the server yet. <br />If you're waiting too long then try to refresh the page.");
                }
            });
        }

        this.demoteFromModerator = function(clickedObj){

            let clickedMessageId = clickedObj.attr('data-message-id');
            k12PopupEFX.Confirm('Do you want to Demote this user from moderators?', function () {
                if (self.isConnected) {
                    if (clickedMessageId > 0) {
                        // Call the promoteToModerator method on the hub.
                        self.chat.server.demoteFromModerator(channelName, clickedMessageId, userId);
                    } else {
                        k12PopupEFX.Alert("Please, Select Message");
                    }
                } else {
                    k12PopupEFX.btnContinue.SetText("Ok");
                    k12PopupEFX.Alert("Please, wait you're not connected to the server yet. <br />If you're waiting too long then try to refresh the page.");
                }
            });
        }

        this.deleteMessageObj = function (message) {
            // delete Message by Id
            let selectedMessage = self.findMessage(message.ID);
            if (typeof selectedMessage != 'undefined' && selectedMessage != null) {
                let messageTex = selectedMessage.find('.chat-message-text > span').text();
                selectedMessage.find('.chat-message-text > span').first().addClass("messageFromServer"); // add Class to change message style
                selectedMessage.find('.chat-message-text > span').first().text("\"Deleted message\"");
                selectedMessage.find('.chat-message-header-line-reply-to-btn').first().addClass("hideButton");
                selectedMessage.find('.js-delete-btn').first().addClass("hideButton");
                selectedMessage.find('.js-question-icon').first().addClass("hideButton");

                //remove message for non-author users
                if (userId != ownerID && self.userId != self.moderatorId) {
                    selectedMessage.remove();  //delete message from chat
                }
            }
            let selectedQuestion = self.container.find('.chat-message[data-question-id=' + message.ID + ']');
            selectedQuestion.hide();

            // delete all replies by Message Id
            let replyMessage = self.container.find('.chat-message-replied-to-section[data-reply-id=' + message.ID + ']');
            replyMessage.find('.chat-message-replied-to-message').html("\"Deleted message\"");

            // hide replies section if all replies deleted
            let originalMessage = self.findMessage(message.FK_OnlineChatMessageReplyTo);
            let chatReply = originalMessage.find('.js-chat-reply');
            if(chatReply.find('.chat-message').length == 0){
                chatReply.hide();
            }
        }

        this.banUserObj = function (message) {
            let selectedMessage = self.container.find('.chat-message-header-line[data-user-id=' + message.FK_GlobalAccess + ']');
            if (typeof selectedMessage != 'undefined' && selectedMessage != null) {
                selectedMessage.find('.js-ban-btn').addClass("hideButton");
                selectedMessage.find('.js-unblock-btn').removeClass("hideButton");
            }
            if(userId == ownerID){
                selectedMessage.find('.js-moderator-btn').addClass("hideButton"); // hide moderator button for banned users
            }
        }

        this.unBlockUserObj = function (message) {
            let selectedMessage = self.container.find('.chat-message-header-line[data-user-id=' + message.FK_GlobalAccess + ']');
            if (typeof selectedMessage != 'undefined' && selectedMessage != null) {
                selectedMessage.find('.js-ban-btn').removeClass("hideButton");
                selectedMessage.find('.js-unblock-btn').addClass("hideButton");
            }
            if(userId == ownerID){
                selectedMessage.find('.js-moderator-btn').removeClass("hideButton"); // show moderator button for unbanned users
            }
        }
        
        this.answerObj = function (message) {
            let selectedMessage = self.findMessage(message.ID);
            if (typeof selectedMessage != 'undefined' && selectedMessage != null) {
                selectedMessage.find('.js-question-icon').addClass("hideButton");
                selectedMessage = self.container.find('.chat-message[data-question-id=' + message.ID + ']').remove();
            }

            let questionContainer = self.container.find('.js--chat-question-container');
            var container = questionContainer.find('.chat-message');
            if (container.length <= 1) {
                self.container.find('.chat-question-body').hide();
            }
        }

        this.promoteUserToModeratorObj = function(message){
            let selectedMessage = self.container.find('.chat-message-header-line[data-user-id=' + message.FK_GlobalAccess + ']');

            self.moderatorId = self.userId;
            self.container.find('.js-admin-panel').show();
            self.container.find('.js-delete-btn').removeClass("hideButton");
            self.container.find('.js-question-panel').show();
            self.container.find('.js--btn-chat-send-question').hide();

            selectedMessage.find('.js-admin-panel').hide();
            //find all moderators and also hide admin panel
        }

        this.promoteToModeratorObj = function(message){
            let selectedMessage = self.container.find('.chat-message-header-line[data-user-id=' + message.FK_GlobalAccess + ']');
            let otherModerator = self.container.find('.js-moderator-icon').not('.hideButton').parents('.chat-message'); // find all messages from moderator
            if (typeof selectedMessage != 'undefined' && selectedMessage != null) {
                selectedMessage.find('.js-moderator-btn').addClass("hideButton");
                selectedMessage.find('.js-demote-moderator-btn').removeClass("hideButton");
                selectedMessage.find('.js-moderator-icon').removeClass("hideButton");
            }
            if(userId != ownerID){
                selectedMessage.find('.js-admin-panel').hide();
                otherModerator.find('.js-admin-panel').hide(); // hide admin panel on moderator message
            } 
        }

        this.demoteUserFromModeratorObj = function(message){
            let selectedMessage = self.container.find('.chat-message-header-line[data-user-id=' + message.FK_GlobalAccess + ']');

            self.moderatorId = 0;
            var allMessage = self.container.find('.js-admin-panel').hide();
            self.container.find('.js-delete-btn').addClass("hideButton");
            self.container.find('.js-question-panel').hide();
            self.container.find('.js--btn-chat-send-question').show();
            selectedMessage.find('.js-delete-btn').removeClass("hideButton");
        }

        this.demoteFromModeratorObj = function(message){
            let selectedMessage = self.container.find('.chat-message-header-line[data-user-id=' + message.FK_GlobalAccess + ']');
            if (typeof selectedMessage != 'undefined' && selectedMessage != null) {
                selectedMessage.find('.js-moderator-btn').removeClass("hideButton");
                selectedMessage.find('.js-demote-moderator-btn').addClass("hideButton");
                selectedMessage.find('.js-moderator-icon').addClass("hideButton");
            }
            if(self.moderatorId > 0){
                selectedMessage.find('.js-admin-panel').show();
                //if(message.IsBanned){
                //    selectedMessage.find('.js-unblock-btn').removeClass("hideButton");
                //}
                //else
                //    selectedMessage.find('.js-ban-btn').removeClass("hideButton");
            }
        }

        this.ReplyTo = function (replyToMessageId) {
            let replyToSection = self.container.find('.chat-reply-to-section');
            replyToSection.attr('data-message-id', replyToMessageId);
            let clickedMessage = self.findMessage(replyToMessageId);

            if(typeof(clickedMessage) != 'undefined' && clickedMessage != null) {
                let clickedMessageText = clickedMessage.find('.chat-message-text > span').first().text();
                let clickedMessageAuthorName = clickedMessage.find('.chat-message-author-name > span').first().text();
                if (typeof(clickedMessageText) != 'undefined' && clickedMessageText != null) {
                    if (clickedMessageText.length > 50)
                        clickedMessageText = clickedMessageText.slice(0,50) + ' ...';
                    self.container.find('.chat-reply-to-message > span').html(clickedMessageText);
                }
                if(typeof(clickedMessageAuthorName) != 'undefined' && clickedMessageAuthorName != null) {
                    self.container.find('.js--reply-to-author-name').html(clickedMessageAuthorName);
                }
            }

            self.container.find('.chat-ask-question-section').hide();
            self.container.find('.chat-ask-question-section').attr('data-question-message', 'false');

            replyToSection.show();
            //self.ScrollToChatSection();
            let messageContainer = self.container.find('.js--txt-chat-message');
            messageContainer.focus();
        }

        this.IsValidMessage = function() {
            var val = self.container.find('.js--txt-chat-message').val();
            return val && val != null && val.length != null && val.length > 0
                && (val.replace(/^\s+|\s+$/g, "").length != 0);
        }
        
        this.ClearInput = function () {
            self.container.find('.js--txt-chat-message').val('').text('').focus();
        }

        this.GetNextMessages = function (fromMessageId, isScrollBottomAfterLoad, notificationMessageId) {
            if (fromMessageId == null)
                fromMessageId = 0;

            if(notificationMessageId == null)
                notificationMessageId = 0;
                   
            if (!self.isLoadingMessages) {

                self.showLoadMessagesIndicator();
                self.isLoadingMessages = true;

                $.ajax({
                    type: "POST",
                    url: domainUrl + "/Services/EventsService.asmx/GetOnlineChatMessages",
                    contentType: "application/json; charset=utf-8",
                    async: true,
                    data: JSON.stringify({ 'chatid': self.chatId, 'fromMessageId': fromMessageId, 'size': self.messageCount, 'channel': channelName, 'notificationMessageId': notificationMessageId, 'isLoadBottom': false  }),
                    dataType: "json",
                    success: function (data) {
                        if (data != null) {
                            if (typeof data.d != 'undefined' && data.d != null &&
                                typeof data.d.length != 'undefined' && data.d.length != null
                                && data.d.length > 0) {
                                var isToTop = true;
                                self.PushMessagesToChat(data.d, isToTop, isScrollBottomAfterLoad);
                                self.hideLoadMessagesIndicator();
                            } else {
                                if(self.isFirstLoad){
                                    self.ShowNoMessagesLabel();
                                }
                                self.hideLoadMessagesIndicator();
                                self.isTheEnd = true;
                            }
                        } 
                        else {
                            self.hideLoadMessagesIndicator();
                            self.isTheEnd = true;
                        }

                        self.isFirstLoad = false;
                        self.isLoadingMessages = false;
                                               
                        if (isScrollBottomAfterLoad) {
                            self.scrollToNotificationMessage();
                        }
                    },
                    error: function (xhr, status, error) {
                        console.error('GetOnlineChatMessages Service not Responding');
                        self.isLoadingMessages = false;
                        // if we get an error, we should try again with the default settings
                        if(self.isErrorLoad == false){
                            self.isErrorLoad = true;
                            self.GetNextMessages(null, isScrollBottomAfterLoad, null);
                        }
                    }
                });
            }
        }

        this.GetNextMessagesToBottom = function (fromMessageId, loadAll) {
            if (fromMessageId == null)
                fromMessageId = 0;
            
            var messageCount = self.messageCount
            if(loadAll == true)
                messageCount = 100;

            if (!self.isLoadingMessages) {
                self.showLoadMessagesIndicator();
                self.isLoadingMessages = true;
                $.ajax({
                    type: "POST",
                    url: domainUrl + "/Services/EventsService.asmx/GetOnlineChatMessages",
                    contentType: "application/json; charset=utf-8",
                    async: true,
                    data: JSON.stringify({ 'chatid': self.chatId, 'fromMessageId': fromMessageId, 'size': messageCount, 'channel': channelName, 'notificationMessageId': 0, 'isLoadBottom': true }),
                    dataType: "json",
                    success: function (data) {
                        if (data != null) {

                            if (typeof data.d != 'undefined' && data.d != null &&
                                typeof data.d.length != 'undefined' && data.d.length != null
                                && data.d.length > 0) {
                                self.PushMessagesToChat(data.d, false, false);

                                self.hideLoadMessagesIndicator();
                            } else {
                                self.hideLoadMessagesIndicator();
                                self.isLoadBottomEnd = true;
                            }
                        } 
                        else {
                            self.hideLoadMessagesIndicator();
                            self.isLoadBottomEnd = true;
                        }

                        self.isLoadingMessages = false;

                        if(loadAll){
                            if(!self.isLoadBottomEnd){
                                self.loadAllMessage();
                            }
                            else{
                                self.ScrollBottomAnimated();
                            }
                        }
                    },
                    error: function (xhr, status, error) {
                        console.error('GetOnlineChatMessages Service not Responding');
                        self.isLoadingMessages = false;
                         //if we get an error, we should try again with the default settings
                        //if(self.isErrorLoad == false){
                        //    self.isErrorLoad = true;
                        //    self.GetNextMessages(null, isScrollBottomAfterLoad, null);
                        //}
                    }
                });
            }
        }

        this.GetRepliedMessages = function(id, lastRepliesId, scrollToMessageId, isFirstLoad){
            self.showLoadRepliesIndicator(id);
            var isToTop = false;
            if(lastRepliesId > 0)
                isToTop = true;

            if(scrollToMessageId == null)
                scrollToMessageId = 0;

            var isTheRepliesEnd = false;
            $.ajax({
                type: "POST",
                url: domainUrl + "/Services/EventsService.asmx/GetRepliedMessages",
                contentType: "application/json; charset=utf-8",
                async: true,
                data: JSON.stringify({ 'messageId': id, 'lastRepliesId': lastRepliesId, 'size': self.repliesCount, 'channel': channelName, 'notificationMessageId': scrollToMessageId}),
                dataType: "json",
                success: function (data) {
                    if (data != null) {
                        if (typeof data.d != 'undefined' && data.d != null &&
                            typeof data.d.length != 'undefined' && data.d.length != null
                            && data.d.length > 0) {
                            if(data.d.length < self.repliesCount){
                                isTheRepliesEnd = true;
                            }
                            self.PushRepliesToChat(data.d, id, isToTop, isTheRepliesEnd);
                        }
                        else{
                            var  messageRow = self.findMessage(id);

                            if(isFirstLoad)
                                messageRow.find('.js-chat-reply').hide();

                            messageRow.find('.js-load-more-replies').hide();
                        }
                    } 
                    else {
                        self.hideLoadRepliesIndicator(id);
                    }
                    self.hideLoadRepliesIndicator(id);

                    if (scrollToMessageId > 0) {

                        setTimeout(function(){
                            self.ScrollToMessage(scrollToMessageId);
                        }, 500);
                    }
                },
                error: function (xhr, status, error) {
                    if(self.isErrorLoad == false){
                        self.isErrorLoad = true;
                        self.GetRepliedMessages(id);
                    }
                    console.error('GetOnlineChatReplies Service not Responding');
                }
            });
        }

        this.ShowNoMessagesLabel = function() {
            self.container.find('.js--chat-no-messages').show();
        }

        this.HideNoMessagesLabel = function() {
            self.container.find('.js--chat-no-messages').hide();
        }

        this.isNoMessagesLabelVisible = function () {
            var label = self.container.find('.js--chat-no-messages');
            if (label.css('display') != 'none')
                return true;
            return false;
        }

        this.PushMessagesToChat = function(messages, isToTop, isScrollBottomAfterLoad) {
            if (messages != null) {
                for (var i = 0; i < messages.length; i++) {
                    var message = messages[i];
                    if (message != null) {
                        self.addMessageObj(message, isToTop);
                        if (message.IsQuestion) {
                            self.addQuestionMessage(message, isToTop);
                        }
                    }
                }
            }
        }

        this.PushRepliesToChat = function(messages, originalMessageId, isToTop, isTheRepliesEnd){
            if(isTheRepliesEnd != true)
                isTheRepliesEnd = false;
            for (var i = 0; i < messages.length; i++) {
                var message = messages[i];
                if (message != null) {
                    self.addRepliesToChat(message, isToTop, originalMessageId, false, isTheRepliesEnd);
                }
            }
        }

        this.ScrollBottom = function () {
            let chatContainer = self.container.find('.js--chat-message-container');
            chatContainer.scrollTop(chatContainer[0].scrollHeight);
        }

        this.ScrollBottomAnimated = function () {
            let chatContainer = self.container.find('.js--chat-message-container');
            chatContainer.animate({
                scrollTop: (chatContainer[0].scrollHeight)
            });
        }
    
        this.ScrollBottomQuestion = function () {
            let questionContainer = self.container.find('.js--chat-question-container');
            questionContainer.scrollTop(questionContainer[0].scrollHeight);
        }

        this.scrollToMessageAnimated = function(messageId){
            let chatContainer = self.container.find('.js--chat-message-container');
            let messageContainer = self.findMessage(messageId);
            if (messageContainer.length > 0) {
                chatContainer.animate({
                    scrollTop: parseInt(messageContainer.offset().top - chatContainer.offset().top + chatContainer.scrollTop())
                },
                500,
                null,
                function () {
                    messageContainer.removeClass('chat-message-highlight-out').addClass('chat-message-highlight-in');
                    setTimeout(function () {
                        messageContainer.removeClass('chat-message-highlight-in').addClass('chat-message-highlight-out');
                    }, 1000);
                });
            }
        }

        this.ScrollToMessage = function (messageId) {
            let chatContainer = self.container.find('.js--chat-message-container');
            let messageContainer = self.findMessage(messageId);
            if (messageContainer.length > 0) {
                //chatContainer.animate({
                //    scrollTop: parseInt(messageContainer.offset().top - chatContainer.offset().top + chatContainer.scrollTop())
                //},
                //500,
                //null,
                //function () {
                //    messageContainer.removeClass('chat-message-highlight-out').addClass('chat-message-highlight-in');
                //    setTimeout(function () {
                //        messageContainer.removeClass('chat-message-highlight-in').addClass('chat-message-highlight-out');
                //    }, 1000);
                //});

                chatContainer.scrollTop(parseInt(messageContainer.offset().top - chatContainer.offset().top + chatContainer.scrollTop()));
                messageContainer.removeClass('chat-message-highlight-out').addClass('chat-message-highlight-in');
                    setTimeout(function () {
                        messageContainer.removeClass('chat-message-highlight-in').addClass('chat-message-highlight-out');
                    }, 1000);

            }
        }

        //scroll to notification message on page load
        this.scrollToNotificationMessage = function(){
            //scroll to notification message id
            if (self.notificationMessageId > 0) {
                if(self.notificationRepliesId > 0){
                    let messageRow = self.findMessage(self.notificationMessageId);
                    var replyContainer = messageRow.find('.js-reply-container');

                    // if the reply container is hidden, we need to upload replies to the message
                    if(replyContainer.css('display') == 'none'){
                        var isFirstLoad = false;
                        self.showReplies(self.notificationMessageId, false)
                        self.GetRepliedMessages(self.notificationMessageId, 0, self.notificationRepliesId);
                    }
                    else{
                        setTimeout(function(){
                            self.ScrollToMessage(self.notificationRepliesId);
                        }, 1);
                    }
                  
                    self.notificationMessageId = 0;
                }
                else{
                    self.ScrollToMessage(self.notificationMessageId);
                }
            }
            else{
                setTimeout(function () {
                    self.ScrollBottom();
                }, 1);
            }
        }

        this.ScrollToChatSection = function () {
            $([document.documentElement, document.body]).animate({
                scrollTop: $(".js--txt-chat-message").offset().top
            }, 500);

            let messageContainer = self.container.find('.js--txt-chat-message');
            messageContainer.focus();
        }

        this.showLoadMessagesIndicator = function () {
            self.container.find('.js--loading-message-indicator').show();
        }

        this.hideLoadMessagesIndicator = function () {
            self.container.find('.js--loading-message-indicator').hide();
        }

        this.showLoadRepliesIndicator = function(id){
            let messageRow = self.findMessage(id);
            messageRow.find('.js--loading-replies-indicator').show();
        }

        this.hideLoadRepliesIndicator = function(id){
            let messageRow = self.findMessage(id);
            messageRow.find('.js--loading-replies-indicator').hide();
        }

        this.changeViewText = function(isHide, obj){
            if(isHide){
                obj.find('.js-toggle-replies-bottom').html('&#11165' + ' Hide replies ' + '&#11165');
                obj.find('.js-toggle-replies').html('&#11165' + ' Hide replies ' + '&#11165');
                obj.find('.js-replies').show();
            }
            else{
                obj.find('.js-toggle-replies').html('&#11167' + ' View replies ' + '&#11167');
                obj.find('.js-toggle-replies-bottom').html('&#11167' + ' View replies ' + '&#11167');
                obj.find('.js-replies').toggle('fast');
            }
        }

        this.DisabledFuncAfterStopStream = function(){
            self.chat.server.disabledFuncAfterStopStream();
        }

        this.DisabledChatFuncObj = function () {
            self.container.find('.chat-message-header-line-commands').addClass('disabled-icon');
            self.container.find('.js--btn-chat-send-message').addClass('disabled-button'); //val('').text('').focus();
            self.container.find('.txt-message-wrapper span').addClass('disabled-span');
            self.container.find('.txt-message-wrapper .js--txt-chat-message').addClass('disabled-textarea');
            self.container.find('.txt-message-wrapper .js--txt-chat-message').blur();
            self.container.find('.js--btn-chat-send-question').addClass('disabled-button');
        }
        
        let searchParams = new URLSearchParams(window.location.search);
        if (searchParams.has('m') && $('#divComments').hasClass('hidden-tab')) {
            var url = $(location).attr("href");
            self.notificationMessageId = searchParams.get('m').split('/')[0];
            self.notificationRepliesId = searchParams.get('m').split('/')[1];
        }
        else{
            self.isLoadBottomEnd = true;
        }

        //display question panel
        if(userId == ownerID || (self.userId != 0 && self.userId == self.moderatorId)){
            self.container.find('.js-question-panel').show();
            self.container.find('.js--btn-chat-send-question').hide();
        }

        this.InitLoadingMessages = function () {
            var isScrollBottomAfterLoad = true;
            self.GetNextMessages(0, isScrollBottomAfterLoad, self.notificationMessageId);

            let chatContainer = self.container.find('.js--chat-message-container');

            jQuery(chatContainer).scroll(function () {
                var scrolledEl = this;

                if ($(this).scrollTop() <= 300) {
                    if (!self.isTheEnd && !self.isFirstLoad && !self.isLoadingMessages) {
                        self.showLoadMessagesIndicator();
                        var chat = self.container.find('.js--chat-message-container');
                        var messages = chat.find('.chat-message:not(.js--chat-message-base)');
                        var lastMessage = messages.first();

                        var lastMessageId = lastMessage.attr('data-message-id');

                        isScrollBottomAfterLoad = false;
                        self.GetNextMessages(lastMessageId, isScrollBottomAfterLoad, 0);
                    }
                }

                if (self.isLoadBottomEnd == false && $(this)[0].scrollTop >= $(this)[0].scrollHeight - 700) {
                    var chat = self.container.find('.js--chat-message-container');
                    var messages = chat.find('.chat-message:not(.js--chat-message-base)');
                    var lastBottomMessage = messages.last();
                    var lastBottomMessageId = lastBottomMessage.attr('data-message-id');
                    var loadAll = false;
                    self.GetNextMessagesToBottom(lastBottomMessageId, loadAll);
                }
            });
        }

        //scroll to bottom button
        var messageContainer = self.container.find('.js--chat-message-container');
        messageContainer.scroll(function () {
            if ((messageContainer[0].scrollHeight - messageContainer[0].scrollTop) < messageContainer[0].clientHeight + 200) {
                self.container.find('.scroll-to-bottom-btn').addClass("hideButton");
            }
            else {
                self.container.find('.scroll-to-bottom-btn').removeClass("hideButton");
            }
        });

        //timer on send question button
        this.StartCooldown = function(duration){
            var cooldown = Math.round(new Date() / 1000) + duration;
            window.localStorage.setItem('Cooldown', cooldown);
           
            var timer = duration,
                minutes, seconds;
               
            minutes = parseInt(timer / 60, 10)
            seconds = parseInt(timer % 60, 10);
            minutes = minutes < 10 ? "0" + minutes : minutes;
            seconds = seconds < 10 ? "0" + seconds : seconds;

            self.container.find('.js--btn-chat-send-question').addClass('disabled-btn');
            self.container.find('.js--btn-chat-send-question').html("To next question " + minutes + ":" + seconds);

            var timerID = setInterval(function() {
                minutes = parseInt(timer / 60, 10)
                seconds = parseInt(timer % 60, 10);

                minutes = minutes < 10 ? "0" + minutes : minutes;
                seconds = seconds < 10 ? "0" + seconds : seconds;


                self.container.find('.js--btn-chat-send-question').html("To next question " + minutes + ":" + seconds);

                if (--timer < 0) {
                    clearInterval(timerID);
                    self.container.find('.js--btn-chat-send-question').removeClass('disabled-btn');
                    self.container.find('.js--btn-chat-send-question').html("SEND QUESTION");
                    window.localStorage.removeItem('Cooldown');
                }
            }, 1000);
        }

        //Initialization message field with data
        this.initMessageField = function(message, messageType){
            var messageBase = self.container.find('.js--chat-message-base').clone();

            messageBase.find('.chat-message-author-name > span').text(message.Author);
            messageBase.find('.chat-message-text > span').html(message.MessageText);
            messageBase.attr('data-message-id', message.ID);
            messageBase.find('.chat-message-header-line').attr('data-user-id', message.FK_GlobalAccess);

            switch (messageType){
                case 'message':
                    try {
                        let datetimeUTC = new Date(Date.parse(message.CreationDateJsFormat)).toUTCString();
                        // Local users time
                        messageBase.find('.chat-message-sent-date > span').text(this.getUsersLocalTime(new Date(new Date(datetimeUTC).getTime() - self.clientTZOffset * 60000)));
                    } catch (ex) {
                        messageBase.find('.chat-message-sent-date > span').text(message.CreationDateStr + " (GMT)");
                        console.log("Failed to convert time ("+message.CreationDateStr+")");
                    }
                    break;

                case 'replies':
                    messageBase.find('.chat-message-header-line-reply-to-btn').hide(); // hide reply button
                    messageBase.find('.chat-reply-sent-date').show();
                    messageBase.find('.js-chat-reply').remove();
                                      
                    try {
                        let datetimeUTC = new Date(Date.parse(message.CreationDateJsFormat)).toUTCString();
                        // Local users time
                        messageBase.find('.chat-reply-sent-date').text(this.getUsersLocalTime(new Date(new Date(datetimeUTC).getTime() - self.clientTZOffset * 60000)));
                    } catch (ex) {
                        messageBase.find('.chat-reply-sent-date').text(message.CreationDateStr + " (GMT)");
                        console.log("Failed to convert time ("+message.CreationDateStr+")");
                    }
                    break;
            }

            //Change style for deleted messages
            if (message.IsDeleted) {
                messageBase.find('.chat-message-text > span').addClass("messageFromServer"); // add Class to change message style
                messageBase.find('.chat-message-header-line-reply-to-btn').addClass("hideButton");
                messageBase.find('.js-delete-btn').addClass("hideButton");
                messageBase.find('.js-question-icon').addClass("hideButton");
            }

            // hide ban button for own message
            if (message.FK_GlobalAccess == userId || message.FK_GlobalAccess == ownerID) {
                messageBase.find('.js-ban-btn').addClass("hideButton");
            }

            // Hide moderator button if user already moderator
            if (message.IsModerator) {
                messageBase.find('.js-moderator-btn').addClass("hideButton");
                messageBase.find('.js-demote-moderator-btn').removeClass("hideButton");
            }

            //change button if user is banned
            if (message.IsBanned) {
                messageBase.find('.js-ban-btn').addClass("hideButton");
                messageBase.find('.js-unblock-btn').removeClass("hideButton");
                messageBase.find('.js-moderator-btn').addClass("hideButton"); // hide moderator button for banned users
            }

            //hide ban/unban button for moderator
            if(ownerID != userId && message.IsModerator && self.moderatorId > 0){
                messageBase.find('.js-ban-btn').addClass("hideButton");
                messageBase.find('.js-unblock-btn').addClass("hideButton");
                messageBase.find('.js-admin-panel').hide();
            }

            //show delete button for own message
            if (message.FK_GlobalAccess == userId || userId == ownerID || (userId != 0 && userId == self.moderatorId)) {
                messageBase.find('.js-delete-btn').removeClass("hideButton");
            }

            //display question icon if message is question
            if (message.IsQuestion) {
                messageBase.find('.js-question-icon').removeClass("hideButton");
            }

            //display moderator icon if message sent moderator
            if (message.IsModerator) {
                messageBase.find('.js-moderator-icon').removeClass("hideButton");
            }

            //display admin icon if message sent admonistrator
            if (message.FK_GlobalAccess == ownerID) {
                messageBase.find('.js-admin-icon').removeClass("hideButton");
            }

            //hide js-moderator-btn for non owner 
            if(userId != ownerID || message.FK_GlobalAccess == ownerID){
                messageBase.find('.js-moderator-btn').hide();
                messageBase.find('.js-demote-moderator-btn').hide();
            }

            // show admin panel for owner and moderators
            if(self.moderatorId > 0 || userId == ownerID){
                messageBase.find('.js-admin-panel').show();
            }

            messageBase.removeClass("js--chat-message-base");

            return messageBase;
        }

        //show replies
        this.showReplies = function(messageId, isFirstLoad){
            var messageRow = self.findMessage(messageId);
            let replyContainer = messageRow.find('.js-reply-container');
            let toggleBtn = messageRow.find('.js-toggle-replies');
            if(replyContainer.css('display') == 'none'){

                if(isFirstLoad){
                    var replyContainerFromHub = messageRow.find('.js-reply-container-fromHub');
                    replyContainerFromHub.find('.chat-message').remove();
                    self.GetRepliedMessages(messageId, 0, 0, isFirstLoad);
                    isFirstLoad = false;
                }
                self.changeViewText(true, messageRow);
            }
            else{
                self.changeViewText(false, messageRow);
            }
            messageRow.find('.js-reply-container').toggle('fast');
        }

        //finde message row by message id
        this.findMessage = function(messageId){
           return self.container.find('.chat-message[data-message-id=' + messageId + ']');
        }

        //Start load all message to bottom
        this.loadAllMessage = function(){   
            self.showLoadMessagesIndicator();

            var chat = self.container.find('.js--chat-message-container');
            var messages = chat.find('.chat-message:not(.js--chat-message-base)');
            var lastBottomMessage = messages.last();
            var lastBottomMessageId = lastBottomMessage.attr('data-message-id');
            var loadAll = true;
            self.GetNextMessagesToBottom(lastBottomMessageId, loadAll);
        }

        
        



    }
}(window, jQuery, moment);
;
