<?php
/**
 * Libs_Template
 *
 * @access public
 */
abstract class Libs_Template {
     
    /**
     * Экземпляр реестра
     *
     * @access public
     * @var mixed
     */       
    public $reg;
     
    /**
     * Экземпляр контроллера шаблона
     *
     * @access protected
     * @var mixed
     */       
    protected $_controller;
     
    /**
     * Конфигурация подключаемых шаблонов
     *
     * @access protected
     * @var    array
     */
    protected $_config = array();
 
    /**
     * Путь к шаблону
     *
     * @access protected
     * @var    string
     */
    protected $_template_route = NULL;
     
    /**
     * Имя базового шаблона
     *
     * @access protected
     * @var    string
     */
    protected $_template_name = NULL;
         
    /**
     * CSS файлы страницы
     *
     * @access public
     * @var    array
     */
    protected $_css = array();
     
    /**
     * JavaScript файлы для вывода в шапке
     *
     * @access protected
     * @var    array
     */
    protected $_js_header = array();
 
    /**
     * JavaScript файлы для вывода в подвале
     *
     * @access protected
     * @var    array
     */
    protected $_js_footer = array();
     
    /**
     * Memcache
     *
     * @access public
     * @var    object
     */
    protected $_mc = NULL;
     
    /**
     * Заголовок страницы
     *
     * @access public
     * @var array
     */       
    public $title;   
     
    /**
     * Конструктор
     *
     * @access  public
     * @param   string
     * @return  string
     */       
    public function __construct($config) {
         
        $this->_config = $config;
         
        if ( CFG_CACHE_ENABLE ) {
            $this->_mc = Registry::get('Cache');
        }
    }
     
    /**
     * Запуск метода в контроллере шаблона
     *
     * @return  mixed
     */   
    public function __call($method, $args) {
         
        $this->_controller = Registry::get('TemplateController');
         
        return call_user_func_array(array($this->_controller, $method), $args);
    }
     
    /**
     * Вывод сфорированного шаблона
     *
     * @access  public
     * @param   string template_route
     * @param   array  data
     * @return  void
     */       
    public function display($template_route, $data = array()) {
         
        $this->_template_route = $template_route;
         
        // Установить имя базового шаблона, если не установлен
        if ( is_null($this->_template_name) ) {
            $this->_template_name = str_replace('.', '_', $template_route);
        }
         
        $config = $this->_getConfig();
         
        // Если конфиг найден
        if ( $config ) {
             
            $this->_prepareCss($config);
            $this->_prepareJs($config);
             
             
            // Подключение файлов шаблона
            foreach ( $this->_config['default']['tpl'] as $block=>$templates ) {
                 
                if ( isset($config['tpl'][$block]) ) {
                    $templates = $config['tpl'][$block];
                }
                 
                foreach ($templates as $template) {
                    if ( $template ) {
                        $this->_fetch($template, $data);
                    }
                }
            }
             
        } else {
            echo 'Шаблон '.$template_route.' не подключен';
        }
    }
     
    /**
     * Подготовка CSS
     *
     * @access  private
     * @param   string config
     * @return  void
     */           
    private function _prepareCss($config) {
         
        // Создание дефолтных стилей
        if ( !empty($this->_config['default']['css']) && empty($this->_css) ) {
            foreach ( $this->_config['default']['css'] as $key=>$val ) {
                $this->_makeCss($key, $val);
            }
        }
         
        // Создание стилей шаблона
        if ( isset($config['css']) ) {
            foreach ( $config['css'] as $key=>$val ) {
                $this->_makeCss($key, $val);
            }
        }
    }
     
    /**
     * Подготовка JavaScript
     *
     * @access  private
     * @param   string config
     * @return  void
     */           
    private function _prepareJs($config) {
         
        // Создание дефолтных JavaScript
        if ( !empty($this->_config['default']['js-header']) && empty($this->_js_header) ) {
            foreach ($this->_config['default']['js-header'] as $key=>$val ) {
                $this->_makeJs($key, $val, 'header');
            }
        }
        if ( !empty($this->_config['default']['js-footer']) && empty($this->_js_footer) ) {
            foreach ($this->_config['default']['js-footer'] as $key=>$val ) {
                $this->_makeJs($key, $val, 'footer');
            }
        }
         
        // Создание JavaScript шаблона
        if ( isset($config['js-header']) ) {
            foreach ( $config['js-header'] as $key=>$val ) {
                $this->_makeJs($key, $val, 'header');
            }
        }
         
        if ( isset($config['js-footer']) ) {
            foreach ( $config['js-footer'] as $key=>$val ) {
                $this->_makeJs($key, $val, 'footer');
            }           
        }
    }
     
