//
//  ChatGroupViewController.swift
//  WoWonder
//
//  Created by Mac on 19/11/22.
//  Copyright © 2022 ScriptSun. All rights reserved.
//

import UIKit
import AVFoundation
import AVKit
import Async
import CoreData
import IQKeyboardManagerSwift
import Toast_Swift
import SafariServices
import MapKit
import SDWebImage
import ContactsUI
import Contacts
import Stipop
import MediaPlayer
import WowonderMessengerSDK

class ChatGroupViewController: BaseVC {
    
    // MARK: - IBOutlets
    
    @IBOutlet weak var topView: UIView!
    @IBOutlet weak var headerView: UIView!
    @IBOutlet weak var backButton: UIControl!
    @IBOutlet weak var userProfileImageView: UIImageView!
    @IBOutlet weak var userNameLabel: UILabel!
    @IBOutlet weak var userActiveStatusLabel: UILabel!
    @IBOutlet weak var moreButton: UIButton!
    @IBOutlet weak var mediaButton: UIButton!
    @IBOutlet weak var stickerButton: SPUIButton!
    @IBOutlet weak var audioRecordButton: RecordButton!
    @IBOutlet weak var sendButton: UIButton!
    @IBOutlet weak var chatTableView: UITableView!
    @IBOutlet weak var messageTextView: EmojiTextView!
    @IBOutlet weak var bottomView: UIView!
    @IBOutlet weak var replyMessageView: UIView!
    @IBOutlet weak var replyMessageViewHeight: NSLayoutConstraint!
    @IBOutlet weak var replyBorderView: UIView!
    @IBOutlet weak var replyUserNameLabel: UILabel!
    @IBOutlet weak var replyMessageLabel: UILabel!
    @IBOutlet weak var replyImageView: UIImageView!
    @IBOutlet weak var replyCancelButton: UIButton!
    @IBOutlet weak var audioRecordView: RecordView!
    @IBOutlet weak var tableViewBottom: NSLayoutConstraint!
    @IBOutlet weak var sendView: UIView!
    @IBOutlet weak var audioRecordSendView: UIView!
    @IBOutlet weak var audioRecordSliderView: UISlider!
    @IBOutlet weak var audioRecordPlayButton: UIButton!
    @IBOutlet weak var audioRecordDeleteButton: UIButton!
    @IBOutlet weak var audioRecordSendButton: UIButton!
    @IBOutlet weak var audioRecordSendViewHeight: NSLayoutConstraint!
    @IBOutlet weak var sendMessageView: UIView!
    
    // MARK: - Properties
    
    var limit = 1000
    var messagesArray: [Messages] = []
    var groupData: GroupChat?
    var groupApiData: GroupData?
    private var toneStatus = false
    private var isReplyStatus = false
    private var replyMessageID = ""
    private var receiveMessageAudioPlayer: AVAudioPlayer?
    private var imagePicker = UIImagePickerController()
    private var audioFileURL: URL?
    var audioRecorderHelper: AudioRecorderHelper!
    var isSendRecordAudio = false
    var audioRecodeTimer: Timer?
    private var sendMessageAudioPlayer: AVAudioPlayer?
    var audioRecoderPlayer : AVAudioPlayer!
    var imagePickerMediaType: ImagePickerMediaType = .IMAGE
    let socketHelper = SocketHelper.shared
    
    // MARK: - View Life Cycles
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        
        self.initialConfig()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        AudioPlayerHelper.shared.delegate = self
        self.getGroupChatDataList()
        self.fetchData()
        self.replyMessageViewHeight.constant = 0
        self.replyMessageView.isHidden = true
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        self.removeObserver()
        IQKeyboardManager.shared.isEnabled = true
        self.audioRecoderPlayer?.pause()
        self.audioRecodeTimer?.invalidate()
        self.audioRecodeTimer = nil
        self.audioRecordPlayButton.setImage(UIImage(named: "icon_play_vector"), for: .normal)
        AudioPlayerHelper.shared.stopAudioPlayer()
        
