<?php
/**
 * @copyright 2008-2017 Horde LLC (http://www.horde.org)
 * @author Michael J Rubinsky <mrubinsk@horde.org>
 * @category Horde
 * @license  http://www.horde.org/licenses/gpl GPL
 * @package  Ansel
 */
/**
 * Ansel_View_GalleryRenderer::  Base class for all gallery renderers.
 *
 * Copyright 2008-2017 Horde LLC (http://www.horde.org/)
 *
 * See the enclosed file COPYING for license information (GPL). If you
 * did not receive this file, see http://www.horde.org/licenses/gpl.
 *
 * @copyright 2008-2017 Horde LLC (http://www.horde.org)
 * @author Michael J Rubinsky <mrubinsk@horde.org>
 * @category Horde
 * @license  http://www.horde.org/licenses/gpl GPL
 * @package  Ansel
 */
abstract class Ansel_View_GalleryRenderer_Base
{
    /**
     * The Ansel_View_Gallery object that this Renderer belongs to.
     *
     * @var Ansel_View_Gallery
     */
    public $view;

    /**
     * The gallery id for this view's gallery
     * (Convenience instead of $this->view->gallery->id)
     *
     * @var integer
     */
    public $galleryId;

    /**
     * Gallery slug for current gallery.
     *
     * @var string
     */
    public $gallerySlug;

    /**
     * The current page we are viewing
     *
     * @var integer
     */
    public $page = 0;

    /**
     * The display mode of the current gallery.
     * 0 == Normal
     * 1 == Group by date
     *
     * @var integer
     */
    public $mode;

    /**
     * The style definition.
     *
     * @var Ansel_Style
     */
    public $style;

    /**
     * Holds number of tiles to display per page
     *
     * @var integer
     */
    public $perpage;

    /**
     * The tile number we are starting with on the current page.
     *
     * @var integer
     */
    public $pagestart;

    /**
     * The last tile number on the current page.
     *
     * @var integer
     */
    public $pageend;

    /**
     * The total number of tiles that this view contains
     *
     * @var integer
     */
    public $numTiles;

    /**
     * The Ansel_Image or Ansel_DateGallery objects that appear on the current
     * page in the current view.
     *
     * @var array of Ansel_Image or Ansel_DateGallery objects.
     */
    public $children;

    /**
     * If we are grouping by date, this holds the currently selected date parts.
     *
     * @var array containing sufficient date parts for the current depth.
     */
    public $date = array();

    /**
     * Human readable title for this view type
     *
     * @var string
     */
    public $title;

    /**
     * Constructor
     *
     * @param Ansel_View_Gallery  The view object for this renderer.
     */
    public function __construct(Ansel_View_Gallery $view = null)
    {
        $this->view = $view;
        Ansel_ActionHandler::imageActions(Horde_Util::getFormData('actionID'));
    }