    /**
     * Подключение шаблона по пути и возврат готового HTML
     *
     * @access public
     * @param  string module
     * @param  string template
     * @param  array data
     * @return string
     */
    public function fetch($template_path, $data = array()) {
        $returnValue = (string) '';
 
        ob_start();
        $this->_fetch($template_path, $data);
        $returnValue = ob_get_contents();
        ob_end_clean();
         
        return (string) $returnValue;
    }
     
    /**
     * Подключение шаблона по пути и подстановка данных
     *
     * @access  public
     * @param   string template_path
     * @param   array data
     * @return  void
     */       
    public function get($template_path, $data = array()) {
        $this->_fetch($template_path, $data);
    }
 
    /**
     * Получение конфига нужного шаблона
     *
     * @access  protected
     * @return  array
     */       
    protected function _getConfig() {
 
        $config = array();
         
        $template_route_parts = explode('.', $this->_template_route);
        // Если задан конфиг для начального шаблона
        if (!empty($this->_config[$template_route_parts[0]])) {
             
            $config = $this->_config[$template_route_parts[0]];
             
            // Если это дочерний шаблон
            if ( $template_route_parts > 1 ) {
                for ($ii=1; $ii<count($template_route_parts); $ii++) {
                    if ( !empty($config['children'][$template_route_parts[$ii]]) ) {
                        $config = $config['children'][$template_route_parts[$ii]];
                    } else {
                        $config = array();
                        break;
                    }
                }
            }
        }
         
        return $config;
    }
     
    /**
     * Подстановка данных в шаблон
     *
     * @access protected
     * @return void
     */
    protected function _fetch($_template, $_data) {
         
        extract($_data);
         
        if ( is_file(CFG_TEMPLATES_PATH . '/' . $_template) ) {
            include( CFG_TEMPLATES_PATH . '/' . $_template );
        } else {
            echo 'Файл шаблона "'.CFG_TEMPLATES_PATH . '/' . $_template. '" не найден'."\r\n";
        }
    }   
     
    /**
     * Операции перед выводом на экран
     *
     * @access protected
     * @return void
     */
    public function callback($buffer) {
         
        $buffer = $this->_replaceCss($buffer);
        $buffer = $this->_replaceJs($buffer);
        $buffer = $this->_replaceImage($buffer);
        $buffer = $this->_replaceService($buffer);
        $buffer = $this->_replaceFreetext($buffer);
         
        if ( defined('CFG_SEO_ENABLE') && CFG_SEO_ENABLE ) {
             
            if ( Seo::get('title') ) {
                $buffer = preg_replace('/<title>.*<\/title>/i', '<title>'.Seo::get('title').'</title>', $buffer);
            }
            if ( Seo::get('description') ) {
                $buffer = str_replace("<!--SEO_CONTENT-->", Seo::get('description'), $buffer);
            }
        }
         
        return trim($buffer);
    }
     
    /**
     * Замена <!--#CSS#--> подключения CSS
     *
     * @access protected
     * @return string
     */
    protected function _replaceCss($content) {
         
        if ( $this->_css ) {
            $content = str_replace("<!--CSS-->", implode("\r\n", $this->_css), $content);
        }
 
        if ( defined('CFG_CSS_URL') ) {
            $content = str_replace("<!--CSS-URL-->", CFG_CSS_URL, $content);
        }
         
        return $content;
    }
     
    /**
     * Вывод HTML-тегов подключения JavaScript
     *
     * @access protected
     * @return string
     */
    protected function _replaceJs($content) {
         
        if ( $this->_js_header ) {
            $content = str_replace("<!--JS-HEADER-->", implode("\r\n", $this->_js_header), $content);
        }
         
        if ( $this->_js_footer ) {
            $content = str_replace("<!--JS-FOOTER-->", implode("\r\n", $this->_js_footer), $content);
        }
 
        if ( defined('CFG_JS_URL') ) {
            $content = str_replace("<!--JS-URL-->", CFG_JS_URL, $content);
        }
         
        return $content;
    }
     
