<?php namespace ProcessWire;

/**
 * ProcessWire MarkupPageArray module
 *
 * Adds convenience methods to all PageArray instances for markup generation
 * 
 * It adds PageArray::render() which generates a basic unordered list of linked pages. 
 * It can be called from any PageArray: 
 *
 * $items = $pages->find("id>0, limit=10"); // replace id>0 with your selector
 * echo $items->render(); // renders a basic list of linked pages
 * 
 * It will also generate pagination if the selector had a limit placed on it (i.e. "limit=10"),
 * and there are more pages left to render, and the page's template supports page numbers. 
 *
 * Also adds a PaginatedArray::renderPager() method, which is convenient when you are generating your
 * own page list markup, but just want to use the automatic pagination generator. 
 * 
 * 
 * ProcessWire 3.x, Copyright 2018 by Ryan Cramer
 * https://processwire.com
 *
 *
 */

class MarkupPageArray extends WireData implements Module {

	public static function getModuleInfo() {
		return array(
			'title' => 'PageArray Markup', 
			'summary' => 'Adds renderPager() method to all PaginatedArray types, for easy pagination output. Plus a render() method to PageArray instances.', 
			'version' => 100, 
			'permanent' => false, 
			'singular' => true, 
			'autoload' => true, 
			);
	}

	public function init() { 
		$this->addHook("PageArray::render", $this, "renderPageArray"); 
		$this->addHook("PaginatedArray::renderPager", $this, "renderPager"); 
	}	

	/**
	 * Render markup for a PageArray
	 *
	 * Can be accessed as $mypages->render() where '$mypages' is any instance of a PageArray. 
	 *
	 * Be sure to see the $defaultOptions in the method if you want to change it's behavior or output. 
	 * 
	 * @param HookEvent $event
	 *
	 * #param array $options Optional list of options to modify the behavior and output. 
	 * #return string
	 *
	 */
	public function renderPageArray(HookEvent $event) {

		/** @var PaginatedArray $pageArray */
		$pageArray = $event->object;
		$arguments = $event->arguments;
		$options = array();
		
		if(!count($pageArray)) {
			$event->return = '';
			return;
		}

		$defaultOptions = array(

			// markup for the list container, specify {out} where generated items should go
			'listMarkup' => "\n<ul class='PageArray'>{out}\n</ul>", 

			// markup for list item. note {title} may be any valid page field, or you may use multiple fields
			'itemMarkup' => "\n\t<li><a href='{url}'>{title}</a></li>", 

			// options to send to the pager (optional). See MarkupPagerNav::$options
			'pagerOptions' => array(), 	

			// show pagination links at the top (when applicable)?
			'pagerTop' => false,  		

			// show pagination links at the bottom (when applicable)?
			'pagerBottom' => true, 		

			// getVars for pager, but preferably use $input->whitelist instead!
			'getVars' => array(), 		

			// number of links to use for pagination, typically 10. 
			'numPageLinks' => 10, 		

			// base URL for pagination
			'baseUrl' => '',
			); 

		if(isset($arguments[0]) && is_array($arguments[0])) $options = $arguments[0]; 
		$options = array_merge($defaultOptions, $options); 

		$out = '';
		$fields = array();

		if(preg_match_all('/\{[-_a-z0-9|]+\}/i', $options['itemMarkup'], $matches)) {
			$fields = $matches[0];
		}
		
		foreach($pageArray as $page) {
			if($page instanceof Page && !$page->viewable()) continue; 
			$values = array();
			foreach($fields as $field) {
				$values[$field] = $page->get(trim($field, '{}'));
			}
			$out .= str_replace($fields, $values, $options['itemMarkup']); 
		}

		$out = str_replace('{out}', $out, $options['listMarkup']); 

		if(($options['pagerTop'] || $options['pagerBottom']) && $pageArray->getTotal() > count($pageArray))  {

			/** @var MarkupPagerNav $pager */
			$pager = $this->modules->get('MarkupPagerNav'); 	
			$pagerOptions = $options['pagerOptions']; 

			if(!empty($options['baseUrl'])) $pager->setBaseUrl($options['baseUrl']); 
				else $pager->setBaseUrl($this->page->url); 

			if(empty($options['getVars'])) $pagerOptions['getVars'] = $options['getVars'];
			if(empty($options['numPageLinks'])) $pagerOptions['numPageLinks'] = $options['numPageLinks'];

			$pagerOut = $pager->render($pageArray, $pagerOptions); 

			if($options['pagerTop']) $out = $pagerOut . $out; 
			if($options['pagerBottom']) $out .= $pagerOut; 
		} 

		$event->return = $out; 
	}

	/**
	 * Render pagination markup for a PageArray
	 *
	 * i.e. echo $mypages->renderPager(), where '$mypages' is a PageArray instance
	 * 
	 * @param HookEvent $event
	 *
	 * #param array $options Optional options to provide to MarkupPagerNav - see MarkupPagerNav::$options
	 * #return string
	 *
	 */
	public function renderPager(HookEvent $event) {
		/** @var PaginatedArray $pageArray */
		$pageArray = $event->object; 
		if(!$pageArray->getLimit()) return; 
		$arguments = $event->arguments; 
		$options = array();
		if(isset($arguments[0]) && is_array($arguments[0])) $options = $arguments[0]; 
		/** @var MarkupPagerNav $pager */
		$pager = $this->modules->get('MarkupPagerNav'); 
		if(empty($options['baseUrl'])) {
			$baseUrl = $this->wire('page')->url;
			$urlSegmentStr = $this->wire('input')->urlSegmentStr; 
			if(strlen($urlSegmentStr)) $baseUrl = rtrim($baseUrl, '/') . "/$urlSegmentStr/";
			$pager->setBaseUrl($baseUrl); 
		}
		$event->return = $pager->render($pageArray, $options); 
	}


}

