/home/coolpkct/www/websites/cake3.cool.rocks/admin/classes/pageset.php
<?php
/**
 * Part of Showkase web site management package
 *
 * @package Showkase
 * @author Jack Hardie {@link http://www.jhardie.com}
 * @copyright Copyright (c) 2012, SimpleViewer Inc.
 */
defined('SK_ACCESS')||die('<h1>403: Forbidden</h1>');
require_once 'classes'.DIRECTORY_SEPARATOR.'themeset.php';
require_once 'classes'.DIRECTORY_SEPARATOR.'helpers.php';
/**
 * PageSet class
 *
 * @access public
 * @package Showkase
 */
Class PageSet
{
    /**
     * @var array page names and paths
     * Note that 'path' is relative to the showkase admin directory and is really a path (backslashes on Windows)
     * The array index is arbitrary and will change on sort
     * As the user deletes pages, gaps will appear in the sequence of page refs.
     */
    public $pagesData = array(
      'pageRef'   =>1,
      'path'      =>'',
      'pageType'  =>'unknown',
      'navWeight' =>1,
      'navName'   =>'noname',
      'navShow'   =>'true',
      'supported' =>'true',
      'indexShow' =>'true',
      'parentPage'=>0,
      'isGallery' =>false
    );
  
    /**
     * @var string path from server root to pages data file
     *
     */
    private $pagesDataFile;
  
    /**
     * @var array preferences for all pages
     * 
     */
    private $pagesPrefs = array(
      'showPro'              => false,
      'uploaderRuntime'      => UPLOADER_RUNTIME,
      'publishing'           => 'published',
      'galleryImageResize'   => GALLERY_RESIZE_DEFAULT,
      'libraryImageResize'   => LIBRARY_RESIZE_DEFAULT,
      'galleryMaxImageWidth' => GALLERY_DEFAULT_IMAGE_WIDTH,
      'galleryMaxImageHeight'=> GALLERY_DEFAULT_IMAGE_HEIGHT,
      'libraryMaxImageWidth' => LIBRARY_DEFAULT_IMAGE_WIDTH,
      'libraryMaxImageHeight'=> LIBRARY_DEFAULT_IMAGE_HEIGHT,
      'galleryResizeQuality' => GALLERY_DEFAULT_RESIZE_QUALITY,
      'libraryResizeQuality' => LIBRARY_DEFAULT_RESIZE_QUALITY,
    );
    /**
     * @var object instance of PathParser class
     */
    private $pathParser;
  
    /**
     * Constructs
     */
    public function __construct()
    {
        $this->config = SkConfig::getInstance();
        $this->pathParser = new PathParser();
        $this->pagesDataFile = $this->config->getPagesDataPath();
        $pagesData = $this->readPagesData();
        $this->pagesData = $pagesData;
        $pagesPrefs = $this->readPagesPrefs();
        if ($pagesPrefs !== false) {
            $this->pagesPrefs = array_merge($this->pagesPrefs, $pagesPrefs);
        }
    }
  
    /**
     * Read page data from file
     *
     * Note that there is no error message for missing page data file - normal condition on install
     * @access private
     * @return array
     */
    private function readPagesData()
    {
        if (!file_exists($this->pagesDataFile)) return array();
        $pagesData = @file_get_contents($this->pagesDataFile);
        if ($pagesData === false) {
            Board::addMessage('Cannot read pages data file '.basename($this->pagesDataFile), 'warning');
            return array();
        }
        $data = @unserialize($pagesData);
        if ($data === false) {
            Board::addMessage('Page database needs <a href="index.php?cmd=repair">repair</a>', 'warning');
            return array();
        }
        return $data;    
    }
  
    /**
     * Reset $this-pagesData to an empty array
     */
    public function wipe()
    {
        $this->pagesData = array();
    }
  
    /**
     * Read pages preferences file
     *
     * @return array
     */
    public function readPagesPrefs()
    {
        if (!file_exists($this->config->getPagesPrefsPath())) return false;
        $pagesPrefs = @file_get_contents($this->config->getPagesPrefsPath());
        if ($pagesPrefs === false) return false;
        $data = @unserialize($pagesPrefs);
        if ($data === false) return false;
        return $data;
    }
 
    /**
     * returns page data
     *
     * @return array
     */
    public function getPagesData() {
        return $this->pagesData;
    }
  
    /**
     * Checks if page exists in pagesdata
     *
     * @param integer page index
     * @return boolean
     */
    public function pageExists($key)
    {
        return isset($this->pagesData[$key]); 
    }
  
    /** returns page valid current page index
     *
     * @return string
     * @param string page index
     */
    public function getCurrentPageIndex(Request $request)
    {
        $pageIndexRequest = $request->getProperty('pageIndex');
        $message = 'No current page, go to <a href="index.php?cmd=showpages">pages screen</a> and select an existing page or create a new one';
        switch (true) {
              case (!is_null($pageIndexRequest) && !$this->pageExists($pageIndexRequest)) :
                  throw new Exception($message);
                  break;
              case (!is_null($pageIndexRequest)) :
                  $pageIndex = $pageIndexRequest;
                  break;
              case (isset($_SESSION['pageIndex']) && $this->pageExists($_SESSION['pageIndex'])) :
                  $pageIndex = $_SESSION['pageIndex'];
                  break;
              default :
                  throw new Exception('No current page, go to <a href="index.php?cmd=showpages">pages screen</a> and select an existing page or create a new one');
        }
        return $pageIndex;
    }
  
    /** returns page reference
     *
     * @return string
     * @param string page index
     */
    public function getPageRef($pageIndex)
    {
      if (!isset($this->pagesData[$pageIndex])) {
          throw new Exception('There is no page index '.$pageIndex);
      }
      if (!isset($this->pagesData[$pageIndex]['pageRef'])) {
          throw new Exception('Cannot get page reference for page '.$key);
      }
      return $this->pagesData[$pageIndex]['pageRef'];
    }
  
    /** returns page path (backslashes in Windows)
     *
     * @return string
     * @param string page reference
     */
    public function getPagePath($key)
    {
      if (!isset($this->pagesData[$key])) {
          throw new Exception('There is no page index '.$key);
      }
      if (!isset($this->pagesData[$key]['path'])) {
          throw new Exception('Cannot get path for page '.$key);
      }
      return $this->pagesData[$key]['path'];
    }
  
    /** returns page type
     *
     * @return string
     * @param string page reference
     */
    public function getPageType($key)
    {
      if (!isset($this->pagesData[$key])) {
          throw new Exception('There is no page ref '.$key);
      }
      if (!isset($this->pagesData[$key]['pageType'])) {
          throw new Exception('Cannot get page type for page '.$key);
      }
      return $this->pagesData[$key]['pageType'];
    }
  
    /** 
     * set page type
     *
     * @return void
     * @param string page reference
     * @param string new value
     */
    public function setPageType($key, $value)
    {
        $this->pagesData[$key]['pageType'] = $value;
    }   
  
    /**
     * Set page data path
     * @param integer page index
     * @param string path
     */
    public function setPagePath($key, $path)
    {
        $this->pagesData[$key]['path'] = $path;
    }
  
    /**
     * returns pages prefs
     *
     * @return array
     */
    public function getPagesPrefs()
    {
      return $this->pagesPrefs;
    }
    
    /**
     * returns single pages pref
     *
     * @param string name
     * @return array
     */
    public function getPagesPref($pref)
    {
      return $this->pagesPrefs[$pref];
    }
  
    /**
     * Sets pagesPref
     *
     * @return void
     * @param string preference key
     * @param mixed new setting
     */
    public function setPagesPref($pref, $setting)
    {
        $this->pagesPrefs[$pref] = $setting;
    }
    
    /**
     * Toggle show pro viewers state
     *
     * @return void
     */
     public function togglePro()
     {
         $this->pagesPrefs['showPro'] = !$this->pagesPrefs['showPro'];
     }
    
    /**
     * add new data record
     *
     * @access public
     * @return integer index in pagesData array
     * @param object page
     */
    public function addPagesDataRecord(Page $page)
    {
        $supported = $page->isSupportedPageType() ? 'true' : 'false';
        $this->pagesData[] = array(
            'pageRef'=>$page->getRef(),
            'path'=>$page->getPagePathRelSvm(),
            'pageType'=>$page->getPageType(),
            'navWeight'=>$page->getNavWeight(),
            'navName'=>$page->getNavName(),
            'navShow'=>$page->getNavShow(),
            'supported'=>$supported,
            'indexShow'=>$page->getIndexShow(),
            'parentPage'=>$page->getParentPage(),
            'isGallery'=>isset($page->gallery)
        );
        //store result in variable to prevent E_STRICT warning
        $keys = array_keys($this->pagesData);
        return array_pop($keys);
    }
  
    /**
     * get index corresponding to page ref
     * note that 0 is a valid return
     *
     * @return integer
     * @param integer page ref or false if ref does not exist
     */
    public function getPageIndex($pageRef)
    {
        $inverse = array();
        foreach ($this->pagesData as $index=>$data) {
            $inverse[$data['pageRef']] = $index;
        }
        return isset($inverse[$pageRef])
            ? $inverse[$pageRef]
            : false;
    }
  
    /**
     * set pagesData['parentPage']
     *
     * @return void
     * @param string page index
     * @param integer index page ref
     */
    public function setPagesDataParentPage($index, $pageIndex)
    {
        $this->pagesData[$index]['parentPage'] = $pageIndex;
    }
  
    /**
     * set pagesData['navName']
     *
     * @return void
     * @param string page index
     * @param string nav name
     */
    public function setPagesDataNavName($index, $navName)
    {
        $this->pagesData[$index]['navName'] = $navName;
    }
  
    /**
     * set pagesData['navShow']
     *
     * @return void
     * @param string page index
     * @param string true/false
     */
    function setPagesDataNavShow($index, $show)
    {
        $this->pagesData[$index]['navShow'] = $show;
    }
    
    /**
     * set pagesData['supported']
     *
     * @return void
     * @param string page index
     * @param string true/false
     */
    function setPagesDataSupported($index, $supported)
    {
        $this->pagesData[$index]['supported'] = $supported;
    }
  
    /**
     * set pagesData['indexShow']
     *
     * @return void
     * @param string page index
     * @param string true/false
     */
    public function setPagesDataIndexShow($index, $show)
    {
        $this->pagesData[$index]['indexShow'] = $show;
    }
  
    /**
     * set pagesData['navWeight']
     *
     * @return void
     * @param string page index
     * @param real nav weight
     */
    public function setPagesDataNavWeight($index, $navWeight)
    {
        $this->pagesData[$index]['navWeight'] = $navWeight;
    }
  
    /**
     * set pagesData['isGallery']
     *
     * @return void
     * @param string page index
     * @param boolean is gallery page
     */
    function setPagesDataIsGallery($index, $isGallery)
    {
        $this->pagesData[$index]['isGallery'] = $isGallery;
    }
  
    /* save page data to file
     *
     * @access public
     * @return void
     */
    public function savePagesData()
    {
        if (false === Filer::skPutContents($this->pagesDataFile, serialize($this->pagesData), LOCK_EX)) {
            throw new Exception('Cannot save pages data to '.basename($this->pagesDataFile));
        }
    }
  
    /* save pages preferences to file
     *
     * @access public
     * @return boolean success
     */
    public function savePagesPrefs()
    {
        if (false === Filer::skPutContents($this->config->getPagesPrefsPath(), serialize($this->pagesPrefs), LOCK_EX)) {
          throw new Exception('Cannot save pages prefs to '.basename($this->config->getPagesPrefsPath()).'. Check permissions on this file and parent folders.');
        }
    }
  
    /**
     * Find next available page reference number
     *
     * @return integer page reference number
     */
    public function nextPageRef()
    {
        $nextRef = 1;
        if (count($this->pagesData) > 0) {
            foreach ($this->pagesData as $key=>$page) {
                $ref[$key] = $page['pageRef'];
            }
            $nextRef = 1 + max($ref);
        }
        return $nextRef;
    }
    /**
     * Remove page from the database without deleting it
     *
     * @return void
     * @param integer key to page in pagesData
     */
    public function removePage($key)
    {
        if (!isset($this->pagesData[$key])) {
            Board::addMessage('Could not find a page to remove.', 'warning');
            return;
        }
        Filer::skUnlink(
            $this->config->getThumbCachePath().DIRECTORY_SEPARATOR.
            INDEX_THUMB_PREFIX.
            $this->pagesData[$key]['pageRef'].
            '.jpg'
            );
        if (!Filer::rChmod($this->pagesData[$key]['path'], TRASH_DIR_MODE, TRASH_FILE_MODE)) {
            Board::addMessage('Cannot change folder and file permissions.', 'warning');
        }
        $oldDir = rtrim($this->pagesData[$key]['path'], '\\/');
        $newDir =
            dirname($oldDir).DIRECTORY_SEPARATOR.
            $this->config->getTrashDirectoryName().DIRECTORY_SEPARATOR.
            basename($oldDir).
            '-'.time();
        unset($this->pagesData[$key]);
        if (!Filer::skRename($oldDir, $newDir)){
            Board::addMessage('Cannot move page to trash.', 'warning');
        }
        return;
    }
  
    /**
     * Check if pages refer to deleted parents and reset parent to zero
     *
     * @return void
     */
    public function removeDeletedParents(PageFactory $pageFactory, ThemeSet $themeSet)
    {
        $pageRefs = array();
        foreach ($this->pagesData as $pageData) {
            $pageRefs[] = $pageData['pageRef'];
        }
        unset($pageData);
        foreach ($this->pagesData as $key=>$pageData) {
            if ($pageData['parentPage'] == 0) continue;
            if (!in_array($pageData['parentPage'], $pageRefs)) {
                $this->pagesData[$key]['parentPage'] = 0;
                $tempPage = $pageFactory->make($pageData['pageType'], $pageData['pageRef'], $pageData['path']);
                $tempPage->setParentPage(0);
                $tempPage->saveLayer();
            }
        }
    }
    
    /**
     * Set supported to false for non-supported page types
     *
     * @return void
     * @param array of page types with theme exposed setting
     */
    public function hideUnsupportedPageTypes(array $pageTypes)
    {
        $allSupported = true;
        $unsupported = array();
        foreach ($this->pagesData as &$pageData) {
            if (
                isset($pageTypes[$pageData['pageType']]['exposed'])
                && $pageTypes[$pageData['pageType']]['exposed'] == 'true'
            ) {
                $pageData['supported'] = 'true';
            } else {
                $pageData['supported'] = 'false';
                $unsupported[] = ucfirst($pageData['pageType']);
                $allSupported = false;
            }
        }
        if (!$allSupported) {
            $unsupported = array_unique($unsupported);
            $isAre = ' page type is ';
            if (count($unsupported) > 1) {
                $last = array_pop($unsupported);
                $isAre = ' and '.$last.' page types are ';
            }
            Board::addMessage(implode(', ', $unsupported).$isAre.' not supported in this theme. Unsupported page types will not show in the published website.', 'notice');
        }
    }
    
    /**
     * Get first (non-link) page url
     *
     * @return string absolute home page url or empty if no home page
     */
    public function getHomeUrl()
    {
        $weights = array();
        $pagesData = $this->pagesData;
        foreach ($pagesData as $pageData) {
            $weights[] = isset($pageData['navWeight']) ? $pageData['navWeight'] : 0;
        }
        unset($pageData);
        array_multisort($weights, $pagesData);
        $homePath = '';
        foreach ($pagesData as $pageData) {
            if ($pageData['pageType'] == 'link') continue;
            if (isset($pageData['parentPage']) && $pageData['parentPage'] != '0') continue;
            $homePath = $pageData['path'];
            break;
        }
        if ($homePath == '') return '';
        $contentPath =  rtrim($this->config->getDocRootRelativeContentPath(), '\\/');
        $homePath = basename(rtrim($homePath,'\\/')).'/index.html';
        return str_replace(array('\\', '/'), '/', $contentPath.'/'.$homePath);
    }
}