<?php
/*
['start']=>
['first']=>
['last']=>
['current']=>
['sql_start']=>
['next']=>
['prev']=>
['pages']=>array()

*/


class Paginator
{
	public $items_at_page=10;
	public $current=0;
	public $total_items=0;
	public $wide_edge=3;
	public $wide=9;
	public $reverse=false;
	public $total=0;
	public $pages=array();
	
	function __construct($total=null, $items_at_page=null, $current=null)
	{
		if ($total) $this->total_items=$total;
		if ($items_at_page) $this->items_at_page=$items_at_page;
		if ($current) $this->current=$current;
	}
	
	public function getPages()
	{
		$result=array();
		$result['total']=$this->_getTotal();
		$result['first']=$this->_getFirst();
		$result['last']=$this->_getLast();
		$result['current']=$this->_getCurrent();
		$result['sql_start']=$this->_getSqlStart();
		$result['sql_limit']=$this->items_at_page;
		$result['next']=(!$this->reverse)?$this->_getNext():$this->_getPrev();
		$result['prev']=(!$this->reverse)?$this->_getPrev():$this->_getNext();
		$result['pages']=$this->_getPages();
		$result['labels']=$this->_getLabels();
		$result['total_items']=$this->total_items;
		return $result;
	}
	
	private function _getPages()
	{
		if ($this->total<=1) return null;
		$this->pages=$pages=array();
		//если тотал меньше границы, возвращаем тотал
		if ($this->total<=$this->wide) {
			$this->pages=array_merge(
				$pages,
				(!$this->reverse)?range(1, $this->total):range($this->total, 1)
			);
			return $this->pages;
		}

		if (!$this->reverse) {
			$pages=range(1, $this->wide_edge);
			if ($this->current-$this->wide/2<1) {
				$pages=array_merge(
					$pages,
					range(1, $this->wide-1)
				);
			} elseif ($this->current+$this->wide/2>$this->total) {
				$pages=array_merge(
					$pages,
					range($this->total-$this->wide+2, $this->total)
				);
			} else {
				$pages=array_merge(
					$pages,
					range(
						$this->current-ceil($this->wide/2)+1,
						$this->current+ceil($this->wide/2)-1
					)
				);
			}
			
			$pages=array_merge(
				$pages,
				range($this->total-$this->wide_edge+1, $this->total)
			);
			
			$pages=array_unique($pages);
			foreach ($pages as $key=>$page) {
				$this->pages[]=$page;
				if (array_key_exists($key+1, $pages)
					&& ($page+1!=$pages[$key+1])
				) {
					$this->pages[]=null;
				}
			}
		} else {
			$pages=range($this->total, $this->total-$this->wide_edge+1);
			if ($this->current+$this->wide/2>$this->total) {
				$pages=array_merge(
					$pages,
					range(
						$this->total,
						$this->total-$this->wide+1
					)
				);
			} elseif ($this->current-$this->wide/2<1) {
				$pages=array_merge($pages, range($this->wide, 1));
			} else {
				$pages=array_merge(
					$pages,
					range(
						$this->current+ceil($this->wide/2)-1,
						$this->current-ceil($this->wide/2)+1
					)
				);
			}
			$pages=array_merge($pages, range($this->wide_edge, 1));
			$pages=array_unique($pages);
			foreach ($pages as $key=>$page) {
				$this->pages[]=$page;
				if (array_key_exists($key+1, $pages)
					&& ($page-1!=$pages[$key+1])
				) {
					$this->pages[]=null;
				}
			}
		}
		
		return $this->pages;
	}
	
	private function _getLabels()
	{
		if ($this->total==1) return null;
		if ($this->reverse) {
			foreach ($this->pages as $label) {
				$this->labels[]=($label)?($this->total+1-$label):null;
			}
			return $this->labels;
		} else
			return $this->pages;
	}
	
	private function _getNext()
	{
		if ($this->current+1<=$this->total) return $this->current+1;
		return null;
	}
	
	private function _getPrev()
	{
		if ($this->current-1>0) return $this->current-1;
		return null;
	}
	
	private function _getFirst()
	{
		return ($this->reverse)?$this->total:1;
	}
	
	private function _getLast()
	{
		return ($this->reverse)?1:$this->total;
	}
	
	private function _getTotal()
	{
		return $this->total=intval(ceil($this->total_items/$this->items_at_page));
	}
	
	private function _getCurrent()
	{
		$this->current=intval($this->current);
		if ($this->current > $this->total) $this->current = $this->total;
		if ($this->current < 1) $this->current=(!$this->reverse)?1:$this->total;
		return $this->current;
	}
	
	private function _getSqlStart()
	{
		if ($this->reverse) {
			return ($this->total-$this->current) *$this->items_at_page;
		}
		else
			return ($this->current-1)*$this->items_at_page;
	}
	
}