/home/coolpkct/www/websites/cake3.cool.rocks/admin/classes/themeset.php
<?php
/**
 * Part of SimpleViewer.net portfolio web site package.
 *
 * @package Showkase
 * @author Jack Hardie {@link http://www.jhardie.com}
 * @copyright Copyright (c) 2014, SimpleViewer Inc.
 */
defined('SK_ACCESS')||die('<h1>403: Forbidden</h1>');
require_once "classes".DIRECTORY_SEPARATOR."site.php";
require_once "classes".DIRECTORY_SEPARATOR."theme.php";
/**
  * Manages the set of themes
  *
  * @package Showkase
  */
class ThemeSet
{
    /**
     * @var string absolute path to current theme directory with trailing separator
     */
    private $themePath;
    
    /**
     * @var string absolute path to current parent directory with trailing separator. Empty for no parent.
     */
    private $parentPath = '';
    
    /**
     * @var array of all theme config data indexed by theme directory name
     */
    private $themeConfigData = array();
    
    /**
     * @var string current theme directory name
     */
    private $currentTheme;
    
    /**
     * @var string parent theme directory name
     */
    private $parentTheme = '';
    
    /**
     * @var string name of first exposed theme
     */
    private $defaultTheme = '';
    
    /**
     * @var array all showkase page types from plugins overriden by theme pagetypes.ini
     */
    private $allPageTypes = array();
  
    /**
     * constructor
     */
    public function __construct()
    {
        $this->config          = SkConfig::getInstance();
        $this->themeConfigData = $this->readThemeConfigData();
        $this->currentTheme    = $this->readCurrentThemeName();
        if (!isset($this->themeConfigData[$this->currentTheme])) {
            Board::addMessage('Cannot find theme directory, setting to first available theme', 'notice');
            $this->saveCurrentThemeName($this->currentTheme = $this->defaultTheme);
        }
        $this->themePath =
            $this->config->getThemesPath().DIRECTORY_SEPARATOR.
            $this->currentTheme.DIRECTORY_SEPARATOR;
        $this->parentTheme  = $this->themeConfigData[$this->currentTheme]['parent'];
        $this->parentPath   = $this->buildThemeParentPath();
        $this->allPageTypes = $this->getAllPageTypes();
    }
    
    /**
     * Read theme config data for all themes
     * @return array
     */
    private function readThemeConfigData()
    {
        $themeConfig = array();
	      $paths = glob($this->config->getThemesPath().DIRECTORY_SEPARATOR.'*');
        foreach ($paths as $path) {
            if (!is_dir($path)) continue;
            $themeDirectory = basename($path);
            $configData = @parse_ini_file($path.DIRECTORY_SEPARATOR.'config.ini', true);
            if (!is_array($configData)) throw new Exception('Cannot read theme config file for '.basename($path));
            $themeConfig[$themeDirectory]['displayName'] = isset($configData['displayName'])
                ? $configData['displayName']
                : $themeDirectory;
            $themeConfig[$themeDirectory]['description'] = isset($configData['description'])
                ? $configData['description']
                : 'No description available';
            $themeConfig[$themeDirectory]['version'] = isset($configData['version'])
                ? $configData['version']
                : '';
            $themeConfig[$themeDirectory]['parent'] = isset($configData['parent'])
                ? $configData['parent']
                : '';
            $themeConfig[$themeDirectory]['exposed'] =
                !isset($configData['exposed'])
                || strtolower($configData['exposed']) != 'false';
            $themeConfig[$themeDirectory]['devMode'] =
                isset($configData['devMode'])
                && strtolower($configData['devMode']) == 'true';
            if (
                $this->defaultTheme == ''
                && $themeConfig[$themeDirectory]['exposed']
            ) {
                $this->defaultTheme = $themeDirectory;
            }
        }
        if ($this->defaultTheme == '') throw new Exception('Cannot find any themes');
        return $themeConfig;
    }
    