    /**
     * Initialize the renderer. This *must* be called before any attempt is made
     * to display or otherwise interact with the renderer.
     *
     */
    public function init()
    {
        global $prefs, $conf, $registry, $page_output;

        $this->galleryId = $this->view->gallery->id;
        $this->gallerySlug = $this->view->gallery->get('slug');
        $this->page = $this->view->page;

        // Number perpage from prefs or config
        if ($this->view->tilesperpage) {
            $this->perpage = $this->view->tilesperpage;
        } else {
            $this->perpage = min(
                $prefs->getValue('tilesperpage'),
                $conf['thumbnail']['perpage']);
        }
        $this->pagestart = ($this->page * $this->perpage) + 1;

        // Fetch the children
        $this->fetchChildren($this->view->force_grouping);

        // Do we have an explicit style set from the API?
        // If not, use the gallery's
        if (!empty($this->view->style)) {
            $this->style = Ansel::getStyleDefinition($this->view->style);
        } else {
            $this->style = $this->view->gallery->getStyle();
        }

        // Include any widgets
        if (!empty($this->style->widgets) && !$this->view->api) {
            // Special case widgets - these are built in
            if (array_key_exists('Actions', $this->style->widgets)) {
                // Don't show action widget if no actions
                if ($registry->getAuth() ||
                    !empty($conf['report_content']['driver']) &&
                    (($conf['report_content']['allow'] == 'authenticated' &&
                      $registry->isAuthenticated()) ||
                     $conf['report_content']['allow'] == 'all')) {

                    $this->view->addWidget(Ansel_Widget::factory('Actions'));
                }
                unset($this->style->widgets['Actions']);
            }

            // Gallery widgets always receive an array of image ids for
            // the current page.
            $ids = $this->getChildImageIds();
            foreach ($this->style->widgets as $wname => $wparams) {
                $wparams = array_merge($wparams, array('images' => $ids));
                $this->view->addWidget(Ansel_Widget::factory($wname, $wparams));
            }
        }

        if (empty($this->view->api)) {
            $page_output->addScriptFile('views/common.js');
            $page_output->addScriptFile('views/gallery.js');
            $page_output->addScriptFile('popup.js', 'horde');

            $strings = array (
                'delete_conf' => _("Are you sure you want to delete the selected photos?"),
                'choose_gallery_move' => _("You must choose a gallery to move photos to."),
                'choose_images' => _("You must first choose photos.")
            );
            $urls = array(
                'image_date' => strval(Horde::url('edit_dates.php')->add(array('gallery' => $this->galleryId)))
            );
            $js = array(
                'Ansel = window.Ansel || {};',
                'Ansel.galleryview_strings = ' . Horde_Serialize::serialize($strings, Horde_Serialize::JSON),
                'Ansel.galleryview_urls = ' . Horde_Serialize::serialize($urls, Horde_Serialize::JSON),
                'Ansel.has_edit = ' . $this->view->gallery->hasPermission($registry->getAuth(), Horde_Perms::EDIT) ? 1 : 0,
                'Ansel.has_delete = ' . $this->view->gallery->hasPermission($registry->getAuth(), Horde_Perms::DELETE) ? 1 : 0
            );
            $page_output->addInlineScript($js, true);
        }

        // Perform any initialization of the subclasses.
        $this->_init();
    }

    /**
     * Stub to be overridden by child classes if needed.
     */
    protected function _init()
    {
    }

    /**
     * Return an initialized Horde_View instance, populated with all the values
     * common to all Gallery views.
     *
     * @return Horde_View
     */
    protected function _getHordeView()
    {
        global $registry, $injector, $prefs;

        $view = $injector->getInstance('Horde_View');
        $view->addTemplatePath(ANSEL_TEMPLATES .  '/view' . (!empty($this->view->api) ? '/api' : ''));
        $view->gallery = $this->view->gallery;
        $view->numTiles = $this->numTiles;
        $view->pergage = $this->perpage;
        $view->pagestart = $this->pagestart;
        $view->pageend = $this->pageend;
        $view->gallery_desc = $injector
            ->getInstance('Horde_Core_Factory_TextFilter')
            ->filter(
                $this->view->gallery->get('desc'),
                'text2html',
                array('parselevel' => Horde_Text_Filter_Text2html::MICRO));
        $view->children = $this->children;
        $view->view = $this->view;
        $view->style = $this->style;

        // Don't bother if we are being called from the api
        if (empty($this->view->api)) {
            $view->option_edit = $this->view->gallery->hasPermission(
                $registry->getAuth(), Horde_Perms::EDIT);

            $view->option_select = $view->option_delete = $this->view->gallery->hasPermission(
                $registry->getAuth(), Horde_Perms::DELETE);

            $view->option_move = ($view->option_delete && $injector
                ->getInstance('Ansel_Storage')
                ->countGalleries($registry->getAuth(), array('perm' => Horde_Perms::EDIT)));

            $view->option_copy = ($view->option_edit && $injector
                ->getInstance('Ansel_Storage')
                ->countGalleries($registry->getAuth(), array('perm' => Horde_Perms::EDIT)));

            // See if we requested a show_actions change (fallback for non-js)
            if (Horde_Util::getFormData('actionID', '') == 'show_actions') {
                $prefs->setValue('show_actions', (int)!$prefs->getValue('show_actions'));
            }
        }
        $view->tilesperrow = $this->view->tilesperrow ? $this->view->tilesperrow : $prefs->getValue('tilesperrow');
        $view->cellwidth = round(100 / $view->tilesperrow);
        $this->_setupPager($view);

        return $view;
    }

