<?php
/** 
 * Альтернатива wp_pagenavi. Пагинация на страницах архивов
 * 
 * @version: 0.2
 * @author: veselka.ua
 *
 * @package veselka_ua/themes
 */

class NavArchives {

	use FileHandling, TemplatesLoad;

	/**
	 * Массив параметров.
	 * @type array
	 */
	private $options = [];
	/**
	 * Регистр.
	 * @type array
	 */
	private $registry = [];
	/**
	 * Результат работы.
	 * @type string
	 */
	private $result_set;

	public function __construct() {
		// В крючке вызывается метод обертка
		add_action( 'page_navigation', [$this, 'get_navigation'], 10, 0 );
	}

	/**
	 * Оберткка для получения результата работы.
	 *
	 * @param void
	 * @return string
	 */
	public function get_navigation() {
		// Инициализация
		$this->load();
		// Вывод результата
		echo $this->result_set;
	}

	/**
	 * Инициализация.
	 *
	 * @param void
	 * @return void
	 */
	private function load() {

		// Загрузка данных из вордпресс
		$this->load_wp_condition();
		//проверка на необходимость в навигации
		if( $this->registry['max_page'] <= 1 ) {
			return false;
		}

		// Загрузка шаблонов
		$this->get_html();
		// Загрузка параметров
		$this->load_options();

		// Вычисление интрервалов
		$this->page_calculations();
		// Подготовка к построению результата
		$this->result_set = '';
		// Текстовое оформление информационного блока если нужно
		$this->nonstandard_text_layout();

		// Сборка пагинации
		$this->pagination_assembly();
		// Обертка
		$this->pagination_wrapper();
	}


	/**
	 * Получение текущих параметов WP.
	 *
	 * @param void
	 * @return void
	 */
	private function load_wp_condition() {
		global $wp_query;
		$this->registry['posts_per_page'] = (int) $wp_query->query_vars['posts_per_page']; //?
		$this->registry['paged'] = (int) $wp_query->query_vars['paged'];
		$this->registry['max_page'] = (int) $wp_query->max_num_pages;
		// Обработка исключений
		if( empty($this->registry['paged']) || $this->registry['paged'] == 0 ) {
			$this->registry['paged'] = 1;
		}
	}


	/**
	 * Формирование разметки рейтинга.
	 *
	 * @param void
	 * @return void
	 */
	private function get_html() {
		// Проверка наличия файла с разметкой навигации
		//$file_path['wrapper'] = TEMPLATEPATH . '/view/pagination.php';
		$this->options['files']['pagination'] = 'pagination.php';
		// Проверка наличия файла с разметкой элемента навигации
		//$file_path['item'] = TEMPLATEPATH . '/view/pagination_item.php';
		$this->options['files']['pagination_item'] = 'pagination_item.php';

		foreach( $this->options['files'] as $key => $value ) {
			// Исключение (нет файла)
			if( !$this->check_template( $key, 'view' ) ) {
				throw new Exception('File error: ' . $value);
			}
		}
	}


	/**
	 * Запись параметров.
	 *
	 * @param void
	 * @return void
	 */
	private function load_options() {
		// Выводит до блока навигации
		$this->options['before'] = '';
		// Выводит после блока навигации
		$this->options['after'] = '';
		// Текст перед пагинацией. {current} - текущая; {last} - последняя (пр. 'Страница {current} из {last}' получим: "Страница 4 из 60" )
		$this->options['text_num_page'] = '';
		// сколько ссылок показывать
		$this->options['num_pages'] = 3;
		// ссылки с шагом (значение - число, размер шага (пр. 1,2,3...10,20,30). Ставим 0, если такие ссылки не нужны.
		$this->options['step_link'] = 3;
		// промежуточный текст "до".
		$this->options['ellipsis'] = '...';
		// текст "перейти на предыдущую страницу". Ставим 0, если эта ссылка не нужна.
		$this->options['back_text'] = '<i class="fa fa-step-backward" aria-hidden="true"></i>';
		// текст "перейти на следующую страницу". Ставим 0, если эта ссылка не нужна.
		$this->options['next_text'] = '<i class="fa fa-step-forward" aria-hidden="true"></i>';
		// текст "к первой странице". Ставим 0, если вместо текста нужно показать номер страницы.
		$this->options['first_page_text'] = '<i class="fa fa-fast-backward" aria-hidden="true"></i>';
		// текст "к последней странице". Ставим 0, если вместо текста нужно показать номер страницы.
		$this->options['last_page_text'] = '<i class="fa fa-fast-forward" aria-hidden="true"></i>';		
	}