    /**
     * Calculate theme parent path
     *
     * @return string
     */
    private function buildThemeParentPath()
    {
        if (empty($this->parentTheme)) return '';
        if (!isset($this->themeConfigData[$this->parentTheme])) {
		        Throw new Exception('Cannot find parent theme folder '.$this->parentTheme);
  	    }
  	    if (!empty($this->themeConfigData[$this->parentTheme]['parent'])) {
  	        Throw new Exception('Parent theme '.$this->parentTheme.' cannot be a child of another theme');
  	    }
  	    return
  	        $this->config->getThemesPath().DIRECTORY_SEPARATOR.
            $this->parentTheme.DIRECTORY_SEPARATOR;
    }
    
    /**
     * Scan plugins directory for available page types
     *
     * @return array
     */
    private function getAllPageTypes()
    {
        $parentPageTypes = array();
        $themePageTypes = array();
        $allPageTypes = array();
        if (!empty($this->parentTheme)) {
            $parentPageTypes = @parse_ini_file($this->parentPath.'pagetypes.ini', true);
            if ($parentPageTypes === false) {
                throw new Exception('Cannot read parent pagetypes.ini file in '.$this->parentTheme);
            }
        }     
        $themePageTypesIniPath = $this->themePath.'pagetypes.ini';
        if (file_exists($themePageTypesIniPath)) {
            $themePageTypes = @parse_ini_file($themePageTypesIniPath, true);
            if ($themePageTypes === false) throw new Exception('Cannot read theme pagetypes.ini file');
        }
        $themePageTypes = array_merge($parentPageTypes, $themePageTypes);
        $pluginConfigPaths = glob(PLUGINS_DIRECTORY.DIRECTORY_SEPARATOR.'*'.DIRECTORY_SEPARATOR.'config.ini');
        foreach ($pluginConfigPaths as $pluginConfigPath) {
            $plugin = basename(dirname($pluginConfigPath));
            $pluginConfig = @parse_ini_file($pluginConfigPath);
            if ($pluginConfig === false) {
                Board::addMessage('Cannot read plugin config file '.$pluginConfigPath, 'error');
                continue;
            }
            $allPageTypes[$plugin] = $pluginConfig;
            $allPageTypes[$plugin]['versionString'] = $this->readVersionString($plugin);
        }
        // preserve order of theme page types
        $union = $themePageTypes + $allPageTypes;
        foreach ($union as $pageType => &$pageTypeData) {
	          if (!isset($allPageTypes[$pageType])) {
		            Board::addMessage('Cannot find plugin for '.$pageType.' page type');
		            $pageTypeData['exposed'] = 'false';
		            continue;
	          }
	          if (isset($themePageTypes[$pageType])) {
		            $pageTypeData = array_merge($allPageTypes[$pageType], $themePageTypes[$pageType]);
	          }
	          $pageTypeData['exposed'] =
	              isset($pageTypeData['exposed'])
	              && strtolower($pageTypeData['exposed']) == 'true'
	                  ? 'true'
	                  : 'false';
        }
        return $union;
    }
    
    /**
     * get version string from source code
     *
     * @return string
     * @param string plugin name
     */
    private function readVersionString($plugin)
    {
        $haveVersions = array('juicebox', 'listviewer', 'simpleviewer');
        if (!in_array($plugin, $haveVersions)) return '';
        if ($plugin == 'listviewer') {
            return $allPageTypes[$plugin]['versionString'] = 'ListViewer '.SK_VERSION;
        }
        if ($plugin == 'juicebox') {
            $sourcePath =
                PLUGINS_DIRECTORY.DIRECTORY_SEPARATOR
                .'juicebox'.DIRECTORY_SEPARATOR
                .'master'.DIRECTORY_SEPARATOR.
                'jbcore'.DIRECTORY_SEPARATOR.
                'juicebox.js';
        }
        if ($plugin == 'simpleviewer') {
            $sourcePath =
                PLUGINS_DIRECTORY.DIRECTORY_SEPARATOR
                .'simpleviewer'.DIRECTORY_SEPARATOR
                .'master'.DIRECTORY_SEPARATOR
                .'svcore'.DIRECTORY_SEPARATOR
                .'js'.DIRECTORY_SEPARATOR
                .'simpleviewer.js';
        }
        if (!file_exists($sourcePath)) {
            Board::addMessage('Cannot find '.$plugin.' source file');
            return '';
        }
        $docBlock = file_get_contents($sourcePath, false, NULL, -1, 50);
        $docLines = preg_split("/\r\n|\n|\r/", $docBlock);
        if (!isset($docLines[1])) {
            Board::addMessage('Cannot extract version string from '.$plugin.' source code');
            return '';
        }
        return ltrim($docLines[1], ' *');
    }
    
