<?php
/*
 * @package AJAX_Chat
 * @author Sebastian Tschan
 * @copyright (c) Sebastian Tschan
 * @license GNU Affero General Public License
 * @link https://blueimp.net/ajax/
 */

// Class to handle HTML templates
class AJAXChatTemplate {

    private $ajaxChat;
    private $_regExpTemplateTags;
    private $_templateFile;
    private $_contentType;
    private $_content;
    private $_parsedContent;

    // Constructor:
    function __construct(&$ajaxChat, $templateFile, $contentType=null) {
        $this->ajaxChat = $ajaxChat;
        $this->_regExpTemplateTags = '/\[(\w+?)(?:(?:\/)|(?:\](.+?)\[\/\1))\]/s';
        $this->_templateFile = $templateFile;
        $this->_contentType = $contentType;
    }

    function getParsedContent() {
        if(!$this->_parsedContent) {
            $this->parseContent();
        }
        return $this->_parsedContent;
    }

    function getContent() {
        if(!$this->_content) {
            $this->_content = AJAXChatFileSystem::getFileContents($this->_templateFile);
        }
        return $this->_content;
    }

    function parseContent() {
        $this->_parsedContent = $this->getContent();

        // Remove the XML declaration if the content-type is not xml:
        if($this->_contentType && (strpos($this->_contentType,'xml') === false)) {
            $doctypeStart = strpos($this->_parsedContent, '<!DOCTYPE ');
            if($doctypeStart !== false) {
                // Removing the XML declaration (in front of the document type) prevents IE<7 to go into "Quirks mode":
                $this->_parsedContent = substr($this->_parsedContent, $doctypeStart);
            }
        }

        // Replace template tags ([TAG/] and [TAG]content[/TAG]) and return parsed template content:
        $this->_parsedContent = preg_replace_callback($this->_regExpTemplateTags, array($this, 'replaceTemplateTags'), $this->_parsedContent);
    }