    /**
     * Return the current pagerurl.
     *
     * @return Horde_Url  The url
     */
    protected function _getPagerUrl()
    {
        $date_params = Ansel::getDateParameter(array(
            'year' => !empty($this->view->year) ? $this->view->year : 0,
            'month' => !empty($this->view->month) ? $this->view->month : 0,
            'day' => !empty($this->view->day) ? $this->view->day : 0));

        if (!empty($this->view->gallery_view_url)) {
            $pagerurl = new Horde_Url(str_replace(array('%g', '%s'), array($this->galleryId, $this->gallerySlug), urldecode($this->view->gallery_view_url)));
            $pagerurl->add($date_params)->setRaw(true);
        } else {
            // Build the pager url. Add the needed variables directly to the
            // url instead of passing it as a preserved variable to the pager
            // since the logic to build the URL is already in getUrlFor()
            $pager_params =  array_merge(
                array('gallery' => $this->galleryId,
                      'view' => 'Gallery',
                      'slug' => $this->view->gallery->get('slug')),
                $date_params);
            $pagerurl = Ansel::getUrlfor('view', $pager_params, true);
        }

        return $pagerurl;
    }

    /**
     * Populate the Horde_View with the $pager object.
     *
     * @param Horde_View $view  The Horde_View object.
     */
    protected function _setupPager(Horde_View &$view)
    {
        $vars = Horde_Variables::getDefaultVariables();
        if (!empty($this->view->page)) {
            $vars->add('page', $this->view->page);
            $view->page = $this->view->page;
        } else {
            $view->page = 0;
        }
        $pagerurl = $this->_getPagerUrl();
        if (!empty($this->view->urlCallback)) {
            $callback = $this->view->urlCallback;
        } else {
            $callback = null;
        }

        $params = array(
            'num' => $this->numTiles,
            'url' => $pagerurl,
            'perpage' => $this->perpage,
            'url_callback' => $callback);
        $view->pager = new Horde_Core_Ui_Pager('page', $vars, $params);
    }

    /**
     * Default implementation for fetching children/images for this view.
     * Other view classes can override this if they need anything special.
     *
     * @param boolean $noauto  Flag to indicate if we shouldn't automatically
     *                         drill down on views that support this. E.g.,
     *                         DateMode.
     */
    public function fetchChildren($noauto)
    {
        // Total number of tiles for this gallery view
        $this->numTiles = $this->view->gallery->countGalleryChildren(Horde_Perms::SHOW, false, $noauto);

        // Children to display on this page
        $this->children = $this->view->gallery->getGalleryChildren(
            Horde_Perms::SHOW,
            $this->page * $this->perpage,
            $this->perpage,
            !empty($this->view->force_grouping));

        // The last tile number to display on the current page
        $this->pageend = min($this->numTiles, $this->pagestart + $this->perpage - 1);
    }

    /**
     * Return the image ids contained in the gallery.
     *
     * @return array  An array of image ids.
     */
    public function getChildImageIds()
    {
        $ids = array();
        foreach ($this->children as $child) {
            if ($child instanceof Ansel_Image) {
                $ids[] = $child->id;
            }
        }

        return $ids;
    }

    /**
     * Return the HTML for this view. Done this way so we can override this in
     * subclasses if desired.
     *
     * @return string
     */
    abstract public function html();
}
