<?php
namespace App\Mvc\View\Listing\Members;

/**
 * The pagination class.
 * Previously defined in smarty_function_pageControls_v2
 * @author Lucian Sirbu
 */
class Pagination
{
	protected $currentPage = 	0;
	protected $totalItems = 	0;
	protected $itemsPerPage = 	0;
	protected $itemsPerPageList = [5=>5, 10=>10, 25=>25, 50=>50]; // foramt: itemsPerPage => label
	protected $format = 		'';

	protected $totalItemsIsCached;

	/**
	 * Set the current page index
	 * @param int $currentPage
	 * @return \App\Mvc\View\Listing\Members\Pagination
	 */
	public function setCurrentPage($currentPage)
	{
		$this->currentPage = $currentPage;
		return $this;
	}

	/**
	 * Get the current page number
	 * @return number
	 */
	public function getCurrentPage()
	{
		return $this->currentPage;
	}

	/**
	 * Set the total items to be displayed
	 * @param int $totalItems
	 * @return \App\Mvc\View\Listing\Members\Pagination
	 */
	public function setTotalItems($totalItems)
	{
		$this->totalItems = $totalItems;
		return $this;
	}


	/**
	 * Get the total items count
	 * @return number
	 */
	public function getTotalItems()
	{
		return $this->totalItems;
	}


	/**
	 * Get the text to be displayed for the total number of results
	 * @return string
	 */
	public function getTotalItemsForDisplay()
	{
		if ($this->totalItemsIsCached) {
			// map total number of results like '21344' to '~21k'

			if ($this->totalItems==0) {
				return '0';
			}
			elseif ($this->totalItems<50) {
				return $this->totalItems;
			}
			elseif ($this->totalItems<900) {
				return sprintf("~%d", 10*ceil($this->totalItems/10));
			}
			elseif ($this->totalItems<1100) {
				return sprintf("~%.0fk", round($this->totalItems/1000, 2));
			}
			elseif ($this->totalItems<9000) {
				return sprintf("~%.1fk", round($this->totalItems/1000, 2));
			}
			elseif ($this->totalItems<11000) {
				return sprintf("~%.0fk", round($this->totalItems/1000, 2));
			}
			elseif ($this->totalItems<900000) {
				return sprintf("~%.0fk", round($this->totalItems/1000, 2));
			}
			else {
				return sprintf("~%.2fM", round($this->totalItems/(1000*1000), 3));
			}
		}
		else {
			return $this->totalItems;
		}
	}


	/**
	 * Set if the total number of results is cached, and should be used as 'rounded'
	 * @param bool $isCached
	 * @return \App\Mvc\View\Listing\Members\Pagination
	 */
	public function setTotalItemsIsCached($isCached = true)
	{
		$this->totalItemsIsCached = $isCached;
		return $this;
	}


	/**
	 * Check if the total number of results was marked as cached
	 * @return bool
	 */
	public function getTotalItemsIsCached()
	{
		return $this->totalItemsIsCached;
	}


	/**
	 * Set the items per page count
	 * @param int $itemsPerPage
	 * @return \App\Mvc\View\Listing\Members\Pagination
	 */
	public function setItemsPerPage($itemsPerPage)
	{
		if ($itemsPerPage==0) {
			$itemsPerPage = 1;
			\Log::getInstance()->error(sprintf('[%s:%s] Check why the itemsPerPage is 0 in pagination class.', __METHOD__, __LINE__));
		}
		$this->itemsPerPage = $itemsPerPage;
		return $this;
	}


	/**
	 * Get the number of items per page
	 */
	public function getItemsPerPage()
	{
		return $this->itemsPerPage;
	}


	/**
	 * Get the total number of pages
	 * @return number
	 */
	public function getTotalPages()
	{
		return (int)ceil($this->totalItems / $this->itemsPerPage);
	}