        self.socketHelper.socket.off("group_message")
        self.socketHelper.socket.off("register_reaction")
    }
    
    // MARK: - Selectors
    
    // Back Button Action
    @IBAction func backButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        self.navigationController?.popViewController(animated: true)
    }
    
    // Group Info Button Action
    @IBAction func groupInfoButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if let newVC = R.storyboard.group.groupInfoViewController() {
            newVC.groupData = self.groupApiData
            self.navigationController?.pushViewController(newVC, animated: true)
        }
    }
    
    // More Button Action
    @IBAction func moreButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if let newVC = R.storyboard.group.groupBottomMoreVC() {
            newVC.modalPresentationStyle = .custom
            newVC.transitioningDelegate = self
            newVC.delegate = self
            newVC.groupData = self.groupData
            self.present(newVC, animated: true)
        }
    }
    
    // Media Button Action
    @IBAction func mediaButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if let newVC = R.storyboard.chat.chatMediaOptionVC() {
            newVC.modalPresentationStyle = .custom
            newVC.transitioningDelegate = self
            newVC.delegate = self
            self.present(newVC, animated: true)
        }
    }
    
    // Emoji Button Action
    @IBAction func emojiButtonAction(_ sender: UIButton) {
        self.messageTextView.isEmojiKeyboard = true
        self.messageTextView.becomeFirstResponder()
    }
    
    // Send Button Action
    @IBAction func sendButtonAction(_ sender: UIButton) {
        if messageTextView.text != "" {
            self.socketHelper.emit_group_message(groupId: self.groupData?.group_id ?? "", accessToken: AppInstance.instance._sessionId, username: AppInstance.instance.userProfile?.username ?? "", msg: self.messageTextView.text, messageReplyId: self.replyMessageID) {
                self.view.resignFirstResponder()
                if self.toneStatus {
                    self.playSendMessageSound()
                } else {
                    print("To play sound please enable conversation tone from settings..")
                }
                self.messageTextView.text = ""
                self.setSendButton()
                if self.isReplyStatus {
                    self.hideReplyMessageView()
                }
                self.fetchData()
            }
            // self.sendMessage(text: messageTextView.text, lat: 0, lng: 0)
        }
    }
    
    // Audio Record Play Button Action
    @IBAction func audioRecordPlayButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if self.audioRecoderPlayer.isPlaying {
            self.audioRecoderPlayer?.pause()
            self.audioRecodeTimer?.invalidate()
            self.audioRecodeTimer = nil
            self.audioRecordPlayButton.setImage(UIImage(named: "icon_play_vector"), for: .normal)
        } else {
            self.audioRecoderPlayer?.play()
            self.audioRecodeTimer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.updatePlaybackProgress), userInfo: nil, repeats: true)
            self.audioRecordPlayButton.setImage(UIImage(named: "icon_pause_vector"), for: .normal)
        }
    }
    
    @IBAction func audioRecordSliderValueChanged(_ sender: UISlider) {
        self.audioRecoderPlayer?.currentTime = TimeInterval(sender.value)
    }
    
    @objc func updatePlaybackProgress() {
        self.audioRecordSliderView.value = Float(self.audioRecoderPlayer.currentTime)
    }
    
    // Audio Record Delete Button Action
    @IBAction func audioRecordDeleteButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        self.hideAudioRecordView()
    }
    
    // Audio Record Send Button Action
    @IBAction func audioRecordSendButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        if self.isSendRecordAudio {
            if let audioFileURL = self.audioFileURL {
                let audioData = try? Data(contentsOf: audioFileURL)
                let fileExtension = String(audioFileURL.lastPathComponent.split(separator: ".").last!)
                self.sendSelectedData(type: "audio", imageData: nil, imageMimeType: nil, videoData: nil, videoMimeType: nil, fileData: nil, fileExtension: nil, fileMimeType: nil, audio: audioData, audioExtension: fileExtension, audioMimeType: audioData?.mimeType)
            }
        }
        self.isSendRecordAudio = false
        self.hideAudioRecordView()
    }
    
    // Cancel Reply Button Action
    @IBAction func cancelReplyButtonAction(_ sender: UIButton) {
        self.view.endEditing(true)
        self.hideReplyMessageView()
    }
    
    // MARK: - Helper Functions
    
    // initial Config
    func initialConfig() {
        self.setData()
        self.setUpMessageTextView()
        self.registerCell()
        self.setObserver()
        self.setUpAudioRecordView()
        IQKeyboardManager.shared.isEnabled = false
        AudioPlayerHelper.shared.delegate = self
        self.stickerButton.setUser(SPUser(userID: AppInstance.instance._userId), viewType: .picker)
        self.stickerButton.delegate = self
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
        self.view.addGestureRecognizer(tapGesture)
        let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressed))
        self.chatTableView.addGestureRecognizer(longPressRecognizer)
        self.audioRecordSliderView.setThumbImage(UIImage(named: "left_slider_thumb"), for: .normal)
        self.audioRecordSliderView.setThumbImage(UIImage(named: "left_slider_thumb"), for: .highlighted)
        self.getScoketResposeData()
    }
    
    func getScoketResposeData() {
        self.socketHelper.on_group_message { data in
            print("on_group_message >>>>> ", data)
            let result = data.first as? [String: Any]
            let socket_group_data = result?["group_data"] as? [String: Any]
            if self.groupData?.group_id == "\((socket_group_data?["group_id"] as? Int) ?? 0)" {
                self.fetchData()
            }
        }
        
        self.socketHelper.on_register_reaction { data in
            print("Register Reaction >>>>> ", data)
            self.fetchData()
        }
    }
    
    // Set Observer
    func setObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    // Remove Observer
    func removeObserver() {
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    // Keyboard Will Show
    @objc func keyboardWillShow(_ notification: NSNotification) {
        let userInfo = notification.userInfo!
        let bottom = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.height
        self.tableViewBottom.constant = bottom - self.view.safeAreaBottom
        let duration: TimeInterval = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
        UIView.animate(withDuration: duration) {
            if self.messagesArray.count != 0 {
                self.chatTableView.scrollToLastRow(animated: false)
            }
            self.view.layoutIfNeeded()
        }
    }
    
    // Keyboard Will Hide
    @objc func keyboardWillHide(_ notification: NSNotification) {
        let userInfo = notification.userInfo!
        self.tableViewBottom.constant = 0
        let duration: TimeInterval = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber).doubleValue
        UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() }
    }
    
    // Register Cell
    func registerCell() {
        self.chatTableView.delegate = self
        self.chatTableView.dataSource = self
        if #available(iOS 15.0, *) {
            UITableView.appearance().isPrefetchingEnabled = false
        }
        self.chatTableView.register(UINib(resource: R.nib.leftTextTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftTextTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightTextTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightTextTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightImageTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightImageTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftImageTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftImageTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftDocumentTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftDocumentTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightDocumentTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightDocumentTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftVideoTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftVideoTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightVideoTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightVideoTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightGifTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightGifTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftGifTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftGifTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftLocationTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftLocationTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightLocationTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightLocationTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftAudioTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftAudioTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightAudioTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightAudioTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftContactTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.leftContactTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightContactTableViewCell), forCellReuseIdentifier: R.reuseIdentifier.rightContactTableViewCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.rightStickerCell), forCellReuseIdentifier: R.reuseIdentifier.rightStickerCell.identifier)
        self.chatTableView.register(UINib(resource: R.nib.leftStickerCell), forCellReuseIdentifier: R.reuseIdentifier.leftStickerCell.identifier)
    }
    
    // SetUp Message TextView
    func setUpMessageTextView() {
        self.messageTextView.delegate = self
        self.messageTextView.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.messageTextView.addPlaceholder("Write your message", with: UIColor.text_color_in_between)
        self.setSendButton()
    }
    
    // SetUp Audio Record View
    func setUpAudioRecordView() {
        self.audioRecordView.durationTimerColor = .red
        self.audioRecordButton.recordView = self.audioRecordView
        self.audioRecordView.delegate = self
        self.audioRecordView.isHidden = true
        self.audioRecordSendView.isHidden = true
        self.audioRecordSendViewHeight.constant = 0
        self.audioRecorderHelper = AudioRecorderHelper()
        self.audioRecorderHelper.delegate = self
    }
    
    func showAudioRecordView() {
        self.audioRecordSendView.isHidden = false
        self.audioRecordSendViewHeight.constant = 78
        UIView.animate(withDuration: 0.5) {
            self.view.layoutIfNeeded()
        }
    }
    
    func hideAudioRecordView() {
        self.audioRecoderPlayer?.stop()
        self.audioRecodeTimer?.invalidate()
        self.audioRecodeTimer = nil
        self.audioRecordSliderView.value = 0
        self.audioRecordSendViewHeight.constant = 0
        UIView.animate(withDuration: 0.5, animations: {
            self.view.layoutIfNeeded()
        }) { _ in
            self.audioRecordSendView.isHidden = true
        }
    }
    
    // Set Data
    func setData() {
        let url = URL(string: self.groupData?.avatar ?? "")
        let indicator = SDWebImageActivityIndicator.medium
        self.userProfileImageView.sd_imageIndicator = indicator
        DispatchQueue.global(qos: .userInteractive).async {
            self.userProfileImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "ic_No_images"))
        }
        self.userNameLabel.text = self.groupData?.group_name ?? ""
        self.userActiveStatusLabel.text = "\(self.groupData?.getParts().count ?? 0) people join this"
    }
    
    // Fetch Group Messages Data
    func fetchData() {
        let appDelegate = (UIApplication.shared.delegate) as? AppDelegate
        let context = appDelegate?.persistentContainer.viewContext
        let localMessages = Messages.getMessagesByGroupID(self.groupData?.group_id ?? "", limit: self.limit)
        if !localMessages.isEmpty {
            self.messagesArray = localMessages // .reversed()
            self.chatTableView.reloadData()
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                self.chatTableView.scrollToLastRow(animated: false)
                self.view.layoutIfNeeded()
                self.chatTableView.layoutIfNeeded()
            }
        }
        self.fetchGroupChatMessageData { [weak self] (list) in
            guard let self = self else { return }
            for message in list {
                if let msg = Messages.getMessageByID(message.id ?? "") {
                    msg.updateMessage(message: message)
                } else {
                    let _ = Messages.init(chat_id: self.groupData?.chat_id ?? "", message: message)
                }
            }
            for message in Messages.getMessagesByGroupID(self.groupData?.group_id ?? "", limit: self.limit) {
                if !list.contains(where: { messageModel in
                    messageModel.id == message.message_id
                }) {
                    context?.delete(message)
                    do {
                        try context?.save()
                    } catch {
                        print("failed so save data after deleting object")
                    }
                }
            }
            let array = Messages.getMessagesByChatID(self.groupData?.group_id ?? "", limit: self.limit)
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                self.messagesArray = array //.reversed()
                self.chatTableView.reloadData()
                if self.messagesArray.count != 0 {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                        self.chatTableView.scrollToLastRow(animated: false)
                        self.view.layoutIfNeeded()
                        self.chatTableView.layoutIfNeeded()
                    }
                }
            }
        }
    }
    
    // SetUpReplyMessageView
    func setUpReplyMessageView(message: Messages) {
        if message.from_id == AppInstance.instance._userId {
            self.replyUserNameLabel.text = "You"
        } else {
            self.replyUserNameLabel.text = message.user_data?.name ?? ""
        }
        self.replyImageView.isHidden = false
        if message.type == "right_text" || message.type == "left_text" {
            if (Double(message.lat ?? "0.0") ?? 0.0) > 0.0 || Double(message.lng ?? "0.0") ?? 0.0 > 0.0 {
                self.replyImageView.image = UIImage(named: "chat_media_location")
                self.replyMessageLabel.text = "Location"
            } else {
                self.replyImageView.isHidden = true
                let text = self.decryptionAESModeECB(messageData: message._text.htmlAttributedString ?? "", key: message._time) ?? ""
                self.replyMessageLabel.text = text
            }
        } else if message.type == "right_image" || message.type == "left_image" {
            let imageUrl = URL(string: message.media ?? "")
            let indicator = SDWebImageActivityIndicator.medium
            self.replyImageView.sd_imageIndicator = indicator
            DispatchQueue.global(qos: .userInteractive).async {
                self.replyImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
            }
            self.replyMessageLabel.text = "Image"
        } else if message.type == "right_video" || message.type == "left_video" {
            if let videoURL = URL(string: message.media ?? "") {
                self.replyImageView.image = UIImage(named: "")
                self.generateThumbnail(from: videoURL, completion: { image in
                    self.replyImageView.image = image
                })
            }
            self.replyMessageLabel.text = "Video"
        } else if message.type == "right_file" || message.type == "left_file" {
            self.replyImageView.image = UIImage(named: "chat_media_file")
            self.replyMessageLabel.text = "File"
        } else if message.type == "right_audio" || message.type == "left_audio" {
            self.replyImageView.image = UIImage(named: "chat_media_music")
            self.replyMessageLabel.text = "Audio"
        } else if message.type == "right_contact" || message.type == "left_contact" {
            self.replyImageView.image = UIImage(named: "chat_media_contact")
            self.replyMessageLabel.text = "Contact"
        } else if message.type == "right_sticker" || message.type == "left_sticker" {
            let stickerUrl = URL(string: message.media ?? "")
            let indicator = SDWebImageActivityIndicator.medium
            self.replyImageView.sd_imageIndicator = indicator
            DispatchQueue.global(qos: .userInteractive).async {
                self.replyImageView.sd_setImage(with: stickerUrl, placeholderImage: UIImage(named: ""))
            }
            self.replyMessageLabel.text = "Sticker"
        } else if message.type == "right_gif" || message.type == "left_gif" {
            let gifUrl = URL(string: message.stickers ?? "")
            let indicator = SDWebImageActivityIndicator.medium
            self.replyImageView.sd_imageIndicator = indicator
            DispatchQueue.global(qos: .userInteractive).async {
                self.replyImageView.sd_setImage(with: gifUrl)
            }
            self.replyMessageLabel.text = "Gif"
        }
        self.isReplyStatus = true
        self.replyMessageID = message._message_id
        self.showReplyMessageView()
    }
    
    // Swipe To Reply
    private func showReplyMessageView() {
        self.replyMessageView.isHidden = false
        self.replyMessageViewHeight.constant = 84
        UIView.animate(withDuration: 0.5) {
            self.view.layoutIfNeeded()
        }
    }
    
    private func hideReplyMessageView() {
        self.replyMessageID = ""
        self.isReplyStatus = false
        self.replyMessageViewHeight.constant = 0
        UIView.animate(withDuration: 0.5, animations: {
            self.view.layoutIfNeeded()
        }) { _ in
            self.replyMessageView.isHidden = true
        }
    }
    
    // Set Send Button
    func setSendButton() {
        if self.messageTextView.text == "" {
            self.sendButton.isHidden = true
            self.stickerButton.isHidden = false
            self.audioRecordButton.isHidden = false
        } else {
            self.sendButton.isHidden = false
            self.stickerButton.isHidden = true
            self.audioRecordButton.isHidden = true
        }
    }
    
    @objc func handleTap(_ gesture: UITapGestureRecognizer) {
        self.view.endEditing(true)
    }
    
    // TableView longPressed Click
    @objc func longPressed(sender: UILongPressGestureRecognizer) {
        let objSender = sender.location(in: self.chatTableView)
        let indexPath = self.chatTableView.indexPathForRow(at: objSender)
        if indexPath != nil {
            let objCopyMessageArray = self.messagesArray[indexPath?.row ?? 0]
            if let newVC = R.storyboard.group.groupMessageOptionVC() {
                newVC.modalPresentationStyle = .custom
                newVC.transitioningDelegate = self
                newVC.delegate = self
                newVC.indexPath = indexPath ?? IndexPath()
                if objCopyMessageArray.type == "right_text" || objCopyMessageArray.type == "left_text" {
                    if (Double(objCopyMessageArray.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objCopyMessageArray.lng ?? "0.0") ?? 0.0 > 0.0 {
                        newVC.isCopy = false
                    } else {
                        newVC.isCopy = true
                    }
                } else {
                    newVC.isCopy = false
                }
                newVC.message = objCopyMessageArray
                self.present(newVC, animated: true)
            }
        }
    }
    
    // Play Receive Message Sound
    func playReceiveMessageSound() {
        guard let url = Bundle.main.url(forResource: "Popup_GetMesseges", withExtension: "mp3") else { return }
        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
            try AVAudioSession.sharedInstance().setActive(true)
            receiveMessageAudioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
            receiveMessageAudioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
            guard let aPlayer = receiveMessageAudioPlayer else { return }
            aPlayer.play()
        } catch let error {
            print(error.localizedDescription)
        }
    }
    
    func playSendMessageSound() {
        var sendMessageAudioPlayer: AVAudioPlayer?
        guard let url = Bundle.main.url(forResource: "Popup_SendMesseges", withExtension: "mp3") else { return }
        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
            try AVAudioSession.sharedInstance().setActive(true)
            sendMessageAudioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
            sendMessageAudioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
            guard let aPlayer = sendMessageAudioPlayer else { return }
            aPlayer.play()
        } catch let error {
            print(error.localizedDescription)
        }
    }
    
}