    /**
     * Вывод URL подключения images
     *
     * @access protected
     * @return string
     */
    protected function _replaceImage($content) {
 
        if ( defined('CFG_IMAGE_URL') ) {
            $content = str_replace("<!--IMAGE-URL-->", CFG_IMAGE_URL, $content);
        }
         
        return $content;
    }
     
    /**
     * Вывод URL подключения к сервисам
     *
     * @access protected
     * @return string
     */
    protected function _replaceService($content) {
 
        if ( defined('CFG_SERVICE_ESTATE') ) {
            $content = str_replace("<!--SERVICE-ESTATE-->", CFG_SERVICE_ESTATE, $content);
        }
 
        if ( defined('CFG_SERVICE_NEWS') ) {
            $content = str_replace("<!--SERVICE-NEWS-->", CFG_SERVICE_NEWS, $content);
        }
 
        if ( defined('CFG_SERVICE_OFFICES') ) {
            $content = str_replace("<!--SERVICE-OFFICES-->", CFG_SERVICE_OFFICES, $content);
        }
 
        if ( defined('CFG_SERVICE_DISCOUNT') ) {
            $content = str_replace("<!--SERVICE-DISCOUNT-->", CFG_SERVICE_DISCOUNT, $content);
        }
 
        if ( defined('CFG_SERVICE_IPOTEKA') ) {
            $content = str_replace("<!--SERVICE-IPOTEKA-->", CFG_SERVICE_IPOTEKA, $content);
        }
 
        if ( defined('CFG_SERVICE_BANNERS') ) {
            $content = str_replace("<!--SERVICE-BANNERS-->", CFG_SERVICE_BANNERS, $content);
        }
         
        return $content;
    }
     
    /**
     * Вывод URL подключения к сервисам
     *
     * @access protected
     * @return string
     */
    protected function _replaceFreetext($content) {
 
        if ( defined('CFG_FREETEXT') ) {
            $content = str_replace("<!--FREE-TEXT-->", CFG_FREETEXT, $content);
        }
         
        return $content;
    }
     
    /**
     * Генерация CSS файлов
     *
     * @access protected
     * @param  string fileName
     * @param  array cssList
     */
    protected function _makeCss($fileName, $cssList) {
         
        $realFilePath = $this->_getFileName($fileName, 'css', $cssList);
         
        if ( $realFilePath ) {
            $realFilePath = CFG_CSS_URL . $this->_getFileName($fileName, 'css', $cssList);
             
            if ( preg_match('/ie-(?P<pref>.+)?(?P<num>[0-9])/i', $realFilePath, $matches) ) {
                $css  = '<!--[if '. (isset($matches['pref']) ? $matches['pref'].' ' : '' ) .'IE '.$matches['num'].']>'."\r\n";
                $css .= '<link rel="stylesheet" type="text/css" href="'.$realFilePath."\" />\r\n";
                $css .= '<![endif]-->';
            } elseif ( preg_match('/media-(?P<media>.+).css?/i', $realFilePath, $matches) ) {
                $css = '<link rel="stylesheet" type="text/css" href="'.$realFilePath.'" media="'. $matches['media'].'" />';
            } else {
                $css = '<link rel="stylesheet" type="text/css" href="'.$realFilePath."\" />";
            }
             
            $this->_css[] = $css;
        }
    }
 
    /**
     * Генерация JavaScript файлов
     *
     * @access protected
     * @param  string fileName
     * @param  array jsList
     */
    protected function _makeJs($fileName, $jsList, $location) {
         
        $realFilePath = $this->_getFileName($fileName, 'js', $jsList);
 
        if ( $realFilePath ) {
            $realFilePath = CFG_JS_URL . $this->_getFileName($fileName, 'js', $jsList);
             
            $js = '<script type="text/javascript" src="' . $realFilePath . "\"></script>";
             
            if ( $location == "header" ) {
                $this->_js_header[]= $js;
            } else {
                $this->_js_footer[]= $js;
            }
        }
    }
     