	/**
	 * Get the first displayed item index
	 * @return int
	 */
	public function getFirstDisplayedItem()
	{
		$index = min(
			$this->currentPage*$this->itemsPerPage,
			$this->totalItems - $this->totalItems % $this->itemsPerPage
		);

		return $index;
	}


	/**
	 * Get the last displayed item index
	 * @return int
	 */
	public function getLastDisplayedItem()
	{
		$index = min(
			$this->currentPage*$this->itemsPerPage+$this->itemsPerPage,
			$this->totalItems
		);

		return $index;
	}


	/**
	 * Get the list of items per page
	 * @return multitype:number
	 */
	public function getItemsPerPageList()
	{
		return $this->itemsPerPageList;
	}


	/**
	 * Set the internal itemsPerPage setting
	 * @param array $itemsPerPageList
	 * @return \App\Mvc\View\Listing\Members\Pagination
	 */
	public function setItemsPerPageList($itemsPerPageList)
	{
		$this->itemsPerPageList = $itemsPerPageList;
		return $this;
	}


	/**
	 * Set the output format
	 * @param string $format
	 * @return \App\Mvc\View\Listing\Members\Pagination
	 */
	public function setFormat($format)
	{
		$this->format = $format;
		return $this;
	}


	/**
	 * Get the output format
	 * @return string
	 */
	public function getFormat()
	{
		return $this->format;
	}


	/**
	 * Get the pages list
	 * @return multitype:
	 */
	public function getPagesList()
	{
		/**
		 * This function generates the list of pages to be displayed in the interface.
		 * It split the whole pagination in 2 intervals, and loops through each page that should get displayed.
		 *
		 *    <-------------------------#------------------------------------->
		 *                              ^
		 *                              |
		 *                           ---+----
		 *                         Current page
		 *
		 * First, it loops through all elements on the left of the current page, using a for() loop.
		 * 	- it initializes "$distance" with value 1
		 *  - for each element, it it divides $distance, add it to the pages list
		 *  - reports max 5 items per interval ($maxItemsPerInterval)
		 *  - when reported items reaches $maxItemsPerInterval, it sets $distance to 10, and continues reports items dividing $distance
		 *  	- same for 10, 100, 1000, 10000 etc. The divisor is multiplied by $distanceMultiplier when it reaches its limit.
		 *
		 *  A very similar algorithm is applied for all items on the left of the current page
		 *
		 */

		$pagination = [];

		$maxItemsPerInterval = 5;
		$distanceMultiplier = 10;
		$maxInterval = PHP_INT_MAX/100;
		$itemsMarginWidth = 2;

		// determine pages following the current one
		$items = 0;
		$distance = 1;

		$totalPages = $this->getTotalPages();
		$currentPage = $this->getCurrentPage();
		for ($i=$this->currentPage; $i<$totalPages; $i++) {
			$add = false;

			if ($items>$maxItemsPerInterval && $distance<$maxInterval) {
				$items = 0;
				$distance*=$distanceMultiplier;
			}

			if ($i % $distance===($distance-1)) {
				$add = true;
			}

			if ($i >= ($totalPages - $itemsMarginWidth)) {
				$add = true;
			}

			if($add){
				$items++;
				$pagination[$i] = [
					'index' => 		$i,
					'distance' => 	$distance,
					'isCurrent' => 	($i===$currentPage)
				];
			}
		}

		// determine pages before the current one
		$items = 0;
		$distance = 1;
		for ($i=$currentPage-1; $i>=0; $i--) {
			$add = false;

			if ($items>=$maxItemsPerInterval && $distance<$maxInterval) {
				$items = 0;
				$distance*=$distanceMultiplier;
			}

			if ($i % $distance===($distance-1)) {
				$add = true;
			}

			if ($i < ($itemsMarginWidth)) {
				$add = true;
			}

			if ($add) {
				$items++;
				$pagination[$i] = [
					'index' => 		$i,
					'distance' => 	$distance,
					'isCurrent' => 	($i===$currentPage)
				];
			}
		}

		ksort($pagination);
		return array_values($pagination);
	}
}