// MARK: - Extensions

// MARK: Api Call
extension ChatGroupViewController {
    
    // Get Group Chat Data List
    func getGroupChatDataList() {
        if Connectivity.isConnectedToNetwork() {
            let sessionToken = AppInstance.instance.sessionId ?? ""
            Async.background {
                GroupChatManager.instance.fetchGroups(session_Token: sessionToken, type: "get_list", limit: 10, completionBlock: { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                print("userList = \(success?.data ?? [])")
                                for group in success?.data ?? [] {
                                    if group.group_id == self.groupData?.group_id {
                                        self.groupApiData = group
                                        break
                                    }
                                }
                                if let groupData = self.groupApiData {
                                    self.groupData?.updateGroupChat(groupData)
                                    self.setData()
                                }
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                print("serverError = \(serverError?.errors?.error_text ?? "")")
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                print("error = \(error?.localizedDescription ?? "")")
                            }
                        }
                    }
                })
            }
        } else {
            self.dismissProgressDialog {
                self.view.makeToast(InterNetError)
            }
        }
    }
    
    // Fetch GroupChat Data
    private func fetchGroupChatMessageData(_ completion: @escaping ([MessageModel]) -> Void) {
        if Connectivity.isConnectedToNetwork() {
            let sessionID = AppInstance.instance.sessionId ?? ""
            let groupId = self.groupData?.group_id ?? ""
            print("group id = \(groupId)")
            Async.background {
                GroupChatManager.instance.getGroupChats(group_Id: groupId, session_Token: sessionID, completionBlock: { (success, sessionError, serverError, error) in
                    if success != nil{
                        Async.main {
                            self.dismissProgressDialog {
                                completion(success?.data?.messages ?? [])
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                // self.view.makeToast(sessionError?.errors?.error_text ?? "")
                                print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(serverError?.errors?.error_text ?? "")
                                print("serverError = \(serverError?.errors?.error_text ?? "")")
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(error?.localizedDescription)
                                print("error = \(error?.localizedDescription ?? "")")
                            }
                        }
                    }
                })
            }
        } else {
            self.dismissProgressDialog {
                self.view.makeToast(InterNetError)
            }
        }
    }
    
    // Send Message
    private func sendMessage(text: String, lat: Double, lng: Double) {
        self.messagesArray.removeAll()
        let messageHashId = Int(arc4random_uniform(UInt32(100000)))
        let replyID = self.replyMessageID
        let groupId = self.groupData?.group_id ?? ""
        let sessionID = AppInstance.instance.sessionId ?? ""
        Async.background {
            GroupChatManager.instance.sendMessageToGroup(message_hash_id: messageHashId, GroupId: groupId, text: text, session_Token: sessionID, lat: lat, lag: lng, reply_id: replyID) { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.resignFirstResponder()
                            if self.toneStatus {
                                self.playSendMessageSound()
                            } else {
                                print("To play sound please enable conversation tone from settings..")
                            }
                            self.messageTextView.text = ""
                            self.setSendButton()
                            if self.isReplyStatus {
                                self.hideReplyMessageView()
                            }
                            self.fetchData()
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text ?? "")
                            print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text ?? "")
                            print("serverError = \(serverError?.errors?.error_text ?? "")")
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                            print("error = \(error?.localizedDescription ?? "")")
                        }
                    }
                }
            }
        }
    }
    
    // Send Selected Data
    private func sendSelectedData(type: String, imageData: Data?, imageMimeType: String?, videoData: Data?, videoMimeType: String?, fileData: Data?, fileExtension: String?, fileMimeType: String?, audio: Data?, audioExtension: String?, audioMimeType: String?) {
        let messageHashId = Int(arc4random_uniform(UInt32(100000)))
        let replyID = self.replyMessageID
        let sessionId = AppInstance.instance.sessionId ?? ""
        let groupId = self.groupData?.group_id ?? ""
        if type == "image" {
            Async.background {
                GroupChatManager.instance.sendGroupChatData(message_hash_id: messageHashId, groupId: groupId, session_Token: sessionId, type: type, image_data: imageData, imageMimeType: imageMimeType, video_data: nil, videoMimeType: nil, file_data: nil, file_Extension: nil, fileMimeType: nil, audio_data: nil, audio_Extension: "", audioMimeType: nil, reply_id: replyID, completionBlock: { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                print("userList = \(success?.apiStatus ?? 0)")
                                self.view.resignFirstResponder()
                                if self.isReplyStatus {
                                    self.hideReplyMessageView()
                                }
                                self.fetchData()
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(sessionError?.errors?.error_text ?? "")
                                print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(serverError?.errors?.error_text)
                                print("serverError = \(serverError?.errors?.error_text ?? "")")
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(error?.localizedDescription)
                                print("error = \(error?.localizedDescription ?? "")")
                            }
                        }
                    }
                })
            }
        }
        if type == "audio" {
            Async.background {
                GroupChatManager.instance.sendGroupChatData(message_hash_id: messageHashId, groupId: groupId, session_Token: sessionId, type: type, image_data: nil, imageMimeType: nil, video_data: nil, videoMimeType: nil, file_data: nil, file_Extension: nil, fileMimeType: nil, audio_data: audio, audio_Extension: "mp3", audioMimeType: audioMimeType, reply_id: replyID, completionBlock: { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                print("userList = \(success?.apiStatus ?? 0)")
                                self.view.resignFirstResponder()
                                if self.isReplyStatus {
                                    self.hideReplyMessageView()
                                }
                                self.fetchData()
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(sessionError?.errors?.error_text ?? "")
                                print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(serverError?.errors?.error_text ?? "")
                                print("serverError = \(serverError?.errors?.error_text ?? "")")
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(error?.localizedDescription)
                                print("error = \(error?.localizedDescription ?? "")")
                            }
                        }
                    }
                })
            }
        }
        if type == "video" {
            Async.background {
                GroupChatManager.instance.sendGroupChatData(message_hash_id: messageHashId, groupId: groupId, session_Token: sessionId, type: type, image_data: nil, imageMimeType: nil, video_data: videoData, videoMimeType: videoMimeType, file_data: nil, file_Extension: nil, fileMimeType: nil, audio_data: nil, audio_Extension: "", audioMimeType: nil, reply_id: replyID, completionBlock: { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                print("userList = \(success?.apiStatus ?? 0)")
                                self.view.resignFirstResponder()
                                if self.isReplyStatus {
                                    self.hideReplyMessageView()
                                }
                                self.fetchData()
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(sessionError?.errors?.error_text ?? "")
                                print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(serverError?.errors?.error_text)
                                print("serverError = \(serverError?.errors?.error_text ?? "")")
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(error?.localizedDescription)
                                print("error = \(error?.localizedDescription ?? "")")
                            }
                        }
                    }
                })
            }
        }
        if type == "file" {
            Async.background {
                GroupChatManager.instance.sendGroupChatData(message_hash_id: messageHashId, groupId: groupId, session_Token: sessionId, type: type, image_data: nil, imageMimeType: nil, video_data: nil, videoMimeType: nil, file_data: fileData, file_Extension: fileExtension, fileMimeType: fileMimeType, audio_data: nil, audio_Extension: nil, audioMimeType: nil, reply_id: replyID, completionBlock: { (success, sessionError, serverError, error) in
                    if success != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                print("userList = \(success?.apiStatus ?? 0)")
                                self.view.resignFirstResponder()
                                if self.isReplyStatus {
                                    self.hideReplyMessageView()
                                }
                                self.fetchData()
                            }
                        }
                    } else if sessionError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(sessionError?.errors?.error_text ?? "")
                                print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                            }
                        }
                    } else if serverError != nil {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(serverError?.errors?.error_text)
                                print("serverError = \(serverError?.errors?.error_text ?? "")")
                            }
                        }
                    } else {
                        Async.main {
                            self.dismissProgressDialog {
                                self.view.makeToast(error?.localizedDescription ?? "")
                                print("error = \(error?.localizedDescription ?? "")")
                            }
                        }
                    }
                })
            }
        }
    }
    
    private func sendContact(jsonPayload: String?) {
        let messageHashId = Int(arc4random_uniform(UInt32(100000)))
        let replyID = self.replyMessageID
        let jsonPayloadString = jsonPayload ??  ""
        let groupId = self.groupData?.group_id ?? ""
        let sessionID = AppInstance.instance.sessionId ?? ""
        Async.background {
            GroupChatManager.instance.sendContactToGroup(message_hash_id: messageHashId, groupId: groupId, jsonPayload: jsonPayloadString, session_Token: sessionID, reply_id: replyID, completionBlock: { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.resignFirstResponder()
                            if self.isReplyStatus {
                                self.hideReplyMessageView()
                            }
                            self.fetchData()
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text ?? "")
                            print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                            print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                            print("error = \(error?.localizedDescription ?? "")")
                        }
                    }
                }
            })
        }
    }
    
    private func sendGIF(url: String) {
        let messageHashId = Int(arc4random_uniform(UInt32(100000)))
        let replyID = self.replyMessageID
        let sessionID = AppInstance.instance.sessionId ?? ""
        let groupId = self.groupData?.group_id ?? ""
        GroupChatManager.instance.sendGIF(message_hash_id: messageHashId, groupId: groupId, url: url, session_Token: sessionID, reply_id: replyID) { (success, sessionError, serverError, error) in
            if success != nil {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.resignFirstResponder()
                        if self.isReplyStatus {
                            self.hideReplyMessageView()
                        }
                        self.fetchData()
                    }
                }
            } else if sessionError != nil {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.makeToast(sessionError?.errors?.error_text)
                    }
                }
            } else if serverError != nil {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.makeToast(serverError?.errors?.error_text)
                    }
                }
            } else {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.makeToast(error?.localizedDescription)
                    }
                }
            }
        }
    }
    
    // Send Sticker
    private func sendSticker(url: String, sticker_id: String) {
        let messageHashId = Int(arc4random_uniform(UInt32(100000)))
        let replyID = self.replyMessageID
        let sessionID = AppInstance.instance.sessionId ?? ""
        let groupId = self.groupData?.group_id ?? ""
        GroupChatManager.instance.sendSticker(message_hash_id: messageHashId, groupId: groupId, url: url, sticker_id: sticker_id, session_Token: sessionID, reply_id: replyID) { (success, sessionError, serverError, error) in
            if success != nil {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.resignFirstResponder()
                        if self.isReplyStatus {
                            self.hideReplyMessageView()
                        }
                        self.fetchData()
                    }
                }
            } else if sessionError != nil {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.makeToast(sessionError?.errors?.error_text)
                    }
                }
            } else if serverError != nil {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.makeToast(serverError?.errors?.error_text)
                    }
                }
            } else {
                Async.main {
                    self.dismissProgressDialog {
                        self.view.makeToast(error?.localizedDescription)
                    }
                }
            }
        }
    }
    
    // Delete Message Api
    private func deleteMessage(messageID: String, indexPath: Int) {
        let sessionID = AppInstance.instance._sessionId
        Async.background {
            ChatManager.instance.deleteChatMessage(messageId: messageID , session_Token: sessionID, completionBlock: { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            print("userList = \(success?.message ?? "")")
                            let appDelegate = (UIApplication.shared.delegate) as? AppDelegate
                            let context = appDelegate?.persistentContainer.viewContext
                            context?.delete(self.messagesArray[indexPath])
                            do {
                                try context?.save()
                            } catch {
                                print("failed so save data after deleting object")
                            }
                            self.messagesArray.remove(at: indexPath)
                            self.chatTableView.reloadData()
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(sessionError?.errors?.error_text)
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(serverError?.errors?.error_text)
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            self.view.makeToast(error?.localizedDescription)
                        }
                    }
                }
            })
        }
    }
    
    private func exitGroup() {
        let sessionToken = AppInstance.instance.sessionId ?? ""
        let groupId = self.groupData?.group_id ?? ""
        Async.background {
            GroupChatManager.instance.leaveGroup(group_Id: groupId, session_Token: sessionToken, type: "leave", completionBlock: { (success, sessionError, serverError, error) in
                if success != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            print("success = \(success?.api_status ?? 0)")
                            self.navigationController?.popViewController(animated: true)
                            appDelegate.window?.rootViewController?.view.makeToast(success?.message_data)
                        }
                    }
                } else if sessionError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            print("sessionError = \(sessionError?.errors?.error_text ?? "")")
                            self.view.makeToast(sessionError?.errors?.error_text ?? "")
                        }
                    }
                } else if serverError != nil {
                    Async.main {
                        self.dismissProgressDialog {
                            print("serverError = \(serverError?.errors?.error_text ?? "")")
                            self.view.makeToast(serverError?.errors?.error_text ?? "")
                        }
                    }
                } else {
                    Async.main {
                        self.dismissProgressDialog {
                            print("error = \(error?.localizedDescription ?? "")")
                            self.view.makeToast(error?.localizedDescription ?? "")
                        }
                    }
                }
            })
        }
    }
    
}