	/**
	 * Вычисление интрервалов.
	 *
	 * @param void
	 * @return void
	 */
	private function page_calculations() {

		$this->registry['pages_to_show'] = intval( $this->options['num_pages'] );
		$pages_to_show_decrement = $this->registry['pages_to_show'] - 1;

		$half_page_start = floor( $pages_to_show_decrement / 2 ); //сколько ссылок до текущей страницы
		$half_page_end = ceil( $pages_to_show_decrement / 2 ); //сколько ссылок после текущей страницы

		$this->registry['start_page'] = $this->registry['paged'] - $half_page_start; //первая страница
		$this->registry['end_page'] = $this->registry['paged'] + $half_page_end; //последняя страница (условно)

		if( $this->registry['start_page'] <= 0 ) {
			$this->registry['start_page'] = 1;
		}
		if( ($this->registry['end_page'] - $this->registry['start_page']) != $pages_to_show_decrement ) {
			$this->registry['end_page'] = $this->registry['start_page'] + $pages_to_show_decrement;
		}
		if( $this->registry['end_page'] > $this->registry['max_page'] ) {
			$this->registry['start_page'] = $this->registry['max_page'] - $pages_to_show_decrement;
			$this->registry['end_page'] = (int) $this->registry['max_page'];
		}
		if( $this->registry['start_page'] <= 0 ) {
			$this->registry['start_page'] = 1;
		}

		// создаем базу чтобы вызвать get_pagenum_link один раз
		$this->registry['link_base'] = get_pagenum_link( 99999999 ); // 99999999 будет заменено
		$this->registry['link_base'] = str_replace( 99999999, '___', $this->registry['link_base']);
		$this->registry['first_url'] = get_pagenum_link( 1 );
	}


	/**
	 * Текстовое оформление информационного блока.
	 *
	 * @param void
	 * @return void
	 */
	private function nonstandard_text_layout() {
		if( $this->options['text_num_page'] != '' ){
			$this->options['text_num_page'] = preg_replace( '!{current}|{last}!', '%s', $this->options['text_num_page'] );
			$this->result_set .= sprintf( "<span class='pages'>$this->options['text_num_page']</span> ", $this->registry['paged'], $this->registry['max_page'] );
		} 
	}


	/**
	 * Пагинация.
	 *
	 * @param void
	 * @return void
	 */
	private function pagination_assembly() {
		// Ссылка в начало
		$this->fast_backward_assembly();
		// Ссылка на предыдущий элемент
		$this->step_backward_assembly();
		// Сбока внутренних страниц
		$this->internal_elements_assembly();
		// Ссылки с шагом
		$this->step_links_assembly();
		// Ссылка на следующий элемент
		$this->step_forward_assembly();
		// Ссылка в конец
		$this->fast_forward_assembly();
	}


	/**
	 * Ссылка в начало.
	 *
	 * @param void
	 * @return void
	 */
	private function fast_backward_assembly() {
		if( $this->registry['start_page'] >= 2 && $pages_to_show < $this->registry['max_page'] ) {
			if( $this->options['first_page_text'] ) {
				$anchor = $this->options['first_page_text'];
			} else {
				$anchor = 1;
			}
			$incubator = '<a rel="start" class="first-page" href="' . $this->registry['first_url'] . '">' . $anchor . '</a>';
			$this->result_set .= $this->item_wrapper($incubator);
		}
	}


	/**
	 * Ссылка на предыдущий элемент.
	 *
	 * @param void
	 * @return void
	 */
	private function step_backward_assembly() {

		if( $this->options['back_text'] && $this->registry['paged'] != 1 ) {
			$url = str_replace( '___', ($this->registry['paged']-1), $this->registry['link_base'] );
			$incubator = '<a rel="prev" class="prev-page" href="' . $url . '">' . $this->options['back_text'] . '</a>';
			$this->result_set .= $this->item_wrapper($incubator);
		}
	}


