{extends "../@layout.xml"}
{block title}{$correspondent->getCanonicalName()}{/block}

{block header}
    
<a href="/im">{_my_messages}</a> »
<a href="{$correspondent->getURL()}">{$correspondent->getCanonicalName()}</a>    
    <div n:if="($online = $correspondent->getOnline()->timestamp()) + 2505600 > time()" style="float: right;">
        {var diff = date_diff(date_create(), date_create('@' . $online))}
        {if 5 >= $diff->i}
            <span><b>{_online}</b></span>
        {else}
            <span>{$correspondent->isFemale() ? "заходила" : "заходил"} {$correspondent->getOnline()}</span>
        {/if}
    </div>
{/block}

{block wrap}
    <div class="messenger-app">
        <div class="messenger-app--messages" data-bind="event: { scroll: onMessagesScroll }">
            <div data-bind="foreach: messages">
                <div class="messenger-app--messages---message" data-bind="css: { unread: !read }">
                    <img class="ava" data-bind="attr: { src: sender.avatar, alt: sender.name }" />
                    <div class="_content">
                        <a href="#" data-bind="attr: { href: sender.link }">
                            <strong data-bind="text: sender.name"></strong>
                        </a>
                        <span class="text" data-bind="html: text"></span>
                        <div data-bind="foreach: attachments" class="attachments">
                            <div class="msg-attach-j">
                                <div data-bind="if: type === 'photo'" class="msg-attach-j-photo">
                                    <a data-bind="attr: { href: link }">
                                        <img data-bind="attr: { src: photo.url, alt: photo.caption  }" />
                                    </a>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="time" align="right">
                        <span data-bind="text: timing.sent"></span>
                    </div>
                </div>
            </div>
        </div>
        <div class="messenger-app--input">
            {if $correspondent->getId() === $thisUser->getId() || $correspondent->getPrivacyPermission('messages.write', $thisUser)}
                <img class="ava" src="{$thisUser->getAvatarUrl()}" alt="{$thisUser->getCanonicalName()}" />
                <div class="messenger-app--input---messagebox">
                    <textarea
                            data-bind="value: messageContent, event: { keydown: onTextareaKeyPress }"
                            name="message"
                            placeholder="Введите сообщение"></textarea>
                    <button class="button" data-bind="click: sendMessage">Отправить</button>
                </div>
                <img class="ava" src="{$correspondent->getAvatarUrl()}" alt="{$correspondent->getCanonicalName()}" />
            {else}
                <div class="blocked" data-localized-text="Вы не можете писать сообщения {$correspondent->getCanonicalName()} из-за его настроек приватности."></div>
            {/if}
        </div>
    </div>
    
    <script src="https://knockoutjs.com/downloads/knockout-3.5.1.js"></script>
    <script>
        function MessengerViewModel(initialMessages = []) {
            window.messages     = ko.observableArray(initialMessages);
            this.messages       = window.messages;
            this.messageContent = ko.observable("");
            
            this.sendMessage = model => {
                if(model.messageContent() === "") return false;
                
                window.Msg.sendMessage(model.messageContent());
                model.messageContent("");
            };
            this.loadHistory = _ => {
                window.Msg._loadHistory();
            };
            
            this.onMessagesScroll   = (model, e) => {
                if(e.target.scrollTop < 21)
                    model.loadHistory();
            };
            this.onTextareaKeyPress = (model, e) => {
                if(e.which === 13) {
                    if(!e.metaKey && !e.shiftKey) {
                        let ta = u("textarea[name=message]").nodes[0];
                        ta.blur(); //Fix update
                        model.sendMessage(model);
                        ta.focus();
                        
                        return false;
                    }
                }
                
                return true;
            };
        }
        
        class Messenger {
            constructor(messages = []) {
                this.ko     = ko.applyBindings(new MessengerViewModel(messages));
                this.appEl  = document.querySelector(".messenger-app--messages");
                this.offset = 0;
                
                this._loadHistory();
                this._setupListener();
                this.appEl.scrollTop = this.appEl.scrollHeight;
            }
            
            _loadHistory() {
                let xhr = new XMLHttpRequest();
                xhr.open("GET", "/im/api/messages" + {$correspondent->getId()} + `/${ this.offset }.json`, false);
                xhr.send();
                
                let messages    = JSON.parse(xhr.responseText);
                let lastMessage = messages[messages.length - 1];
                if(typeof lastMessage !== "undefined") this.offset = lastMessage.uuid;
                
                this.prependMessages(messages);
            }
            
            _setupListener() {
                let listenLongpool = () => {
                    let xhr = new XMLHttpRequest();
                    xhr.open("GET", "/im12", true);
                    xhr.onload = () => {
                        let data = JSON.parse(xhr.responseText);
                        data.forEach(event => {
                            event = event.event;
                            if(event.type !== "newMessage")
                                return;
                            else if(event.message.sender.id !== {$correspondent->getId()})
                                return;
                            else if(this.offset >= event.message.uuid)
                                return void(console.warn("Gay message recieved, skipping. [-WHeterosexual]"));
                            
                            this.addMessage(event.message);
                            this.offset = event.message.uuid;
                        });
                        
                        listenLongpool();
                    };
                    xhr.send();
                };
                
                listenLongpool();
            }
            
            appendMessages(messages) {
                messages.forEach(m => window.messages.push(m));
            }
            
            prependMessages(messages) {
                messages.forEach(m => window.messages.unshift(m));
            }
            
            addMessage(message, scroll = true) {
                this.appendMessages([message]);
                
                if(scroll) {
                    this.appEl.scrollTop = this.appEl.scrollHeight;
                }
            }
            
            _patchMessage(tempId, message) {
                for(let i = window.messages().length - 1; i > -1; i--) {
                    let msg = window.messages()[i];
                    if(typeof msg._tuid === "undefined")
                        return;
                    else if(msg._tuid !== tempId)
                        return;
                    
                    window.messages.valueWillMutate();
                    window.messages()[i] = message;
                    window.messages.valueHasMutated();
                }
            }
            
            _newSelfMessage(content = "...") {
                return {
                    "sender": {
                        "link": {$thisUser->getURL()},
                        "avatar": {$thisUser->getAvatarUrl()},
                        "name": {$thisUser->getFullName()}
                    },
                    "timing": {
                        "sent": window.API.Service.getTime(),
                        "edited": null
                    },
                    "text": content,
                    "read": false,
                    "attachments": [],
                    "_tuid": Math.ceil(performance.now())
                };
            }
            
            _newReplyMessage(content = "...") {
                return {
                    "sender": {
                        "link": {$correspondent->getURL()},
                        "avatar": {$correspondent->getAvatarUrl()},
                        "name": {$correspondent->getFullName()}
                    },
                    "timing": {
                        "sent": window.API.Service.getTime(),
                        "edited": null
                    },
                    "text": content,
                    "read": true,
                    "_tuid": Math.ceil(performance.now())
                };
            }
            
            newMessage(content) {
                let msg = this._newSelfMessage(content);
                this.addMessage(msg);
                
                return msg._tuid;
            }
            
            newReply(content) {
                let msg = this._newReplyMessage(content);
                this.addMessage(msg);
                
                return msg._tuid;
            }
            
            newReplies(replies) {
                replies.forEach(this.newReply);
            }
            
            sendMessage(content) {
                console.debug("New outcoming message. Pushing preview to local stack.");
                let tempId = this.newMessage(content);
                
                let msgData = new FormData();
                msgData.set("content", content);
                msgData.set("hash", {$csrfToken});
                
                let that = this;
                let xhr  = new XMLHttpRequest();
                xhr.open("POST", "/im/api/messages" + {$correspondent->getId()} + "/create.json", true);
                xhr.onreadystatechange = (function() {
                    if(this.readyState !== 4)
                        return;
                    else if(this.status !== 202) {
                        console.error("Message was not sent.");
                        that._patchMessage(tempId, {
                            sender: {
                                avatar: "/assets/packages/static/openvk/img/oof.apng",
                                id: -1,
                                link: "/support/manpages/messages/not-delivered.html",
                                name: "Сообщение не доставлено"
                            },
                            text: "При отправке этого сообщения произошла ошибка общего характера...",
                            timing: {
                                edited: null,
                                sent: "???"
                            },
                            uuid: -4096
                        });
                        
                        return;
                    }
                    
                    console.debug("Message sent, updating view.");
                    that._patchMessage(tempId, JSON.parse(xhr.responseText));
                });
                xhr.send(msgData);
                console.debug("Message sent, awaiting response.");
            }
        }
        
        window.Msg = new Messenger([]);
    </script>
{/block}