    /**
     * Создание файла
     *
     * @access protected
     * @param  string fileName
     * @param  string fileType
     * @param  array fileList
     * @return string
     */
    private function _getFileName($fileName, $fileType, $fileList) {
         
        $returnValue = '';
         
        if ( CFG_TPL_CACHE_ENABLE && $this->_mc ) {
            $returnValue = $this->_mc->get('TPL_CACHE_'.$fileName.$fileType);
        }
 
        if ( empty($returnValue) ) {
            if ( !CFG_TPL_CACHE_ENABLE ) {
                $returnValue = $this->_makeFile($fileName, $fileType, $fileList);
            } else {
                $files = scandir(CFG_APP_PATH . '/' . $fileType . '/');
                 
                for ($ii=0; $ii<count($files); $ii++) {
                    if ( preg_match('/^' . $fileName . '_(.+)\.' . $fileType . '/', $files[$ii]) ) {
                        $returnValue = $fileType . '/' . $files[$ii];
                        break;
                    }
                }
                 
                if ( empty($returnValue) ) {
                    $returnValue = $this->_makeFile($fileName, $fileType, $fileList);
                }
            }
        }
         
        if ( !empty($returnValue) && CFG_TPL_CACHE_ENABLE && $this->_mc ) {
            $this->_mc->set('TPL_CACHE_'.$fileName.$fileType, $returnValue);
        }
         
        return (string) $returnValue;
    }
     
    private function _makeFile($fileName, $fileType, $fileList) {
        $returnValue = '';
        $contents    = array();
        $dir_path_app= CFG_APP_PATH . '/' . $fileType . '/';
        $dir_path_pub= CFG_PUBLIC_PATH . '/' . $fileType . '/';
         
        foreach ( $fileList as $file ) {
             
            $file_path = $dir_path_app . $file;
             
            if ( is_file($file_path) ) {
                 
                $handle    = fopen($file_path, "r");
                $contents[]= fread($handle, filesize($file_path));
                fclose($handle);
 
            }               
        }
 
        if ( $contents ) {
            $contents = implode("\r\n", $contents);
            $md5      = md5($contents);
            $handle   = fopen($dir_path_pub . $fileName . '_' . $md5 . '.' . $fileType, "w+");
 
            if ($handle) {
                fwrite($handle, $contents);
                fclose($handle);
 
                $returnValue = $fileType . '/' . $fileName . '_' . $md5 . '.' . $fileType;
            }
        }
        return (string) $returnValue;
    }
 
     
    /**
     * Получение имени шаблона
     *
     * @access public
     * @return string
     */
    public function getTemplateName() {
        return $this->_template_name;
    }
 
    public function formatRuDate($date) {
        $date = intval($date);
        $months = array(
            1  => 'января',
            2  => 'февраля',
            3  => 'марта',
            4  => 'апреля',
            5  => 'мая',
            6  => 'июня',
            7  => 'июля',
            8  => 'августа',
            9  => 'сентября',
            10 => 'октября',
            11 => 'ноября',
            12 => 'декабря'
        );
 
        return date('d', $date).' '.$months[date('n', $date)].' '.date('Y', $date);
    }
     
    /**
     * Функция возвращает окончание для множественного числа слова на основании числа и массива окончаний
     * @param $number Integer Число на основе которого нужно сформировать окончание
     * @param $endingsArray Array Массив слов или окончаний для чисел (1, 4, 5),
     * например array('яблоко', 'яблока', 'яблок')
     * @return String
     */
    function getNumEnding($number, $endingArray) {
        $number = $number % 100;
        if ( $number>=11 && $number<=19 ) {
            $ending = $endingArray[2];
        } else {
            $i = $number % 10;
            switch ($i) {
                case (1): $ending = $endingArray[0]; break;
                case (2):
                case (3):
                case (4): $ending = $endingArray[1]; break;
                default:  $ending = $endingArray[2];
            }
        }
        return $ending;
    }
 
