<?php
/**
 * CGBetterUploads API
 *
 * @package CGBetterUploads
 */

namespace CGBetterUploads;
use Iterator;
use Countable;

/**
 * An abstract class to allow iterating, counting, and paginationg the output from a filter.
 *
 * @property-read int $pagecount The total number of pages
 * @property-read int $page The current page number
 * @property-read int $total The total number of records matched by the filter.
 * @property-read Filter $filter The filter used to create the matches.
 */
abstract class FilterResultset implements Iterator, Countable
{
    /**
     * @ignore
     */
    private $_list;

    /**
     * @ignore
     */
    private $_total;

    /**
     * @ignore
     */
    private $_filter;

    /**
     * Constructor
     *
     * @internal
     */
    protected function __construct( Filter $filter, int $totalMatches, array $matches = null )
    {
        $this->_filter = $filter;
        $this->_total = $totalMatches;
        if( is_null($matches) ) $matches = [];
        $this->_list = $matches;
    }

    /**
     * @ignore
     */
    public function rewind() { reset($this->_list); }

    /**
     * @ignore
     */
    public function current() { return current($this->_list); }

    /**
     * @ignore
     */
    public function key() { return key($this->_list); }

    /**
     * @ignore
     */
    public function next() { return next($this->_list); }

    /**
     * @ignore
     */
    public function valid() { return ($this->key() !== null); }

    /**
     * @ignore
     */
    public function count() { return count($this->_list); }

    /**
     * @ignore
     */
    public function __get( string $key )
    {
        switch( $key ) {
        case 'pagecount':
            return ceil($this->_total / $this->_filter->limit);

        case 'page':
            return floor($this->_filter->offset / $this->_filter->limit) + 1;

        case 'total':
            return $this->_total;

        case 'filter':
            return $this->_filter;

        default:
            throw new \InvalidArgumentException("$key is not a gettable property of ".get_class($this));
        }
    }

    /**
     * @ignore
     */
    public function __set( string $key, $val )
    {
        throw new \InvalidArgumentException("$key is not a settable property of ".get_class($this));
    }

    /**
     * Get a list of pages matching this resultset, to be used in generating a pagination interface.
     *
     * @param int $surround The number of entries to surround the current page with.
     * @return int[] An array of page numbers.
     */
    public function pageList(int $surround = 5)
    {
        $surround = max(2,min(50,$surround));

        $list = array();
        for( $i = 1; $i <= min($surround,$this->pagecount); $i++ ) {
            $list[] = (int)$i;
        }

        $x1 = max(1,(int)($this->page - $surround / 2));
        $x2 = min($this->pagecount - 1,(int)($this->page + $surround / 2) );
        for( $i = $x1; $i <= $x2; $i++ ) {
            $list[] = (int)$i;
        }

        for( $i = max(1,$this->pagecount - $surround); $i < $this->pagecount; $i++) {
            $list[] = (int)$i;
        }

        $list = array_unique($list);
        sort($list);
        return $list;
    }

} // class