    /**
     * get page type version string (empty for non-viewers)
     *
     * @return string
     * @param string page type
     */
    public function getVersionString($pageType)
    {
        return $this->allPageTypes[$pageType]['versionString'];
    }
    
    /**
     * get absolute theme path with trailing separator
     *
     * @return string
     */
    public function getThemePath()
    {
	      return $this->themePath;
    }
    
    /**
     * get absolute parent path with trailing separator
     *
     * @return string
     */
    public function getParentPath()
    {
	      return $this->parentPath;
    }
    
    /**
     * Get config data for all themes
     *
     * @return array
     */
    public function getThemeConfigData()
    {
        return $this->themeConfigData;
    }
    
    /**
     * get smarty force cache setting from theme config
     *
     * @return boolean
     */
    public function getDevMode()
    {
	      return $this->themeConfigData[$this->currentTheme]['devMode'];
    }
  
    /**
     * Get theme display name from directory name
     *
     * @return string
     */
    public function getThemeDisplayName($directoryName)
    {
        return htmlspecialchars($this->themeConfigData[$directoryName]['displayName'], ENT_QUOTES, 'UTF-8');
    }
  
    /**
     * get current theme name
     *
     * return string
     */
    public function getCurrentThemeName()
    {
        return $this->currentTheme;
    }
  
    /**
     * get theme overrides path
     *
     * @return string
     */
    public function getThemeOverridesPath()
    {
        return
            $this->config->getThemeDataPath().DIRECTORY_SEPARATOR.
            $this->currentTheme.DIRECTORY_SEPARATOR.
            'theme.xml';
    }
    
    /**
     * get viewer overrides path
     *
     * @param string
     * @return string
     */
    public function getViewerOverridesPath($pageType)
    {
        return
            $this->config->getThemeDataPath().DIRECTORY_SEPARATOR.
            $this->currentTheme.DIRECTORY_SEPARATOR.
            $pageType.'.xml';
    }
    /**
     * get absolute site.ini path
     *
     * @return string
     */
    /*
    public function getSiteIniPath()
    {   
        return $this->themePath.'site.ini';
    }
    */
    
    /**
     * get absolute site.ini paths
     *
     * @return array
     */
    public function getSiteIniPaths()
    {
        $paths = array('theme' => $this->themePath.'site.ini', 'parent' => '');
        if (!empty($this->parentTheme)) {
	          $paths['parent'] = $this->parentPath.'site.ini';
        }  
        return $paths;
    }
    
    /**
     * get absolute nav.ini path
     *
     * @return string
     */
    /*
    public function getNavIniPath()
    {   
        return $this->themePath.'nav.ini';
    }
    */
    
    /**
     * get absolute nav.ini paths
     *
     * @return array
     */
    public function getNavIniPaths()
    {
        $paths = array('theme' => $this->themePath.'nav.ini', 'parent' => '');
        if (!empty($this->parentTheme)) {
	          $paths['parent'] = $this->parentPath.'nav.ini';
        }  
        return $paths;
    }
 
    /**
     * get absolute theme.ini path
     *
     * @return string
     */
    /*
    public function getThemeIniPath()
    {   
        return $this->themePath.'theme.ini';
    }
    */
    
