<?php
/**
 * SeekQuarry/Yioop --
 * Open Source Pure PHP Search Engine, Crawler, and Indexer
 *
 * Copyright (C) 2009 - 2026  Chris Pollett chris@pollett.org
 *
 * LICENSE:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * END LICENSE
 *
 * @author Chris Pollett chris@pollett.org
 * @license https://www.gnu.org/licenses/ GPL3
 * @link https://www.seekquarry.com/
 * @copyright 2009 - 2026
 * @filesource
 */
namespace seekquarry\yioop\views\elements;

use seekquarry\yioop as B;
use seekquarry\yioop\configs as C;
use seekquarry\yioop\library as L;
use seekquarry\yioop\library\CrawlConstants;

/**
 * Element responsible for draw the feeds a user is subscribed to
 *
 * @author Chris Pollett
 */
class UsermessagesElement extends Element implements CrawlConstants
{
    /**
     * Emojipicker helper
     * @var helper
     */
    public $emoji_helper;
    /**
     * constructor stores a reference to the view this element will reside on
     *
     * @param object $view   object this element will reside on
     */
    public function __construct($view = null)
    {
        parent::__construct($view);
        $this->emoji_helper = $this->view->helper('emojipicker');
    }
    /**
     * Renders the user-messages page (contact list + selected
     * conversation panel) into HTML.
     *
     * @param array $data field variables prepared by SocialComponent's
     *      userMessages activity for this view
     */
    public function render($data)
    {
        $is_mobile = !empty($data['MOBILE']);
        if (!empty($data['STATUS'])) {
            if (!empty($data['MESSAGES'])) {
                $this->renderContactMessages($data);
            }
            return;
        }
        ?>
        <div class="messages-container"><?php
        if ($is_mobile && empty($data['CONTACT_ID']) || !$is_mobile) { ?>
            <div class="user-contacts">
            <div class="socialcontrols-wrap">
            <?php
            $this->view->element("socialcontrols")->render($data);
            ?></div>
            <?=$this->renderContacts($data); ?>
            </div><?php
        }
        if (!$is_mobile) {
            ?>
            <div class="split-adjuster" id="split-adjuster">
            </div><?php
        }
        if (!$is_mobile || $is_mobile && !empty($data['CONTACT_ID'])) {?>
            <div class="contact-messages"><?php
            if (empty($data['CONTACT_ID'])) { ?>
                <div class="user-messages-warning">
                    <?= tl("usermessages_element_select_contact") ?>
                </div><?php
            } else {
                $this->renderContactMessages($data);
            } ?>
            </div><?php
        }?>
        </div>
        <?php
    }
    /**
     * Renders the contact search box and the per-contact list of
     * conversations into HTML.
     *
     * @param array $data field variables prepared by SocialComponent's
     *      userMessages activity, including CONTACTS and CONTACT_FILTER
     */
    public function renderContacts($data)
    {
        ?>
        <form class="center">
        <input type="hidden" name='<?=C\p('CSRF_TOKEN')?>'
            value='<?=$data[C\p('CSRF_TOKEN')]?>' >
        <input type="hidden" name='a' value='userMessages' >
        <input type="hidden" name='c' value='<?=$data['CONTROLLER'] ?>' >
        <div class="contact-actions" tabindex="1">
        <input type="search" name='contact_name'
            class="narrow-field" autocomplete="off"
            placeholder="<?=tl('usermessages_element_contact_filter')?>"
            id='contact-filter' value="<?=$data['CONTACT_FILTER'] ?? '' ?>"
            ><br>
        <button type='submit' name='arg' value="search"
            class="button-box"><?=
            tl('usermessages_element_search') ?></button>
        <button type='submit' name='arg' value="addcontact"
            class="button-box"><?=
            tl('usermessages_element_add_contact') ?></button>
        </div>
        </form>
        <?php
        $token_string = C\p('CSRF_TOKEN') . "=". $data[C\p('CSRF_TOKEN')];
        foreach ($data['CONTACTS'] as $contact_id => $contact_info) {
            $selected = ($contact_id == $data['CONTACT_ID']) ?
                " selected-contact " : "";
            ?>
            <div class="contact-detail <?=$selected?>" tabindex="0"
                onclick="javascript:elt('contact-id-<?=$contact_id
                    ?>').click()"><?php
            if ($contact_info['NUM_UNREAD_MESSAGES'] > 0) {?>
                <div class='unread-messages'><?=
                    $contact_info['NUM_UNREAD_MESSAGES'] ?></div><?php
            }?>
            <div class="contact-detail-inner">
            <img class="message-icon" src="<?=
                $contact_info["ICON_URL"]; ?>"
                alt="<?=tl('usermessages_element_user_icon'); ?>" >
            <a id="contact-id-<?=$contact_id
                ?>" href="<?=$this->formatHref(B\feedsUrl('user_messages',
                $contact_id, true, $data['CONTROLLER']) .
                $token_string)?>"><?=
                    $contact_info["USER_NAME"]; ?></a>
            </div>
            </div>
            <?php
        }
        if (!empty($data['CONTACT_REQUESTS'])) {
            $request_options = [
                "addcontact" => tl('usermessages_element_accept'),
                "blockcontact" => tl('usermessages_element_block'),
                "ignorecontact" => tl('usermessages_element_ignore'),
            ];
            foreach ($data['CONTACT_REQUESTS'] as $contact_id => $contact_info){
                $contact_request_url = B\feedsUrl('user_messages',
                    $contact_id, true, $data['CONTROLLER']) .
                    $token_string . "&amp;contact_id=$contact_id&amp;arg=";
                ?>
                <div class="contact-detail">
                <div class="contact-detail-inner">
                <img class="message-icon" src="<?=
                    $contact_info["ICON_URL"]; ?>"
                    alt="<?=tl('usermessages_element_user_icon'); ?>" >
                <span><?= $contact_info["USER_NAME"]; ?></span>
                </div>
                </div>
                <div class="contact-detail-request float-opposite">
                <?php
                $this->view->helper("options")->renderLinkDropDown(
                    "request-options$contact_id", $request_options,
                    '', $contact_request_url,
                    false, "",
                    tl('usermessages_element_request'));
                ?>
                </div>
                <?php
            }
        }
        if (empty($data['CONTACTS']) && empty($data['CONTACT_REQUESTS'])) { ?>
            <div class="user-messages-warning">
                <?= tl("usermessages_element_no_contacts") ?>
            </div>
            <?php
        }
    }
    /**
     * Renders the message-thread panel for the currently selected
     * contact into HTML.
     *
     * @param array $data field variables prepared by SocialComponent's
     *      userMessages activity, including MESSAGES and ADMIN
     */
    public function renderContactMessages($data)
    {
        $logged_in = !empty($data["ADMIN"]);
        $token_string = ($logged_in) ? C\p('CSRF_TOKEN') . "=" .
            $data[C\p('CSRF_TOKEN')]
            : "";
        $messages_url = B\controllerUrl("user_messages", true) .
            $token_string;
        if (empty($data['MESSAGES'])) { ?>
            <div class="user-messages-warning">
                <?= tl("usermessages_element_no_messages") ?>
            </div><?php
        } else {
            ?>
            <div id="conversation-header"
                class="selected-conversation-header"><?php
            if (!empty($data['MOBILE'])) {
                $arrow = ($data['LOCALE_DIR'] == 'rtl') ? "&gt;" : "&lt;";
                ?>
                <a class="float-same contacts-arrow" href="<?=
                    $messages_url?>"><?=$arrow ?></a>
                <?php
            }
            $now = time();
            if (C\GROUP_CALL_ICE_SERVERS) {
                ?><audio id="phone-sound"><source
                        src="<?= C\SHORT_BASE_URL . "/resources/" .
                        "freesound_org_audacitier_phone_ringing_5.mp3" ?>"
                        type="audio/mpeg">
                </audio>
                <div class="call-controls float-opposite">
                <?= $this->view->helper("iconlink")->renderButton(
                    ['video-end',
                    'javascript:setCallState("video-end")'], 'video_call_end',
                    div_classes: 'video-call-end  float-opposite none');?>
                <?= $this->view->helper("iconlink")->renderButton(
                    ['video-start',
                    'javascript:setCallState("video")'], 'video_call',
                    div_classes: 'video-call  float-opposite');?>
                </div><?php
            }?>
            <h2>
            <img class="message-icon" src="<?=
                $data["CONTACT_ICON_URL"]; ?>"
                alt="<?=tl('usermessages_element_user_icon'); ?>" >
                <span><?= $data['CONTACT_NAME'] ?></span>
                <?php
                if (!empty($data['AVAILABLE_LOCALES'])) {
                $current_language = $data['TRANSLATION_LANGUAGE'] ?? 'off';
                $translation_url = $messages_url . "&amp;contact_id=" .
                    $data['CONTACT_ID'] .
                    "&amp;arg=settranslation&amp;language=";
                $available_locales = $data['AVAILABLE_LOCALES'];
                $user_locale = $data['CURRENT_LOCALE_TAG'] ?? 'en_US';
                $is_auto_translating = ($current_language === 'off' ||
                    empty($current_language)) &&
                    $user_locale !== 'en_US' &&
                    $user_locale !== C\p('DEFAULT_LOCALE') &&
                    isset($available_locales[$user_locale]);
                if ($current_language !== 'off' &&
                    isset($available_locales[$current_language])) {
                    $current_locale_name = $available_locales[$current_language];
                    unset($available_locales[$current_language]);
                    $reordered_locales = [$current_language =>
                        $current_locale_name] + $available_locales;
                    $show_top_text = $current_locale_name;
                } elseif ($is_auto_translating) {
                    $current_locale_name = $available_locales[$user_locale];
                    unset($available_locales[$user_locale]);
                    $reordered_locales = [$user_locale =>
                        $current_locale_name] + $available_locales;
                    $show_top_text = $current_locale_name;
                    $current_language = $user_locale;
                } else {
                    $reordered_locales = $available_locales;
                    $show_top_text = tl('toggle_helper_off');
                }
                $this->view->helper("options")->renderLinkDropDown(
                    "translation-language", $reordered_locales,
                    $current_language, $translation_url, false, "",
                    $show_top_text);
                }
                ?>
            </h2>
            </div>
            <div id="av-call"></div>
            <div id="conversation" class="conversation" data-time="<?=
                $now?>" data-contact-id="<?= $data['CONTACT_ID'] ?? '' ?>"
                data-loaded-count="<?= count($data['MESSAGES']) ?>"
                data-oldest-timestamp="<?= isset($data['MESSAGES']) &&
                count($data['MESSAGES']) > 0 ?
                $data['MESSAGES'][count($data['MESSAGES']) - 1]['PUBDATE'] :
                $now ?>"
                onscroll="handleConversationScroll()" ><?php
            $old_pubdate = $now;
            $old_user = $data['MESSAGES'][0]['USER_NAME'] ?? "";
            $num_messages = count($data['MESSAGES']);
            for ($i = 0; $i < $num_messages; $i++) {
                $message_info = $data['MESSAGES'][$i];
                $next_message_info = $data['MESSAGES'][$i + 1] ??
                    $message_info;
                $next_user_name = $next_message_info['USER_NAME'];
                if (empty($message_info[self::DESCRIPTION])) {
                    continue;
                }
                $pub_date = $message_info['PUBDATE'];
                $next_pub_date = $next_message_info['PUBDATE'];
                $pub_date_diff = abs($next_pub_date - $pub_date);
                $pub_date_age = $now - $pub_date;
                $user_change = $message_info['USER_NAME'] != $next_user_name;
                $pub_data_change = $user_change ||
                    ($pub_date_age < C\ONE_HOUR &&
                    $pub_date_diff > 5 * C\ONE_MINUTE) ||
                    ($pub_date_age < C\ONE_DAY &&
                    $pub_date_diff > C\ONE_HOUR) ||
                    ($pub_date_diff > C\ONE_DAY);
                $pub_date_string =
                    $this->view->helper("feeds")->getPubdateString(
                    $now, $pub_date, false);
                $color = "back-light-gray";
                $align = "align-same";
                $is_user = false;
                $user_string = "other";
                $top_corner = " top-corner ";
                if ($data['USERNAME'] == $message_info['USER_NAME']) {
                    $color = "back-light-blue";
                    $align = "align-opposite";
                    $is_user = true;
                    $user_string = "user";
                    $top_corner =  "";
                }
                $comma = "";
                ?>
                <div class="<?=$align ?>">
                <div class="message-detail-outer">
                <div class='message-<?=$user_string?>-time' >
                <?php
                if (!$is_user && ($pub_data_change || $user_change)) {
                    e('<img class="message-icon float-same" src="'.
                        $message_info['USER_ICON'].'" >&nbsp;');
                    $comma = ", ";
                    e($message_info['USER_NAME']);
                }
                if ($pub_data_change) {
                    e($comma . $pub_date_string);
                }?>
                </div>
                <div class="message-detail <?=$color . $top_corner?>"><?=
                $message_info[self::DESCRIPTION];
                ?>
                </div>
                </div>
                </div>
                <?php
            }?>
        </div><?php
        }
        $this->drawNewMessageForm($data);
    }
    /**
     * Used to draw the new message form to add a message to an
     * existing conversation
     *
     * @param array $data containing other field needed to draw the form
     */
    private function drawNewMessageForm($data)
    {
        $arrow = ($data['LOCALE_DIR'] == 'rtl') ? "←" : "→";
        ?>
        <div id="new-message-container">
        <form  id="newmessageForm" method="post" action="<?=C\SHORT_BASE_URL?>"
            enctype='multipart/form-data' onsubmit="parseEmojiShortcuts()">
        <input type="hidden" name="c" value="<?=$data['CONTROLLER'] ?>" >
        <input type="hidden" name="a" value="userMessages" >
        <input type="hidden" name="arg" value="newmessage" >
        <input type="hidden" name="contact_id" value="<?=
            $data['CONTACT_ID']; ?>" >
        <input type="hidden" name="<?= C\p('CSRF_TOKEN') ?>"
            value="<?= $data[C\p('CSRF_TOKEN')] ?>" >
        <input type="file" id="file-new-message"
            name="file_new_message" class="none" multiple="multiple" >
        <a id="attach-new-file"
            href="javascript:elt('file-new-message').click()"
            >📎</a>
        <span id="user-input-container">
            <button id="emoji-picker-button" type="button"
                style="filter: grayscale(100%);"
                onclick="toggleEmojiPicker()">🙂</button>
            <div class="emoji-picker-container" id="emoji-picker-container">
                <?=$this->emoji_helper->render();?>
            </div>
            <input type="text" id="new-message"  name="description"
                placeholder="<?=tl('usermessages_element_new_message') ?>" >
        </span>
        <button type="button" id="audio-record-btn" class="audio-control">
        <span id="mic-icon">🎤</span>
        </button>
        <div id="audio-controls" class="none">
            <button
                type="button"
                id="play-audio-btn"
                class="audio-control">▶️</button>
            <button
                type="button"
                id="delete-audio-btn"
                class="audio-control">🗑️</button>
        </div>
        <button type="submit" id="send-message" ><?=$arrow ?></button>
        </form>
        </div>
        <script>
        if (typeof yioop_post_scripts !== 'object' ) {
            yioop_post_scripts = {};
        }
        yioop_post_scripts['new-message'] = function() {
            initializeFileHandler('new-message', "file-new-message",
              <?= min(L\metricToInt(ini_get('upload_max_filesize')),
              L\metricToInt(ini_get('post_max_size')))
              ?>, "textarea", null, true);
            initializeAudioRecorder();
        }
        const emoji_groups = <?php echo
            json_encode($this->emoji_helper->emoji_groups); ?>;
        let emojis_array = {};
        for (const group in emoji_groups) {
            let group_data = emoji_groups[group];
            for (const emoji in group_data["emojis"]) {
                emojis_array[emoji] = group_data["emojis"][emoji][0];
            }
        }
        function insertEmoji(emoji)
        {
            let input = elt('new-message');
            input.value += emoji;
        }
        function toggleEmojiPicker()
        {
            let emoji_picker = elt('emoji-picker-container');
            let emoji_picker_button = elt('emoji-picker-button');
            if (emoji_picker.style.display === "none"
                || emoji_picker.style.display === "") {
                emoji_picker.style.display = "inline-block";
                emoji_picker_button.innerHTML = "🔽";
            } else {
                emoji_picker.style.display = "none";
                emoji_picker_button.innerHTML = "🙂";
            }
        }
        function toggleEmojiGroup(emoji_grp_tab, emoji_grp_name)
        {
            let emoji_grp_id = "emoji-group-" + emoji_grp_name;
            let emoji_groups =
                document.getElementsByClassName("emoji-group-container");
            for (let i=0;i<emoji_groups.length;i++) {
                if (emoji_groups[i].id === emoji_grp_id) {
                    emoji_groups[i].className += " active-emoji-group";
                } else {
                    emoji_groups[i].className = "emoji-group-container";
                }
            }
            let emoji_grps_tab =
                document.getElementsByClassName("emoji-group-tab");
            for (let i = 0; i < emoji_grps_tab.length; i++) {
                emoji_grps_tab[i].className = "emoji-group-tab";
            }
            emoji_grp_tab.className += " active-emoji-group-tab";
        }
        function parseEmojiShortcuts()
        {
            let input = document.getElementById("new-message");
            let raw_message = input.value;
            let possible_shortcuts = raw_message.matchAll(/\[([^\]]+)\]/g);
            let parse_message = "";
            let last_start_idx = 0;
            for (let shortcut of possible_shortcuts) {
                let text = shortcut[1];
                let emoji = emojis_array[text];
                if (emoji !== undefined) {
                    parse_message += raw_message.substring(last_start_idx,
                        shortcut["index"]) + emoji;
                } else {
                    parse_message += raw_message.substring(last_start_idx,
                        shortcut["index"]) + "[" + text + "]";
                }
                last_start_idx = shortcut["index"] + text.length + 2;
            }
            parse_message += raw_message.substring(last_start_idx);
            input.value = parse_message;
            return true;
        }
    </script></div><?php
    }
}