// MARK: TableView Setup
extension ChatGroupViewController: UITableViewDelegate, UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.messagesArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let objChatList = self.messagesArray[indexPath.row]
        guard let type = objChatList.type else {
            return UITableViewCell()
        }
        switch type {
        case "left_text":
            if objChatList.stickers == nil || objChatList.stickers == "" {
                let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftTextTableViewCell.identifier, for: indexPath) as! LeftTextTableViewCell
                self.setLeftTextData(cell: cell, indexPathForCell: indexPath)
                return cell
            } else {
                let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftGifTableViewCell.identifier, for: indexPath) as! LeftGifTableViewCell
                self.setLeftGifData(cell: cell, indexPathForCell: indexPath)
                return cell
            }
        case "right_text":
            if objChatList.stickers == nil || objChatList.stickers == "" {
                let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightTextTableViewCell.identifier, for: indexPath) as! RightTextTableViewCell
                self.setRightTextData(cell: cell, indexPathForCell: indexPath)
                return cell
            } else {
                let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightGifTableViewCell.identifier, for: indexPath) as! RightGifTableViewCell
                self.setRightGifData(cell: cell, indexPathForCell: indexPath)
                return cell
            }
        case "left_map":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftLocationTableViewCell.identifier, for: indexPath) as! LeftLocationTableViewCell
            let lat = Double(objChatList.lat ?? "0.0") ?? 0.0
            let long = Double(objChatList.lng ?? "0.0") ?? 0.0
            self.setLeftLocationData(lat: lat, long: long, cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_map":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightLocationTableViewCell.identifier, for: indexPath) as! RightLocationTableViewCell
            let lat = Double(objChatList.lat ?? "0.0") ?? 0.0
            let long = Double(objChatList.lng ?? "0.0") ?? 0.0
            self.setRightLocationData(lat: lat, long: long, cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_image":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightImageTableViewCell.identifier, for: indexPath) as! RightImageTableViewCell
            self.setRightImageData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_image":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftImageTableViewCell.identifier, for: indexPath) as! LeftImageTableViewCell
            self.setLeftImageData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_video":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftVideoTableViewCell.identifier, for: indexPath) as! LeftVideoTableViewCell
            self.setLeftVideoData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_video":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightVideoTableViewCell.identifier, for: indexPath) as! RightVideoTableViewCell
            self.setRightVideoData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_gif":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightGifTableViewCell.identifier, for: indexPath) as! RightGifTableViewCell
            self.setRightGifData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_gif":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftGifTableViewCell.identifier, for: indexPath) as! LeftGifTableViewCell
            self.setLeftGifData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_contact":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftContactTableViewCell.identifier, for: indexPath) as! LeftContactTableViewCell
            self.setLeftContactData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_contact":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightContactTableViewCell.identifier, for: indexPath) as! RightContactTableViewCell
            self.setRightContactData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_file":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftDocumentTableViewCell.identifier, for: indexPath) as! LeftDocumentTableViewCell
            self.setLeftDocumentData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_file":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightDocumentTableViewCell.identifier, for: indexPath) as! RightDocumentTableViewCell
            self.setRightDocumentData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_audio":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftAudioTableViewCell.identifier, for: indexPath) as! LeftAudioTableViewCell
            self.setLeftAudioData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_audio":
            let cell = chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightAudioTableViewCell.identifier, for: indexPath) as! RightAudioTableViewCell
            self.setRightAudioData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "left_sticker":
            let cell = self.chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.leftStickerCell.identifier, for: indexPath) as! LeftStickerCell
            self.setLeftStickerData(cell: cell, indexPathForCell: indexPath)
            return cell
        case "right_sticker":
            let cell = self.chatTableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.rightStickerCell.identifier, for: indexPath) as! RightStickerCell
            self.setRightStickerData(cell: cell, indexPathForCell: indexPath)
            return cell
        default:
            return UITableViewCell()
        }
    }
    
    // Set Left Text Data
    private func setLeftTextData(cell: LeftTextTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedLabel.text = objChatList.forward == "0" ? "" : "Forwarded"
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
            cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
        } else {
            cell.replyMessageView.isHidden = true
            cell.replyUserLabel.text = ""
            cell.replyMessageLabel.text = ""
        }
        cell.hideAnimation()
        let messageString = self.decryptionAESModeECB(messageData: objChatList._text, key: objChatList._time) ?? ""
        cell.masageTextLabel.text = messageString
        cell.setUPLinkView(messageString: messageString, tableView: self.chatTableView)
        let userAvatarUrl = URL(string: objChatList.user_data?.avatar_url ?? "")
        DispatchQueue.global(qos: .userInteractive).async {
            cell.userImageView.sd_setImage(with: userAvatarUrl, placeholderImage: UIImage(named: ""))
        }
        cell.userNameLabel.text = objChatList.user_data?.name ?? ""
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Text Data
    private func setRightTextData(cell: RightTextTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedLabel.text = objChatList.forward == "0" ? "" : "Forwarded"
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
                
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
            cell.replyUserLabel.text = ""
            cell.replyMessageLabel.text = ""
        }
        cell.hideAnimation()
        let messageString = "\(self.decryptionAESModeECB(messageData: objChatList._text, key: objChatList._time) ?? "")"
        cell.messaageTextLabel.text = "\(messageString)"
        cell.setUPLinkView(messageString: messageString, tableView: self.chatTableView)
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageVIew.isHidden = false
        } else {
            cell.starImageVIew.isHidden = true
        }
        cell.messageView.backgroundColor = UIColor(hex: "#C83747")
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        }
    }
    
    // Set Left Location Data
    private func setLeftLocationData(lat: Double, long: Double, cell: LeftLocationTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
            cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
        } else {
            cell.replyMessageView.isHidden = true
        }
        let userAvatarUrl = URL(string: objChatList.user_data?.avatar_url ?? "")
        DispatchQueue.global(qos: .userInteractive).async {
            cell.userImageView.sd_setImage(with: userAvatarUrl, placeholderImage: UIImage(named: ""))
        }
        cell.userNameLabel.text = objChatList.user_data?.name ?? ""
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.configureMapView(lat: lat, long: long)
        cell.mapButton.tag = indexPathForCell.row
        cell.mapButton.addTarget(self, action: #selector(self.setLocationNavigaction), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Location Data
    private func setRightLocationData(lat: Double, long: Double, cell: RightLocationTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.configureMapView(lat: lat, long: long)
        cell.mapButton.tag = indexPathForCell.row
        cell.mapButton.addTarget(self, action: #selector(self.setLocationNavigaction), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        cell.messageView.backgroundColor = UIColor(hex: "#C83747")
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        }
    }
    
    // Set Left Image Data
    private func setLeftImageData(cell: LeftImageTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
            cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
        } else {
            cell.replyMessageView.isHidden = true
        }
        let imageUrl = URL(string: objChatList.media ?? "")
        cell.imageUrl = imageUrl
        if AppInstance.instance.isDownloadImage == false {
            if let imageURL = imageUrl, let localURL = MediaDownloader.shared.getCachedLocalURL(for: imageURL),
               FileManager.default.fileExists(atPath: localURL.path) {
                cell.loadImage(from: localURL)
                cell.blurView.isHidden = true // Hide download button
            } else {
                let indicator = SDWebImageActivityIndicator.medium
                cell.sendImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.sendImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
            }
        } else {
            cell.blurView.isHidden = true
            let indicator = SDWebImageActivityIndicator.medium
            cell.sendImageView.sd_imageIndicator = indicator
            DispatchQueue.global(qos: .userInteractive).async {
                cell.sendImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
            }
        }
        let userAvatarUrl = URL(string: objChatList.user_data?.avatar_url ?? "")
        DispatchQueue.global(qos: .userInteractive).async {
            cell.userImageView.sd_setImage(with: userAvatarUrl, placeholderImage: UIImage(named: ""))
        }
        cell.userNameLabel.text = objChatList.user_data?.name ?? ""
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.messageImageButton.tag = indexPathForCell.row
        cell.messageImageButton.addTarget(self, action: #selector(self.clickImageClick), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Image Data
    private func setRightImageData(cell: RightImageTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let imageUrl = URL(string: objChatList.media ?? "")
        cell.imageUrl = imageUrl
        if AppInstance.instance.isDownloadImage == false {
            if let imageURL = imageUrl, let localURL = MediaDownloader.shared.getCachedLocalURL(for: imageURL),
               FileManager.default.fileExists(atPath: localURL.path) {
                cell.loadImage(from: localURL)
                cell.blurView.isHidden = true // Hide download button
            } else {
                let indicator = SDWebImageActivityIndicator.medium
                cell.sendImageView.sd_imageIndicator = indicator
                DispatchQueue.global(qos: .userInteractive).async {
                    cell.sendImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
                }
            }
        } else {
            cell.blurView.isHidden = true
            let indicator = SDWebImageActivityIndicator.medium
            cell.sendImageView.sd_imageIndicator = indicator
            DispatchQueue.global(qos: .userInteractive).async {
                cell.sendImageView.sd_setImage(with: imageUrl, placeholderImage: UIImage(named: ""))
            }
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.messageImageButton.tag = indexPathForCell.row
        cell.messageImageButton.addTarget(self, action: #selector(self.clickImageClick), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        cell.messageView.backgroundColor = UIColor(hex: "C83747")
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        }
    }
    
    // Set Left Video Data
    private func setLeftVideoData(cell: LeftVideoTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
            cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
        } else {
            cell.replyMessageView.isHidden = true
        }
        let userAvatarUrl = URL(string: objChatList.user_data?.avatar_url ?? "")
        DispatchQueue.global(qos: .userInteractive).async {
            cell.userImageView.sd_setImage(with: userAvatarUrl, placeholderImage: UIImage(named: ""))
        }
        cell.userNameLabel.text = objChatList.user_data?.name ?? ""
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        let videoUrl = URL(string: objChatList.media ?? "")
        cell.videoUrl = videoUrl
        cell.videoImageView.image = UIImage(named: "")
        if AppInstance.instance.isDownloadVideo == false {
            if let videoUrl = videoUrl, let localURL = MediaDownloader.shared.getCachedLocalURL(for: videoUrl),
               FileManager.default.fileExists(atPath: localURL.path) {
                DispatchQueue.global(qos: .userInteractive).async {
                    AppInstance.instance.generateThumbnail(from: localURL, completion: { image in
                        DispatchQueue.main.async {
                            if let image = image {
                                cell.videoImageView.image = image
                            } else {
                                cell.videoImageView.image = UIImage(named: "")
                            }
                        }
                    })
                }
                cell.blurView.isHidden = true // Hide download button
            } else {
                DispatchQueue.global(qos: .userInteractive).async {
                    AppInstance.instance.generateThumbnail(from: videoUrl, completion: { image in
                        DispatchQueue.main.async {
                            if let image = image {
                                cell.videoImageView.image = image
                            } else {
                                cell.videoImageView.image = UIImage(named: "")
                            }
                        }
                    })
                }
            }
        } else {
            cell.blurView.isHidden = true
            DispatchQueue.global(qos: .userInteractive).async {
                AppInstance.instance.generateThumbnail(from: videoUrl, completion: { image in
                    DispatchQueue.main.async {
                        if let image = image {
                            cell.videoImageView.image = image
                        } else {
                            cell.videoImageView.image = UIImage(named: "")
                        }
                    }
                })
            }
        }
        cell.messageVideoButton.tag = indexPathForCell.row
        cell.messageVideoButton.addTarget(self, action: #selector(self.clickVideoButton), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Video Data
    private func setRightVideoData(cell: RightVideoTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                if (Double(objChatList.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let videoUrl = URL(string: objChatList.media ?? "")
        cell.videoUrl = videoUrl
        cell.videoImageView.image = UIImage(named: "")
        if AppInstance.instance.isDownloadVideo == false {
            if let videoUrl = videoUrl, let localURL = MediaDownloader.shared.getCachedLocalURL(for: videoUrl),
               FileManager.default.fileExists(atPath: localURL.path) {
                DispatchQueue.global(qos: .userInteractive).async {
                    AppInstance.instance.generateThumbnail(from: localURL, completion: { image in
                        DispatchQueue.main.async {
                            if let image = image {
                                cell.videoImageView.image = image
                            } else {
                                cell.videoImageView.image = UIImage(named: "")
                            }
                        }
                    })
                }
                cell.blurView.isHidden = true // Hide download button
            } else {
                DispatchQueue.global(qos: .userInteractive).async {
                    AppInstance.instance.generateThumbnail(from: videoUrl, completion: { image in
                        DispatchQueue.main.async {
                            if let image = image {
                                cell.videoImageView.image = image
                            } else {
                                cell.videoImageView.image = UIImage(named: "")
                            }
                        }
                    })
                }
            }
        } else {
            cell.blurView.isHidden = true
            DispatchQueue.global(qos: .userInteractive).async {
                AppInstance.instance.generateThumbnail(from: videoUrl, completion: { image in
                    DispatchQueue.main.async {
                        if let image = image {
                            cell.videoImageView.image = image
                        } else {
                            cell.videoImageView.image = UIImage(named: "")
                        }
                    }
                })
            }
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.messageVideoButton.tag = indexPathForCell.row
        cell.messageVideoButton.addTarget(self, action: #selector(self.clickVideoButton), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        cell.messageView.backgroundColor = UIColor(hex: "C83747")
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        }
    }
    
    // Set Left Gif Data
    private func setLeftGifData(cell: LeftGifTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                if (Double(objChatList.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
            cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
        } else {
            cell.replyMessageView.isHidden = true
        }
        let userAvatarUrl = URL(string: objChatList.user_data?.avatar_url ?? "")
        DispatchQueue.global(qos: .userInteractive).async {
            cell.userImageView.sd_setImage(with: userAvatarUrl, placeholderImage: UIImage(named: ""))
        }
        cell.userNameLabel.text = objChatList.user_data?.name ?? ""
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        let gifUrl = URL(string: objChatList.stickers ?? "")
        let indicator = SDWebImageActivityIndicator.medium
        cell.videoImageView.sd_imageIndicator = indicator
        DispatchQueue.global(qos: .userInteractive).async {
            cell.videoImageView.sd_setImage(with: gifUrl, placeholderImage: UIImage(named: ""))
        }
        cell.messageGifButton.tag = indexPathForCell.row
        cell.messageGifButton.addTarget(self, action: #selector(self.clickGif), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Gif Data
    private func setRightGifData(cell: RightGifTableViewCell, indexPathForCell:IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                if (Double(objChatList.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        let gifUrl = URL(string: objChatList.stickers ?? "")
        let indicator = SDWebImageActivityIndicator.medium
        cell.videoImageView.sd_imageIndicator = indicator
        DispatchQueue.global(qos: .userInteractive).async {
            cell.videoImageView.sd_setImage(with: gifUrl, placeholderImage: UIImage(named: ""))
        }
        cell.messageGifButton.tag = indexPathForCell.row
        cell.messageGifButton.addTarget(self, action: #selector(self.clickGif), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        cell.messageView.backgroundColor = UIColor(hex: "C83747")
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        }
    }
    
    // Set Left Contact Data
    private func setLeftContactData(cell: LeftContactTableViewCell,  indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = self.messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                if (Double(objChatList.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
            cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
        } else {
            cell.replyMessageView.isHidden = true
        }
        let phoneData = self.decryptionAESModeECB(messageData: objChatList._text, key: objChatList._time) ?? ""
        let dict = htmlToString(text: phoneData)
        let contactName = ((dict?["Key"] as? String) ?? "")
        let phoneNumber = ((dict?["Value"] as? String) ?? "")
        if contactName != "" {
            cell.contactNameLabel.text = "\(contactName)"
        } else if phoneNumber != "" {
            cell.contactNameLabel.text = "\(phoneNumber)"
        }
        let userAvatarUrl = URL(string: objChatList.user_data?.avatar_url ?? "")
        DispatchQueue.global(qos: .userInteractive).async {
            cell.userImageView.sd_setImage(with: userAvatarUrl, placeholderImage: UIImage(named: ""))
        }
        cell.userNameLabel.text = objChatList.user_data?.name ?? ""
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.contactButton.tag = indexPathForCell.row
        cell.contactButton.addTarget(self, action: #selector(self.openContact), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        cell.contactImageView.tintColor = UIColor(hex: "C83747")
    }
    
    // Set Right Contact Data
    private func setRightContactData(cell: RightContactTableViewCell,  indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = self.messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                if (Double(objChatList.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let phoneData = self.decryptionAESModeECB(messageData: objChatList._text, key: objChatList._time) ?? ""
        let dict = htmlToString(text: phoneData)
        let contactName = ((dict?["Key"] as? String) ?? "")
        let phoneNumber = ((dict?["Value"] as? String) ?? "")
        if contactName != "" {
            cell.contactNameLabel.text = "\(contactName)"
        } else if phoneNumber != "" {
            cell.contactNameLabel.text = "\(phoneNumber)"
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.contactButton.tag = indexPathForCell.row
        cell.contactButton.addTarget(self, action: #selector(self.openContact), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        cell.messageView.backgroundColor = UIColor(hex: "C83747")
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        }
    }
    
    // Set Left Document Data
    private func setLeftDocumentData(cell: LeftDocumentTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
            cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
        } else {
            cell.replyMessageView.isHidden = true
        }
        let fileURL = URL(string: objChatList.media ?? "")
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.fileNameLabel.text = fileURL?.lastPathComponent ?? ""
        cell.fileSizeLabel.text = objChatList.file_size
        cell.fileMessageButton.tag = indexPathForCell.row
        cell.fileMessageButton.addTarget(self, action: #selector(self.clickFile), for: .touchUpInside)
        let userAvatarUrl = URL(string: objChatList.user_data?.avatar_url ?? "")
        DispatchQueue.global(qos: .userInteractive).async {
            cell.userImageView.sd_setImage(with: userAvatarUrl, placeholderImage: UIImage(named: ""))
        }
        cell.userNameLabel.text = objChatList.user_data?.name ?? ""
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        cell.fileButton.backgroundColor = UIColor(hex: "C83747")
    }
    
    // Set Right Document Document
    private func setRightDocumentData(cell: RightDocumentTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let fileURL = URL(string: objChatList.media ?? "")
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        cell.fileNameLabel.text = fileURL?.lastPathComponent ?? ""
        cell.fileSizeLabel.text = objChatList.file_size
        cell.fileMessageButton.tag = indexPathForCell.row
        cell.fileMessageButton.addTarget(self, action: #selector(self.clickFile), for: .touchUpInside)
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        cell.messageView.backgroundColor = UIColor(hex: "C83747")
        cell.fileImageView.tintColor = UIColor(hex: "C83747")
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        }
    }
    
    // Set Left Audio Data
    private func setLeftAudioData(cell: LeftAudioTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
            cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
        } else {
            cell.replyMessageView.isHidden = true
        }
        if let audioURL = URL(string: objChatList.media ?? "") {
            cell.playButtonTapHandler = {
                AudioPlayerHelper.shared.playAudio(at: indexPathForCell, url: audioURL)
            }
            cell.setupAudioPlayer(url: audioURL, indexPath: indexPathForCell)
        }
        let userAvatarUrl = URL(string: objChatList.user_data?.avatar_url ?? "")
        DispatchQueue.global(qos: .userInteractive).async {
            cell.userImageView.sd_setImage(with: userAvatarUrl, placeholderImage: UIImage(named: ""))
        }
        cell.userNameLabel.text = objChatList.user_data?.name ?? ""
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        cell.playButton.backgroundColor = UIColor(hex: "C83747")
        cell.audioSliderView.minimumTrackTintColor = UIColor(hex: "C83747")
        cell.audioSliderView.maximumTrackTintColor = UIColor(hex: "C83747").withAlphaComponent(0.34)
    }
    
    // Set Right Audio Data
    private func setRightAudioData(cell: RightAudioTableViewCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        if let audioURL = URL(string: objChatList.media ?? "") {
            cell.playButtonTapHandler = {
                AudioPlayerHelper.shared.playAudio(at: indexPathForCell, url: audioURL)
            }
            cell.setupAudioPlayer(url: audioURL, indexPath: indexPathForCell)
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        cell.messageView.backgroundColor = UIColor(hex: "C83747")
        cell.playButton.tintColor = UIColor(hex: "C83747")
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        }
    }
    
    // Set Left Sticker Data
    private func setLeftStickerData(cell: LeftStickerCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
            cell.replyBorderView.backgroundColor = UIColor(hex: "#C83747")
            cell.replyUserLabel.textColor = UIColor(hex: "#C83747")
        } else {
            cell.replyMessageView.isHidden = true
        }
        let stickerUrl = URL(string: objChatList.media ?? "")
        let indicator = SDWebImageActivityIndicator.medium
        cell.sendImageView.sd_imageIndicator = indicator
        DispatchQueue.global(qos: .userInteractive).async {
            cell.sendImageView.sd_setImage(with: stickerUrl, placeholderImage: UIImage(named: ""))
        }
        let userAvatarUrl = URL(string: objChatList.user_data?.avatar_url ?? "")
        DispatchQueue.global(qos: .userInteractive).async {
            cell.userImageView.sd_setImage(with: userAvatarUrl, placeholderImage: UIImage(named: ""))
        }
        cell.userNameLabel.text = objChatList.user_data?.name ?? ""
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
    }
    
    // Set Right Sticker Data
    private func setRightStickerData(cell: RightStickerCell, indexPathForCell: IndexPath) {
        cell.indexPath = indexPathForCell
        cell.delegate = self
        let objChatList = messagesArray[indexPathForCell.row]
        cell.forwardedView.isHidden = objChatList.forward == "0"
        cell.replyStoryView.isHidden = true
        if objChatList.reply != nil {
            cell.replyMessageView.isHidden = false
            if objChatList.reply?.from_id == AppInstance.instance._userId {
                cell.replyUserLabel.text = "You"
            } else {
                cell.replyUserLabel.text = objChatList.reply?.user_data?.name ?? ""
            }
            if objChatList.reply?._type == "right_text" || objChatList.reply?._type == "left_text" {
                if (Double(objChatList.reply?.lat ?? "0.0") ?? 0.0) > 0.0 || Double(objChatList.reply?.lng ?? "0.0") ?? 0.0 > 0.0 {
                    cell.replyMessageLabel.text = "Location"
                } else {
                    cell.replyMessageLabel.text = self.decryptionAESModeECB(messageData: objChatList.reply?._text ?? "", key: objChatList.reply?._time ?? "") ?? ""
                }
            } else if objChatList.reply?._type == "right_image" || objChatList.reply?._type == "left_image" {
                cell.replyMessageLabel.text = "Image"
            } else if objChatList.reply?._type == "right_audio" || objChatList.reply?._type == "left_audio" {
                cell.replyMessageLabel.text = "Audio"
            } else if objChatList.reply?._type == "right_video" || objChatList.reply?._type == "left_video" {
                cell.replyMessageLabel.text = "Video"
            } else if objChatList.reply?._type == "right_file" || objChatList.reply?._type == "left_file" {
                cell.replyMessageLabel.text = "File"
            } else if objChatList.reply?._type == "right_contact" || objChatList.reply?._type == "left_contact" {
                cell.replyMessageLabel.text = "Contact"
            } else if objChatList.reply?._type == "right_sticker" || objChatList.reply?._type == "left_sticker" {
                cell.replyMessageLabel.text = "Sticker"
            } else if objChatList.reply?._type == "right_gif" || objChatList.reply?._type == "left_gif" {
                cell.replyMessageLabel.text = "Gif"
            }
        } else {
            cell.replyMessageView.isHidden = true
        }
        let stickerUrl = URL(string: objChatList.media ?? "")
        let indicator = SDWebImageActivityIndicator.medium
        cell.sendImageView.sd_imageIndicator = indicator
        DispatchQueue.global(qos: .userInteractive).async {
            cell.sendImageView.sd_setImage(with: stickerUrl, placeholderImage: UIImage(named: ""))
        }
        cell.messageTimeLabel.text = objChatList.time?.timeStampStringToTime()
        if objChatList._reaction == "" {
            cell.reactionImageView.isHidden = true
        } else {
            cell.reactionImageView.isHidden = false
            cell.reactionImageView.image = self.setReactionEmoji(type: objChatList._reaction)
        }
        if objChatList.fav == "yes" {
            cell.starImageView.isHidden = false
        } else {
            cell.starImageView.isHidden = true
        }
        if objChatList.seen == "0" {
            cell.lastSeenImage.image = UIImage(named: "ic_seenCheck")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        } else {
            cell.lastSeenImage.image = UIImage(named: "ic_seen")?.withRenderingMode(.alwaysTemplate)
            cell.lastSeenImage.tintColor = UIColor(hex: "C83747")
        }
    }
    
    // Click Video Button
    @objc func clickVideoButton(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        let player = AVPlayer(url: URL(string: object.media ?? "")!)
        let vc = AVPlayerViewController()
        vc.player = player
        self.present(vc, animated: true) {
            vc.player?.play()
        }
    }
    
    // Click Image Click
    @objc func clickImageClick(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        let vc = R.storyboard.dashboard.showImageVC()
        vc?.imageURL = object.media ?? ""
        vc?.isGif = false
        vc?.modalPresentationStyle = .fullScreen
        vc?.modalTransitionStyle = .coverVertical
        self.present(vc!, animated: true, completion: nil)
    }
    
    // Click File
    @objc func clickFile(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        if let pdfURL = URL(string: object.media ?? "") {
            let safariViewController = SFSafariViewController(url: pdfURL)
            safariViewController.delegate = self
            present(safariViewController, animated: true, completion: nil)
        }
    }
    
    // Open Contact
    @objc func openContact(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        let phoneString = self.decryptionAESModeECB(messageData: object._text, key: object._time) ?? ""
        let phoneData = htmlToString(text: phoneString)
        let contact = CNMutableContact()
        contact.givenName = phoneData?["Key"] as? String ?? ""
        contact.phoneNumbers = [CNLabeledValue(label: CNLabelHome, value: CNPhoneNumber(stringValue: phoneData?["Value"] as? String ?? ""))]
        let contactViewController = CNContactViewController(forNewContact: contact)
        contactViewController.delegate = self
        let navigationController = UINavigationController(rootViewController: contactViewController)
        present(navigationController, animated: true, completion: nil)
    }
    
    @objc func setLocationNavigaction(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        guard let url = URL(string: "comgooglemaps://") else {
            return
        }
        if UIApplication.shared.canOpenURL(url) {
            let url = URL(string: "comgooglemaps://?saddr=&daddr=\(object.lng ?? ""),\(object.lng ?? "")&directionsmode=driving")
            UIApplication.shared.open(url!, options: [:], completionHandler: nil)
        } else {
            let regionDistance: CLLocationDistance = 10000
            let coordinates = CLLocationCoordinate2DMake(Double(object.lat ?? "") ?? 0, Double(object.lng ?? "") ?? 0)
            let regionSpan = MKCoordinateRegion(center: coordinates, latitudinalMeters: regionDistance, longitudinalMeters: regionDistance)
            var options = NSObject()
            options = [
                MKLaunchOptionsMapCenterKey: NSValue(mkCoordinate: regionSpan.center),
                MKLaunchOptionsMapSpanKey: NSValue(mkCoordinateSpan: regionSpan.span),
                MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving
            ] as NSObject
            let placemark = MKPlacemark(coordinate: coordinates, addressDictionary: nil)
            let mapItem = MKMapItem(placemark: placemark)
            mapItem.openInMaps(launchOptions: options as? [String: AnyObject])
        }
    }
    
    @objc func clickGif(_ sender: UIButton) {
        let object = self.messagesArray[sender.tag]
        let vc = R.storyboard.dashboard.showImageVC()
        vc?.imageURL = object.stickers ?? ""
        vc?.isGif = true
        vc?.modalPresentationStyle = .fullScreen
        vc?.modalTransitionStyle = .coverVertical
        self.present(vc!, animated: true, completion: nil)
    }
    
}

// MARK: GroupMessageOptionDelegate Methods
extension ChatGroupViewController: GroupMessageOptionDelegate {
    
    func handleMessageOptionTap(index: Int, optionName: String, indexPath: IndexPath) {
        let object = self.messagesArray[indexPath.row]
        switch index {
        case 0:
            let messageString = "\(self.decryptionAESModeECB(messageData: object._text, key: object._time) ?? object._text)"
            UIPasteboard.general.string = messageString
        case 1:
            if let newVC = R.storyboard.favorite.messageInfoViewController() {
                newVC.object = object
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        case 2:
            self.deleteMessage(messageID: object.message_id ?? "", indexPath: indexPath.row)
        case 3:
            self.setUpReplyMessageView(message: object)
        case 4:
            if let newVC = R.storyboard.favorite.getFriendVC() {
                newVC.message = object
                newVC.isGroupMessage = true
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        default:
            break;
        }
    }
    
    func handleReactionTap(reaction: Int, optionName: String, indexPath: IndexPath) {
         let object = self.messagesArray[indexPath.row]
         let reaction = String(reaction)
         self.socketHelper.emit_register_reaction(id: object._message_id, reaction: reaction, user_id: AppInstance.instance._sessionId)
         // self.reactMessageApi(message_id: object._message_id, reaction: String(reaction), indexPath: indexPath)
    }
    
}

// MARK: AudioPlayerDelegate Methods
extension ChatGroupViewController: AudioPlayerDelegate {
    
    func playbackStateChanged(at indexPath: IndexPath?) {
        if let indexPath = indexPath {
            self.chatTableView.reloadRows(at: [indexPath], with: .none)
        }
    }
    
}

// MARK: CNContactViewControllerDelegate Methods
extension ChatGroupViewController: CNContactViewControllerDelegate {
    
    func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
        dismiss(animated: true, completion: nil)
        if contact != nil {
            print("Contact saved successfully!")            
        } else {
            print("Contact creation cancelled or failed.")
        }
    }
    
}

// MARK: SwipeToReplyCellDelegate
extension ChatGroupViewController: SwipeToReplyCellDelegate {
    
    func handleSwipeToReply(indexPath: IndexPath) {
        let message = self.messagesArray[indexPath.row]
        self.setUpReplyMessageView(message: message)
    }
    
}

// MARK: UIDocumentPickerDelegate Methods
extension ChatGroupViewController: UIDocumentPickerDelegate, UIDocumentInteractionControllerDelegate {
    
    func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
        controller.dismiss(animated: true)
        let fileData = try? Data(contentsOf: url)
        let fileExtension = String(url.lastPathComponent.split(separator: ".").last!)
        switch controller.title {
        case "Document":
            self.sendSelectedData(type: "file", imageData: nil, imageMimeType: nil, videoData: nil, videoMimeType: nil, fileData: fileData, fileExtension: fileExtension, fileMimeType: fileData?.mimeType, audio: nil, audioExtension: nil, audioMimeType: nil)
        case "Audio":
            self.sendSelectedData(type: "audio", imageData: nil, imageMimeType: nil, videoData: nil, videoMimeType: nil, fileData: nil, fileExtension: nil, fileMimeType: nil, audio: fileData, audioExtension: fileExtension, audioMimeType: "application/octet-stream")
        default:
            break
        }
    }
    
    func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
        return self
    }
    
}

// MARK: SPUIDelegate Methods
extension ChatGroupViewController: SPUIDelegate {
    
    func onStickerSingleTapped(_ view: SPUIView, sticker: SPSticker) {
        self.sendSticker(url: sticker.stickerImg, sticker_id: "sticker\(sticker.stickerId)")
        self.view.endEditing(true)
    }
    
}

extension ChatGroupViewController: didSelectGIFDelegate {
    
    func didSelectGIF(GIFUrl: String, id: String) {
        self.sendGIF(url: GIFUrl)
    }
    
}

// MARK: SendLocationProtocol Methods
extension ChatGroupViewController: sendLocationProtocol {
    
    func sendLocation(lat: Double, long: Double) {
        self.sendMessage(text: "", lat: lat, lng: long)
    }
    
}

// MARK: RecordViewDelegate Methods
extension ChatGroupViewController: RecordViewDelegate {
    
    func onStart() {
        print("onStart")
        self.view.endEditing(true)
        self.audioRecorderHelper.startRecording()
        self.audioRecordView.isHidden = false
        self.audioRecordButton.isHidden = true
        self.mediaButton.isHidden = true
        self.sendView.isHidden = true
    }
    
    func onCancel() {
        print("onCancel")
        self.audioRecordView.isHidden = true
        self.audioRecordButton.isHidden = false
        self.mediaButton.isHidden = false
        self.sendView.isHidden = false
        self.isSendRecordAudio = false
        self.audioRecorderHelper.cancelRecording()
    }
    
    func onFinished(duration: CGFloat) {
        print("onFinished \(duration)")
        self.audioRecordView.isHidden = true
        self.audioRecordButton.isHidden = false
        self.mediaButton.isHidden = false
        self.sendView.isHidden = false
        self.isSendRecordAudio = true
        self.showAudioRecordView()
        self.audioRecorderHelper.stopRecording()
    }
    
}

//MARK: AudioRecorderHelperDelegate Methods
extension ChatGroupViewController: AudioRecorderHelperDelegate {
    
    func audioRecordingFinished(success: Bool, audioURL: URL?) {
        self.audioFileURL = audioURL
        if let audioFileURL = self.audioFileURL {
            do {
                self.audioRecoderPlayer = try AVAudioPlayer(contentsOf: audioFileURL)
                self.audioRecoderPlayer.delegate = self
                self.audioRecoderPlayer.prepareToPlay()
                self.audioRecordSliderView.value = 0
                self.audioRecordSliderView.minimumValue = 0
                self.audioRecordSliderView.maximumValue = Float(self.audioRecoderPlayer?.duration ?? 0)
            } catch {
                print("Error initializing audio player: \(error)")
            }
        }
    }
    
}

// MARK: AVAudioPlayerDelegate Methods
extension ChatGroupViewController: AVAudioPlayerDelegate {
    
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        self.audioRecoderPlayer?.pause()
        self.audioRecodeTimer?.invalidate()
        self.audioRecordSliderView.value = Float(self.audioRecoderPlayer.currentTime)
        self.audioRecordPlayButton.setImage(UIImage(named: "icon_play_vector"), for: .normal)
    }
    
}

// MARK: SFSafariViewControllerDelegate Methods
extension ChatGroupViewController: SFSafariViewControllerDelegate {
    
    func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
        controller.dismiss(animated: true, completion: nil)
    }
    
}

// MARK: UITextViewDelegate Methods
extension ChatGroupViewController: UITextViewDelegate {
    
    func textViewDidChange(_ textView: UITextView) {
        self.setSendButton()
    }
    
    func textViewDidEndEditing(_ textView: UITextView) {
        self.messageTextView.isEmojiKeyboard = false
    }
    
}

// MARK: GroupBottomMoreVCDelegate Methods
extension ChatGroupViewController: GroupBottomMoreVCDelegate {
    
    func handleGroupMoreOptionTap(optionName: String, index: Int) {
        switch index {
        case 0:
            if let newVC = R.storyboard.group.updateGroupVC() {
                newVC.groupData = self.groupApiData
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        case 1:
            if let newVC = R.storyboard.group.groupInfoViewController() {
                newVC.groupData = self.groupApiData
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        case 2:
            if let alertVC = R.storyboard.group.groupAlertVC() {
                alertVC.delegate = self
                alertVC.messageText = "Are you sure to exit the group"
                alertVC.okText = "EXIT"
                self.present(alertVC, animated: true, completion: nil)
            }
        case 3:
            if let newVC = R.storyboard.group.groupChatSearchConversationVC() {
                newVC.groupData = self.groupApiData
                self.navigationController?.pushViewController(newVC, animated: true)
            }
        default:
            break
        }
    }
    
}

// MARK: ChatMediaOptionVCDelegate Methods
extension ChatGroupViewController: ChatMediaOptionVCDelegate {
    
    func handleCameraButtonTap() {
        self.view.endEditing(true)
        if UIImagePickerController.isSourceTypeAvailable(.camera) {
            self.imagePicker.delegate = self
            self.imagePicker.sourceType = .camera
            self.imagePicker.mediaTypes = ["public.movie", "public.image"]
            self.imagePicker.allowsEditing = false
            self.present(self.imagePicker, animated: true, completion: nil)
        } else {
            if let messageAlertVC = R.storyboard.popup.messageAlertVC() {
                messageAlertVC.messageText = "You don't have camera"
                self.present(messageAlertVC, animated: true, completion: nil)
                messageAlertVC.confirmButton.isHidden = true
            }
        }
    }
    
    func handleImageAndVideoButtonTap() {
        self.view.endEditing(true)
        self.imagePicker.delegate = self
        self.imagePicker.sourceType = .photoLibrary
        self.imagePicker.mediaTypes = ["public.movie", "public.image"]
        self.imagePicker.allowsEditing = false
        self.present(self.imagePicker, animated: true, completion: nil)
    }
    
    func handleDocumentButtonTap() {
        self.view.endEditing(true)
        let contentTypes: [UTType] = [
            .init(filenameExtension: "doc")!,
            .init(filenameExtension: "docx")!,
            .pdf,
            .presentation,
            .spreadsheet,
            .plainText,
            .text
        ]
        let pickerController = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes, asCopy: true)
        pickerController.title = "Document"
        pickerController.delegate = self
        pickerController.allowsMultipleSelection = false
        self.present(pickerController, animated: true, completion: nil)
    }
    
    func handleContactButtonTap() {
        self.view.endEditing(true)
        let contactPicker = CNContactPickerViewController()
        contactPicker.delegate = self
        contactPicker.displayedPropertyKeys = [CNContactPhoneNumbersKey]
        self.present(contactPicker, animated: true, completion: nil)
    }
    
    func handleGifButtonTap() {
        self.view.endEditing(true)
        if let newVC = R.storyboard.chat.gifVC() {
            newVC.delegate = self
            self.navigationController?.pushViewController(newVC, animated: true)
        }
    }
    
    func handleStickerButtonTap() {
        self.view.endEditing(true)
        let storeVC = SPUISearchViewController()
        storeVC.setUser(SPUser(userID: AppInstance.instance._userId))
        storeVC.delegate = self
        self.present(storeVC, animated: true)
    }
    
    func handleMusicButtonTap() {
        self.view.endEditing(true)
        let contentTypes: [UTType] = [
            .audio
        ]
        let pickerController = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes, asCopy: true)
        pickerController.title = "Audio"
        pickerController.delegate = self
        pickerController.allowsMultipleSelection = false
        self.present(pickerController, animated: true, completion: nil)
    }
    
    func handleLocationButtonTap() {
        self.view.endEditing(true)
        if let newVC = R.storyboard.chat.locationVC() {
            newVC.delegate = self
            self.navigationController?.pushViewController(newVC, animated: true)
        }
    }
    
}

// MARK: UIImagePickerControllerDelegate & UINavigationControllerDelegate Methods
extension ChatGroupViewController: UIImagePickerControllerDelegate & UINavigationControllerDelegate {
    
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        picker.dismiss(animated: true) {
            if let image = info[.originalImage] as? UIImage {
                if let newVC = R.storyboard.photoEditor.photoEditorVC() {
                    newVC.selectedImage = image
                    newVC.delegate = self
                    self.navigationController?.pushViewController(newVC, animated: true)
                }
            }
            if let videoURL = info[.mediaURL] as? URL {
                if let newVC = R.storyboard.story.videoEditorVC() {
                    newVC.delegate = self
                    newVC.videoUrl = videoURL
                    self.navigationController?.pushViewController(newVC, animated: true)
                }
            }
        }
    }
    
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        picker.dismiss(animated: true, completion: nil)
    }
    
}

// MARK: PhotoEditorVCDelegate
extension ChatGroupViewController: PhotoEditorVCDelegate {
    
    func handlePhotoEditorSaveButtonTap(image: UIImage) {
        let imageData = image.jpegData(compressionQuality: 1)
        self.sendSelectedData(type: "image", imageData: imageData, imageMimeType: imageData?.mimeType, videoData: nil, videoMimeType: nil, fileData: nil, fileExtension: nil, fileMimeType: nil, audio: nil, audioExtension: nil, audioMimeType: nil)
    }
    
}

// MARK: VideoEditorVCDelegate
extension ChatGroupViewController: VideoEditorVCDelegate {
    
    func videoEditorDidSaveVideo(url: URL) {
        let videoData = try? Data(contentsOf: url)
        self.sendSelectedData(type: "video", imageData: nil, imageMimeType: nil, videoData: videoData, videoMimeType: videoData?.mimeType, fileData: nil, fileExtension: nil, fileMimeType: nil, audio: nil, audioExtension: nil, audioMimeType: nil)
    }
    
}

// MARK: CNContactPickerDelegate Methods
extension ChatGroupViewController: CNContactPickerDelegate {
    
    func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
        if let phoneNumber = contactProperty.value as? CNPhoneNumber {
            let contactNumber = phoneNumber.stringValue
            let fullName = CNContactFormatter.string(from: contactProperty.contact, style: .fullName)
            let extendedParam = ["Key": fullName, "Value": contactNumber] as? [String: String]
            if let theJSONData = try?  JSONSerialization.data(withJSONObject: extendedParam ?? [:], options: []) {
                let theJSONText = String(data: theJSONData, encoding: String.Encoding.utf8)
                print("JSON string = \(theJSONText ?? "")")
                self.sendContact(jsonPayload: theJSONText)
            }
        }
    }
    
    func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
        // Handle the cancel action
    }
    
}

// MARK: UIViewControllerTransitioningDelegate Methods
extension ChatGroupViewController: UIViewControllerTransitioningDelegate {
    
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        BottomSheetPresentationController(presentedViewController: presented, presenting: presenting)
    }
    
}

// MARK: GroupAlertVCDelegate Methods
extension ChatGroupViewController: GroupAlertVCDelegate {
    
    func groupAlertOKButtonPressed(_ sender: UIButton) {
        self.exitGroup()
    }
    
}