    /**
     * get absolute theme.ini path and parent theme ini path
     *
     * @return array
     */
    public function getThemeIniPaths()
    {
        $paths = array('theme' => $this->themePath.'theme.ini', 'parent'=>'');
        if (!empty($this->parentTheme)) {
	          $paths['parent'] = $this->parentPath.'theme.ini';
        }
        return $paths;
    }
  
    /**
     * get absolute page ini file path
     *
     * @return string
     * @param string
     */
    /*
    public function getPageIniPath($pageType)
    {
        return
            $this->themePath.
            THEME_PAGE_INI_DIRECTORY.DIRECTORY_SEPARATOR.
            $pageType.'.ini';
    }
    */
    
    /**
     * get absolute page ini path and parent page ini path
     *
     * @return array
     */
    public function getPageIniPaths($pageType)
    {
        $paths = array(
            'theme' =>
                $this->themePath.
                THEME_PAGE_INI_DIRECTORY.DIRECTORY_SEPARATOR.
                $pageType.'.ini',
            'parent' => ''
        );
        if (!empty ($this->parentTheme)) {
	          $paths['parent'] =
	              $this->parentPath.
	              THEME_PAGE_INI_DIRECTORY.DIRECTORY_SEPARATOR.
                $pageType.'.ini';
        }
        return $paths;
    }
    
    /**
     * get absolute viewer ini file path
     *
     * @return string
     * @param string
     */
    /*
    public function getViewerIniPath($pageType)
    {
        return
            $this->themePath.
            THEME_VIEWER_INI_DIRECTORY.DIRECTORY_SEPARATOR.
            $pageType.'.ini';
    }
    */
    
    /**
     * get absolute page ini path and parent page ini path
     *
     * @param string
     * @return array
     */
    public function getViewerIniPaths($pageType)
    {
        $paths = array(
            'theme' =>
                $this->themePath.
                THEME_VIEWER_INI_DIRECTORY.DIRECTORY_SEPARATOR.
                $pageType.'.ini',
            'parent' => ''
        );
        if (!empty ($this->parentTheme)) {
	          $paths['parent'] =
	              $this->parentPath.
	              THEME_VIEWER_INI_DIRECTORY.DIRECTORY_SEPARATOR.
                $pageType.'.ini';
        }
        return $paths;
    }
  
    /**
     * get current theme name
     *
     * @return string
     */
    public function readCurrentThemeName()
    {
        $path = $this->config->getSiteDataPath().DIRECTORY_SEPARATOR.CURRENT_THEME_FILE;
        if (file_exists($path)) {
            $theme = file_get_contents($path);
            if ($theme === false) {
                throw new Exception('Cannot read theme file '.CURRENT_THEME_FILE);
            }
        }
        else {
            $this->saveCurrentThemeName($theme = $this->defaultTheme);
            Board::addMessage('Current theme set to <i>'.$theme.'</i>', 'notice');
        }
        return $theme;
    }
  
    /**
     * update theme xml and save
     *
     * @param string theme name
     * @return boolean
     */
    public function saveCurrentThemeName($theme)
    {
        if (false === Filer::skPutContents($savePath = $this->config->getSiteDataPath().DIRECTORY_SEPARATOR.CURRENT_THEME_FILE, $theme, LOCK_EX)) {
            throw new Exception('Cannot save current theme to '.basename($savePath));
        }
        return true;
    }
  
    /**
     * return current page types data from settings pagetypes.ini
     *
     * @return array
     */
    public function getPageTypes()
    {
        return $this->allPageTypes;
    }
    
    /**
     * return unique viewer plugins
     *
     * @return page data array indexed by plugin type
     */
     public function getViewerPageTypes()
     {
         foreach ($this->allPageTypes as $pageType=>$pageTypeData) {
             if (empty($pageTypeData['category'])) continue;
             if ($pageTypeData['category'] != 'gallery') continue;
             if (empty($pageTypeData['exposed'])) continue;
             if ($pageTypeData['exposed'] != 'true') continue;
             $viewerTypes[$pageType] = $pageTypeData;
         }
         return $viewerTypes;
     }
  
}