    function replaceTemplateTags($tagData) {
        switch($tagData[1]) {
            case 'AJAX_CHAT_URL':
                return $this->ajaxChat->htmlEncode($this->ajaxChat->getChatURL());

            case 'CONF':
                return $this->ajaxChat->getConfig(...explode('.', $tagData[2], 2));

            case 'LANG':
                return $this->ajaxChat->htmlEncode($this->ajaxChat->getLang($tagData[2]));
            case 'LANG_CODE':
                return $this->ajaxChat->getLangCode();

            case 'BASE_DIRECTION':
                return $this->getBaseDirectionAttribute();

            case 'CONTENT_ENCODING':
                return $this->ajaxChat->getConfig('contentEncoding');

            case 'CONTENT_TYPE':
                return $this->_contentType;

            case 'LOGIN_URL':
                return ($this->ajaxChat->getRequestVar('view') == 'logs') ? './?view=logs' : './';

            case 'USER_NAME_MAX_LENGTH':
                return $this->ajaxChat->getConfig('userNameMaxLength');
            case 'MESSAGE_TEXT_MAX_LENGTH':
                return $this->ajaxChat->getConfig('messageTextMaxLength');

            case 'LOGIN_CHANNEL_ID':
                return $this->ajaxChat->getValidRequestChannelID();

            case 'SESSION_NAME':
                return $this->ajaxChat->getConfig('sessionName');

            case 'COOKIE_EXPIRATION':
                return $this->ajaxChat->getConfig('sessionCookieLifeTime');
            case 'COOKIE_PATH':
                return $this->ajaxChat->getConfig('sessionCookiePath');
            case 'COOKIE_DOMAIN':
                return $this->ajaxChat->getConfig('sessionCookieDomain');
            case 'COOKIE_SECURE':
                return $this->ajaxChat->getConfig('sessionCookieSecure');

            case 'CHAT_BOT_NAME':
                return rawurlencode($this->ajaxChat->getConfig('chatBotName'));
            case 'CHAT_BOT_ID':
                return $this->ajaxChat->getConfig('chatBotID');

            case 'ALLOW_USER_MESSAGE_DELETE':
                if($this->ajaxChat->getConfig('allowUserMessageDelete'))
                    return 1;
                else
                    return 0;

            case 'INACTIVE_TIMEOUT':
                return $this->ajaxChat->getConfig('inactiveTimeout');

            case 'PRIVATE_CHANNEL_DIFF':
                return $this->ajaxChat->getConfig('privateChannelDiff');
            case 'PRIVATE_MESSAGE_DIFF':
                return $this->ajaxChat->getConfig('privateMessageDiff');

            case 'SHOW_CHANNEL_MESSAGES':
                if($this->ajaxChat->getConfig('showChannelMessages'))
                    return 1;
                else
                    return 0;

            case 'SOCKET_SERVER_ENABLED':
                if($this->ajaxChat->getConfig('socketServerEnabled'))
                    return 1;
                else
                    return 0;

            case 'SOCKET_SERVER_HOST':
                if($this->ajaxChat->getConfig('socketServerHost')) {
                    $socketServerHost = $this->ajaxChat->getConfig('socketServerHost');
                } else {
                    $socketServerHost = (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']);
                }
                return rawurlencode($socketServerHost);

            case 'SOCKET_SERVER_PORT':
                return $this->ajaxChat->getConfig('socketServerPort');

            case 'SOCKET_SERVER_CHAT_ID':
                return $this->ajaxChat->getConfig('socketServerChatID');

            case 'STYLE_SHEETS':
                return $this->getStyleSheetLinkTags();

            case 'CHANNEL_OPTIONS':
                return $this->getChannelOptionTags();
            case 'STYLE_OPTIONS':
                return $this->getStyleOptionTags();
            case 'LANGUAGE_OPTIONS':
                return $this->getLanguageOptionTags();

            case 'ERROR_MESSAGES':
                return $this->getErrorMessageTags();

            case 'LOGS_CHANNEL_OPTIONS':
                return $this->getLogsChannelOptionTags();
            case 'LOGS_YEAR_OPTIONS':
                return $this->getLogsYearOptionTags();
            case 'LOGS_MONTH_OPTIONS':
                return $this->getLogsMonthOptionTags();
            case 'LOGS_DAY_OPTIONS':
                return $this->getLogsDayOptionTags();
            case 'LOGS_HOUR_OPTIONS':
                return $this->getLogsHourOptionTags();
            case 'MENU_BAR':
                return <<<EOF
<ul>
    <li class="first notcurrent"><a href="{$this->ajaxChat->getConfig('flashiiUrl', 'home')}">Home</a></li>
    <li class="notcurrent"><a href="{$this->ajaxChat->getConfig('flashiiUrl', 'news')}">News</a></li>
    <li class="current"><a href="./">Chat</a></li>
    <li class="notcurrent"><a href="{$this->ajaxChat->getConfig('flashiiUrl', 'members')}">Members</a></li>
    <li class="notcurrent"><a href="{$this->ajaxChat->getConfig('flashiiUrl', 'donate')}">Donate</a></li>
    <li class="notcurrent"><a href="{$this->ajaxChat->getConfig('flashiiUrl', 'status')}">Status</a></li>
</ul>
EOF;
            case 'COPYRIGHT':
                return <<<EOF
<div class="copyright">
    Copyright &copy; 2013-2015 <a href="https://flash.moe/" target="_blank">Flashwave</a>
    <br /><a href="https://blueimp.net/ajax/" target="_blank">AJAX Chat</a> &copy; <a href="https://blueimp.net" target="_blank">blueimp.net</a>
    <br />
    <a href="{$this->ajaxChat->getConfig('flashiiUrl', 'feedback')}">Feedback</a> |
    <a href="{$this->ajaxChat->getConfig('flashiiUrl', 'changelog')}">Changelog</a> |
    <a href="{$this->ajaxChat->getConfig('flashiiUrl', 'rules')}">Rules &amp; Info</a> |
    <a href="{$this->ajaxChat->getConfig('flashiiUrl', 'terms')}">Terms of Service</a> |
    <a href="{$this->ajaxChat->getConfig('flashiiUrl', 'contact')}">Contact</a> |
    <a href="{$this->ajaxChat->getConfig('flashiiUrl', 'test')}">DevSite</a> |
    <a href="?view=legacy">Legacy Login</a>
</div><br />
EOF;
            case 'SANDSTORM':
                if(date('md') === '0127' || !empty($_GET['sandstorm']))
                    return <<<HTML
                    <br />
                    <audio loop="loop" autoplay="autoplay" controls="controls">
                        <source type="audio/ogg" src="./sandstorm.ogg" />
                        <source type="audio/mpeg" src="./sandstorm.mp3" />
                    </audio>
                    <br />
HTML;
                else
                    return '';
            default:
                return $this->ajaxChat->replaceCustomTemplateTags($tagData[1], (isset($tagData[2]) ? $tagData[2] : null));
            }
    }

    // Function to display alternating table row colors:
    function alternateRow($rowOdd='rowOdd', $rowEven='rowEven') {
        static $i;
        $i += 1;
        if($i % 2 == 0) {
            return $rowEven;
        } else {
            return $rowOdd;
        }
    }

    function getBaseDirectionAttribute() {
        $langCodeParts = explode('-', $this->ajaxChat->getLangCode());
        switch($langCodeParts[0]) {
            case 'ar':
            case 'fa':
            case 'he':
                return 'rtl';
            default:
                return 'ltr';
        }
    }

    function getStyleSheetLinkTags() {
        $styleSheets = '';
        foreach($this->ajaxChat->getConfig('styleAvailable') as $style) {
            $alternate = ($style == $this->ajaxChat->getConfig('styleDefault')) ? '' : 'alternate ';
            $styleSheets .= '<link rel="'.$alternate.'stylesheet" type="text/css" href="css/'.rawurlencode($style).'.ajaxchat.css" title="'.$this->ajaxChat->htmlEncode($style).'"/>';
        }
        return $styleSheets;
    }

    function getChannelOptionTags() {
        $channelOptions = '';
        $channelSelected = false;
        foreach($this->ajaxChat->getChannels() as $key=>$value) {
            if($this->ajaxChat->isLoggedIn()) {
                $selected = ($value == $this->ajaxChat->getChannel()) ? ' selected="selected"' : '';
            } else {
                $selected = ($value == $this->ajaxChat->getConfig('defaultChannelID')) ? ' selected="selected"' : '';
            }
            if($selected) {
                $channelSelected = true;
            }
            $channelOptions .= '<option value="'.$this->ajaxChat->htmlEncode($key).'"'.$selected.'>'.$this->ajaxChat->htmlEncode($key).'</option>';
        }
        if($this->ajaxChat->isLoggedIn() && $this->ajaxChat->isAllowedToCreatePrivateChannel()) {
            // Add the private channel of the user to the options list:
            if(!$channelSelected && $this->ajaxChat->getPrivateChannelID() == $this->ajaxChat->getChannel()) {
                $selected = ' selected="selected"';
                $channelSelected = true;
            } else {
                $selected = '';
            }
            $privateChannelName = $this->ajaxChat->getPrivateChannelName();
            $channelOptions .= '<option value="'.$this->ajaxChat->htmlEncode($privateChannelName).'"'.$selected.'>'.$this->ajaxChat->htmlEncode($privateChannelName).'</option>';
        }
        // If current channel is not in the list, try to retrieve the channelName:
        if(!$channelSelected) {
            $channelName = $this->ajaxChat->getChannelName();
            if($channelName !== null) {
                $channelOptions .= '<option value="'.$this->ajaxChat->htmlEncode($channelName).'" selected="selected">'.$this->ajaxChat->htmlEncode($channelName).'</option>';
            } else {
                // Show an empty selection:
                $channelOptions .= '<option value="" selected="selected">---</option>';
            }
        }
        return $channelOptions;
    }

    function getStyleOptionTags() {
        $styleOptions = '';
        foreach($this->ajaxChat->getConfig('styleAvailable') as $style) {
            $selected = ($style == $this->ajaxChat->getConfig('styleDefault')) ? ' selected="selected"' : '';
            $styleOptions .= '<option value="'.$this->ajaxChat->htmlEncode($style).'"'.$selected.'>'.$this->ajaxChat->htmlEncode($style).'</option>';
        }
        return $styleOptions;
    }

    function getLanguageOptionTags() {
        $languageOptions = '';
        $languageNames = $this->ajaxChat->getConfig('langNames');
        foreach($this->ajaxChat->getConfig('langAvailable') as $langCode) {
            $selected = ($langCode == $this->ajaxChat->getLangCode()) ? ' selected="selected"' : '';
            $languageOptions .= '<option value="'.$this->ajaxChat->htmlEncode($langCode).'"'.$selected.'>'.$languageNames[$langCode].'</option>';
        }
        return $languageOptions;
    }

    function getErrorMessageTags() {
        $errorMessages = '';
        foreach($this->ajaxChat->getInfoMessages('error') as $error) {
            $errorMessages .= '<h3 class="miotitle">'.$this->ajaxChat->htmlEncode($this->ajaxChat->getLang($error)).'</h3>';
        }
        return $errorMessages;
    }

    function getLogsChannelOptionTags() {
        $channelOptions = '';
        $channelOptions .= '<option value="-3">------</option>';
        foreach($this->ajaxChat->getChannels() as $key=>$value) {
            if($this->ajaxChat->getUserRole() != AJAX_CHAT_ADMIN && $this->ajaxChat->getConfig('logsUserAccessChannelList') && !in_array($value, $this->ajaxChat->getConfig('logsUserAccessChannelList'))) {
                continue;
            }
            $channelOptions .= '<option value="'.$value.'">'.$this->ajaxChat->htmlEncode($key).'</option>';
        }
        $channelOptions .= '<option value="-1">'.$this->ajaxChat->htmlEncode($this->ajaxChat->getLang('logsPrivateChannels')).'</option>';
        $channelOptions .= '<option value="-2">'.$this->ajaxChat->htmlEncode($this->ajaxChat->getLang('logsPrivateMessages')).'</option>';
        return $channelOptions;
    }

    function getLogsYearOptionTags() {
        $yearOptions = '';
        $yearOptions .= '<option value="-1">----</option>';
        for($year=date('Y'); $year>=$this->ajaxChat->getConfig('logsFirstYear'); $year--) {
            $yearOptions .= '<option value="'.$year.'">'.$year.'</option>';
        }
        return $yearOptions;
    }

    function getLogsMonthOptionTags() {
        $monthOptions = '';
        $monthOptions .= '<option value="-1">--</option>';
        for($month=1; $month<=12; $month++) {
            $monthOptions .= '<option value="'.$month.'">'.sprintf("%02d", $month).'</option>';
        }
        return $monthOptions;
    }

    function getLogsDayOptionTags() {
        $dayOptions = '';
        $dayOptions .= '<option value="-1">--</option>';
        for($day=1; $day<=31; $day++) {
            $dayOptions .= '<option value="'.$day.'">'.sprintf("%02d", $day).'</option>';
        }
        return $dayOptions;
    }

    function getLogsHourOptionTags() {
        $hourOptions = '';
        $hourOptions .= '<option value="-1">-----</option>';
        for($hour=0; $hour<=23; $hour++) {
            $hourOptions .= '<option value="'.$hour.'">'.sprintf("%02d", $hour).':00</option>';
        }
        return $hourOptions;
    }

}
