<?php
/**
 * Класс пагинации
 *
 * идея @jasongrimes/php-paginator
 *
 */
class cmsPaginator {

    private $total;
    private $pages_count;
    private $perpage;
    private $current_page;
    private $base_uri;
    private $anchor = '';
    private $page_param_name = 'page';
    private $query = [];

    private $max_show_pages = 5;

    public function __construct($total, $perpage, $current_page, $base_uri, $query = []) {

        $this->total        = (int)$total;
        $this->perpage      = (int)$perpage;
        $this->current_page = (int)$current_page;

        $this->updatePagesCount();

        if ($this->pages_count > 1) {
            $this->setQuery($query)->setBaseUri($base_uri);
        }
    }

    public function setMaxPagesToShow($max_show_pages) {
        $this->max_show_pages = $max_show_pages; return $this;
    }

    public function setPageParamName($page_param_name) {
        $this->page_param_name = $page_param_name;
        return $this;
    }

    public function setQuery($query) {

        if (!is_array($query)){
            parse_str($query, $query);
        }

        $this->query = $query;

        return $this;
    }

    public function setBaseUri($base_uri) {

        if (is_string($base_uri) && strpos($base_uri, '#') !== false){
            list($base_uri, $this->anchor) = explode('#', $base_uri);
        }

        if (!$base_uri) { $base_uri = cmsCore::getInstance()->uri_absolute; }

        if (!is_array($base_uri)){
            $base_uri = array(
                'first' => $base_uri,
                'base'  => $base_uri
            );
        } elseif(!isset($base_uri['first'])){
            $base_uri['first'] = $base_uri['base'];
        }

        $this->base_uri = $base_uri;

        return $this;
    }

    private function updatePagesCount() {
        $this->pages_count = ($this->perpage == 0 ? 0 : intval(ceil($this->total / $this->perpage)));
        return $this;
    }

    private function getPageUrl($page) {

        if(!$page){ return null; }

        $this->query[$this->page_param_name] = $page;

        $uri = $this->query[$this->page_param_name] == 1 ? $this->base_uri['first'] : $this->base_uri['base'];

        $sep = strpos($uri, '?') !== false ? '&' : '?';

        if ($this->query[$this->page_param_name] == 1) { unset($this->query[$this->page_param_name]); }

        return $uri . ($this->query ? $sep .http_build_query($this->query) : '') . ($this->anchor ? '#'.$this->anchor : '');
    }

    private function getNextPage() {
        if ($this->current_page < $this->pages_count) {
            return $this->current_page + 1;
        }
        return null;
    }

    private function getPrevPage() {
        if ($this->current_page > 1) {
            return $this->current_page - 1;
        }
        return null;
    }

    private function getNextUrl() {
        return $this->getPageUrl($this->getNextPage());
    }

    private function getPrevUrl() {
        return $this->getPageUrl($this->getPrevPage());
    }

    private function getPages() {

        $pages = [];

        if ($this->pages_count <= 1) {
            return $pages;
        }

        if ($this->pages_count <= $this->max_show_pages) {
            for ($i = 1; $i <= $this->pages_count; $i++) {
                $pages[] = $this->createPage($i, $i == $this->current_page);
            }
        } else {

            $num_adjacents = floor(($this->max_show_pages - 3) / 2);

            if ($this->current_page + $num_adjacents > $this->pages_count) {
                $sliding_start = $this->pages_count - $this->max_show_pages + 2;
            } else {
                $sliding_start = $this->current_page - $num_adjacents;
            }
            if ($sliding_start < 2){
                $sliding_start = 2;
            }

            $sliding_end = $sliding_start + $this->max_show_pages - 3;
            if ($sliding_end >= $this->pages_count){
                $sliding_end = $this->pages_count - 1;
            }

            $pages[] = $this->createPage(1, $this->current_page == 1);

            if ($sliding_start > 2) {
                $pages[] = $this->createPageEllipsis();
            }

            for ($i = $sliding_start; $i <= $sliding_end; $i++) {
                $pages[] = $this->createPage($i, $i == $this->current_page);
            }

            if ($sliding_end < $this->pages_count - 1) {
                $pages[] = $this->createPageEllipsis();
            }

            $pages[] = $this->createPage($this->pages_count, $this->current_page == $this->pages_count);
        }


        return $pages;
    }

    private function createPage($page, $is_current = false) {
        return [
            'num'        => $page,
            'url'        => $this->getPageUrl($page),
            'is_current' => $is_current
        ];
    }

    private function createPageEllipsis() {
        return [
            'num'        => '...',
            'url'        => null,
            'is_current' => false
        ];
    }

    public function getRendered() {

        if ($this->pages_count <= 1) {
            return '';
        }

        $from = $this->current_page * $this->perpage - $this->perpage + 1;
        $to   = $this->current_page * $this->perpage; if ($to > $this->total) { $to = $this->total; }

        $template = cmsTemplate::getInstance();

        return $template->getRenderedAsset('ui/'.$template->getOption('pagination_template', 'pagination'), [
            'stat_hint'    => sprintf(LANG_PAGES_SHOWN, $from, $to, $this->total),
            'current_page' => $this->current_page,
            'prev_url'     => $this->getPrevUrl(),
            'next_url'     => $this->getNextUrl(),
            'pages'        => $this->getPages(),
            'total'        => $this->total,
            'perpage'      => $this->perpage,
            'pages_count'  => $this->pages_count
        ]);
    }

}