    /**
     * Получение баннеров
     *
     * @access public    
     * @param массив с зонами ('zone1_', 'zone2_')
     * @return array массив данных баннеров
     */
    public function getBanners($zones, $bnCount=1) {
         
        $returnValue  = array();
        $requestZones = array();
        $tempZones = array();
 
        foreach ($zones as $zone) {
 
            $cacheZone = $this->_mc->get('banner_' . $zone);
 
            if ( empty($cacheZone) ) {
                $requestZones[] = $zone;
            } else {
                $cnt = count($cacheZone) < $bnCount ? count($cacheZone) : $bnCount;
                $tempZones[$zone] = $this->setTempBanners($cacheZone, array_rand($cacheZone, $cnt));
            }
         
        }
 
        if ( !empty($requestZones) ) {
 
            $zoneString = implode('^', $requestZones);
            $bannersData = Http::factory(CFG_SERVICE_BANNERS.'?tags=' . $zoneString)->sendRequest()->getResponse('json');
 
            if ( !empty($bannersData) ) {
 
                foreach ($bannersData as $key => $value) {
                    $cnt = count($value) < $bnCount ? count($value) : $bnCount;
                    $tempZones[$key] = $this->setTempBanners($value, array_rand($value, $cnt));
                    $this->_mc->set('banner_' . $key, $value, CFG_BANNER_CACHE_TIME);
 
                }
             
            }          
         
        }
 
        //Сортируем в нужном порядке
        foreach ($zones as $zone) {
            $returnValue[$zone] = !empty($tempZones[$zone]) ? $tempZones[$zone] : array();
        }
         
        return $returnValue;
    }
     
    private function setTempBanners($banners, $keys) {
        $returnValue = array();
         
        if ( count($keys) > 1 ) {
            for ($ii=0; $ii<count($keys); $ii++) {
                $returnValue[]= $banners[$keys[$ii]];
            }
        } else {
            $returnValue[] = $banners[$keys];
        }
         
        return $returnValue;
    }
 
    /**
     * Формат даты для RSS канала
     *
     * @return string
    */
    public function formatRSSDate($date) {
        $date = intval($date);
        return date('r', $date);
    }
 
    /**
     * Получение ссылки на уменьшенный вариант картинки
     *
     * @return string
    */
    public function getResizeImagePath($url, $num) {
        $image_sizes = require(CFG_APP_PATH . "/config/image_sizes.php");
        $file_path   = explode('.', $url);
        $extension   = $file_path[sizeof($file_path) - 1];
         
        unset($file_path[sizeof($file_path) - 1]);
         
        $file_path   = implode('.', $file_path);
        $returnValue = $file_path . '_' . $image_sizes[$num] . '.' . $extension;
         
        return $returnValue;
    }
 
    /**
     * Вывод информации в зависимости от формата
     *
     * @param  array $data Набор данных для отображения пользователю
     * @param  string $template Путь к шаблону, требуется если формат вывода не JSON
     * @return void
     */
    public function getByFormat($data, $template=array(), $encoding='utf8') {
         
        $request = Registry::get('Request');
        $format  = $request->getQuery('format');
        $download= $request->getQuery('download');
        $render  = '';
 
        $this->_setHTTPHeaders($encoding, $format, $download);
 
        switch ($format) {
            case 'csv':
 
                print $data;
                break;
 
            case 'xml':
 
                if ( !empty($template['xml']) ) {
 
                    $render = $this->fetch($template['xml'], array('data'=> $data));
                }
 
                break;
 
            case 'json':
            default:
 
                $render = Json::encode($data, false);
                break;
 
        }
 
        print $this->_encode($render, $encoding);
 
    }
 
    private function _setHTTPHeaders($encoding='utf-8', $format='json', $download=FALSE){
 
        switch ($encoding) {
            case 'utf-8':
            case 'utf8':
                $encoding = 'UTF-8';
                break;
            case 'win':
            default:
                $encoding = 'Windows-1251';
        }
 
        switch ($format) {
            case 'xml':
                $content_type = 'text/xml';
                break;
            case 'csv':
                $content_type = 'text/csv';
                break;
            case 'json':
            default:
                $content_type = 'application/json';
                break;
        }
 
        header('Content-Type: '. $content_type .'; charset=' . $encoding . '');
 
        if ( strtolower($download) == 'true' ) {
            $filename = CFG_APP_NAME .'-'. date('Y-m-d_H-i-s') . '.'. $format;
            header('Expires: 0');
            header('Cache-Control: must-revalidate');
            header('Content-Description: File Transfer');
            header('Content-Type: application/'. $format);
            header('Content-Disposition: attachment; filename="' . $filename . '"');
        }
 
    }
 
    private function _encode($output, $encoding='utf8'){
 
        switch ($encoding) {
            case 'utf8':
                 
                break;
            case 'win':
            default:
                $output = iconv('UTF-8', 'cp1251', $output);
        }
 
        return $output;
    }
}
?>