<?php
namespace SabaiApps\Framework\Paginator;

/**
 * CustomPaginator class for managing pagination with custom functions.
 * Allows dynamic calculation of element counts and fetching elements using user-defined functions.
 */
class CustomPaginator extends AbstractPaginator {

	protected $_getElementCountFunc, $_getElementsFunc, $_extraParams, $_extraParamsPrepend, $_emptyElements;

	/**
	 * Constructor.
	 *
	 * @param callable $getElementCountFunc Function to calculate the total count of elements.
	 * @param callable $getElementsFunc Function to fetch elements for the current page.
	 * @param int      $perpage Number of items per page.
	 * @param array    $extraParams Additional parameters for the functions (optional).
	 * @param array    $extraParamsPrepend Parameters to prepend to the functions (optional).
	 * @param mixed    $emptyElements Empty elements to return when no elements exist (optional).
	 * @param int      $limit Maximum number of items to paginate (optional).
	 */
	public function __construct( $getElementCountFunc, $getElementsFunc, $perpage, array $extraParams = array(), array $extraParamsPrepend = array(), $emptyElements = null, $limit = 0 ) {
		parent::__construct( $perpage, $limit );
		$this->_getElementCountFunc = $getElementCountFunc;
		$this->_getElementsFunc     = $getElementsFunc;
		$this->_extraParams         = $extraParams;
		$this->_extraParamsPrepend  = $extraParamsPrepend;
		$this->_emptyElements       = $emptyElements;
	}

	/**
	 * Sets additional parameters for the functions.
	 *
	 * @param array $params Parameters to set.
	 * @param bool  $prepend Whether to prepend the parameters.
	 */
	public function setExtraParams( array $params, $prepend = false ) {
		if ( $prepend ) {
			$this->_extraParamsPrepend = $params;
		} else {
			$this->_extraParams = $params;
		}
	}

	/**
	 * Calculates the total count of elements using the custom function.
	 *
	 * @return int
	 */
	protected function _getElementCount() {
		return call_user_func_array(
			$this->_getElementCountFunc,
			array_merge( $this->_extraParamsPrepend, $this->_extraParams )
		);
	}

	/**
	 * Fetches elements for the current page using the custom function.
	 *
	 * @param int $limit Number of elements to fetch.
	 * @param int $offset Offset for fetching elements.
	 * @return mixed
	 */
	protected function _getElements( $limit, $offset ) {
		return call_user_func_array(
			$this->_getElementsFunc,
			array_merge( $this->_extraParamsPrepend, array( $limit, $offset ), $this->_extraParams )
		);
	}

	/**
	 * Gets an empty collection of elements.
	 *
	 * @return mixed
	 */
	protected function _getEmptyElements() {
		return isset( $this->_emptyElements ) ? $this->_emptyElements : parent::_getEmptyElements();
	}
}
