public function calculate(): Pagination
    {
        // calculate how many page
        $this->pages_count = 1;
        if ($this->items_count > 0 && $this->items_per_page > 0) {
            $this->pages_count = ceil(($this->items_count / $this->items_per_page));
        } elseif ($this->items_count == 0) {
            $this->pages_count = 0;
        }
        
        // generate pages array
        $this->pages = [];
        if ($this->pages_count > 0) {
            $this->pages = range(1, $this->pages_count);
        }

        // check current page
        if (!$this->isPage($this->current_page)) {
            throw new Exception(__CLASS__.': page '.$this->current_page.' doesn\'t exists');
        }

        $this->first_page = empty($this->pages) ? null : 1;
        $this->last_page = ($this->pages_count < 1) ? null : $this->pages_count;

        // prev/next page
        $this->prev_page = ($this->current_page > 1) ? $this->current_page  - 1 : null;
        $this->next_page = (($this->current_page + 1) <= $this->pages_count) ? $this->current_page + 1 : null;
        
        // item start/end page
        $this->item_start = (($this->current_page - 1) * $this->items_per_page);
        $this->item_end = $this->item_start + $this->items_per_page;
        
        if (($this->items_count != 0)) {
            ++$this->item_start;
        }
        if ($this->item_end > $this->items_count) {
            $this->item_end = $this->items_count;
        }

        // item start offset
        $this->offset = $this->item_start - 1;

        return $this;
    }