	/**
	 * Сбока внутренних страниц.
	 *
	 * @param void
	 * @return void
	 */
	private function internal_elements_assembly() {
		for( $i = $this->registry['start_page']; $i <= $this->registry['end_page']; $i++ ) {
			if( $i == $this->registry['paged'] ) {
				$incubator = '<span class="current-page">' . $i . ' <span class="sr-only">(current)</span></span>';
				$this->result_set .= $this->item_wrapper($incubator, $class = 'active');
			} elseif( $i == 1 ) {
				$incubator = '<a href="' . $this->registry['first_url'] . '">1</a>';
				$this->result_set .= $this->item_wrapper($incubator);
			} else {
				$url = str_replace( '___', $i, $this->registry['link_base'] );
				$incubator = '<a href="' . $url . '">' . $i . '</a>';
				$this->result_set .= $this->item_wrapper($incubator);
			}
		}
	}


	/**
	 * Ссылки с шагом.
	 *
	 * @param void
	 * @return void
	 */
	private function step_links_assembly() {
		//var_dump($this->options);
		//var_dump($this->registry);
		if( $this->options['step_link'] && $this->registry['end_page'] < $this->registry['max_page'] ) {
			for( $i = $this->registry['end_page']+1; $i <= $this->registry['max_page']; $i++ ) {
				if( $i % $this->options['step_link'] == 0 && $i !== $this->options['num_pages'] ) {
					if( ++$dd == 1 ) {
						$incubator = '<span class="ellipsis">' . $this->options['ellipsis'] . '</span>';
						$this->result_set .= $this->item_wrapper($incubator, $class = 'disabled');
					}
					$url = str_replace( '___', $i, $this->registry['link_base'] );
					$incubator = '<a href="' . $url . '">' . $i . '</a>';
					$this->result_set .= $this->item_wrapper($incubator);
				}
			}
		}
	}


	/**
	 * Ссылка на следующий элемент.
	 *
	 * @param void
	 * @return void
	 */
	private function step_forward_assembly() {
		if( $this->options['next_text'] && $this->registry['paged'] != $this->registry['end_page'] ) {
			$url = str_replace( '___', ($this->registry['paged']+1), $this->registry['link_base'] );
			$incubator = '<a rel="next" class="next-page" href="' . $url . '">' . $this->options['next_text'] . '</a>';
			$this->result_set .= $this->item_wrapper($incubator);
		}
	}


	/**
	 * Ссылка в конец.
	 *
	 * @param void
	 * @return void
	 */
	private function fast_forward_assembly() {
		if( $this->registry['end_page'] < $this->registry['max_page'] ) {
			if( $this->options['last_page_text'] ) {
				$anchor = $this->options['last_page_text'];
			} else {
				$anchor = $this->registry['max_page'];
			}
			$url = str_replace( '___', $this->registry['max_page'], $this->registry['link_base'] );
			$incubator = '<a rel="next" class="last-page" href="' . $url . '">' . $anchor . '</a> ';
			$this->result_set .= $this->item_wrapper($incubator);
		}
	}


	/**
	 * Обертка для элемента.
	 *
	 * @param void
	 * @return string
	 */
	private function item_wrapper($item, $class = '') {
		// Селектор элемента
		$replacement['item_selector'] = '';
		if( $class == 'active' ) {
			$replacement['item_selector'] = ' class="active"';
		} elseif( $class == 'disabled' ) {
			$replacement['item_selector'] = ' class="disabled"';
		}
		$replacement['item'] = $item;
		return $this->markers_replacement($this->templates['pagination_item'], $replacement);
	}


	/**
	 * Обертка.
	 *
	 * @param void
	 * @return void
	 */
	private function pagination_wrapper() {
		$replacement['pagination_before'] = $this->options['before'];
		$replacement['pagination_after'] = $this->options['after'];
		$replacement['navigation'] = $this->result_set;

		$this->result_set = $this->markers_replacement($this->templates['pagination'], $replacement);
	}

} // end NavArchives
?>