<?php

class pluginSearch extends Plugin
{

	private $pagesFound = array();
	private $numberOfItems = 0;

	public function init()
	{
		// Fields and default values for the database of this plugin
		$this->dbFields = array(
			'label' => 'Search',
			'minChars' => 3,
			'wordsToCachePerPage' => 800,
			'showButtonSearch' => false
		);
	}

	public function form()
	{
		global $L;

		$html  = '<div class="alert alert-primary" role="alert">';
		$html .= $this->description();
		$html .= '</div>';

		$html .= '<div>';
		$html .= '<label>' . $L->get('Label') . '</label>';
		$html .= '<input name="label" type="text" dir="auto" value="' . $this->getValue('label') . '">';
		$html .= '<span class="tip">' . $L->get('This title is almost always used in the sidebar of the site') . '</span>';
		$html .= '</div>';

		$html .= '<div>';
		$html .= '<label>' . $L->get('Minimum number of characters when searching') . '</label>';
		$html .= '<input name="minChars" type="text" dir="auto" value="' . $this->getValue('minChars') . '">';
		$html .= '</div>';

		$html .= '<div>';
		$html .= '<label>' . $L->get('Show button search') . '</label>';
		$html .= '<select name="showButtonSearch">';
		$html .= '<option value="true" ' . ($this->getValue('showButtonSearch') === true ? 'selected' : '') . '>' . $L->get('enabled') . '</option>';
		$html .= '<option value="false" ' . ($this->getValue('showButtonSearch') === false ? 'selected' : '') . '>' . $L->get('disabled') . '</option>';
		$html .= '</select>';
		$html .= '</div>';
		$html .= '<div>';

		return $html;
	}

	// HTML for sidebar
	public function siteSidebar()
	{
		global $L;

		$html  = '<div class="plugin plugin-search">';
		$html .= '<h2 class="plugin-label">' . $this->getValue('label') . '</h2>';
		$html .= '<div class="plugin-content">';
		$html .= '<input type="text" dir="auto" id="jspluginSearchText" /> ';
		if ($this->getValue('showButtonSearch')) {
			$html .= '<input type="button" value="' . $L->get('Search') . '" onClick="pluginSearch()" />';
		}
		$html .= '</div>';
		$html .= '</div>';

		$DOMAIN_BASE = DOMAIN_BASE;
		$html .= <<<EOF
<script>
	function pluginSearch() {
		var text = document.getElementById("jspluginSearchText").value;
		window.open('$DOMAIN_BASE'+'search/'+text, '_self');
		return false;
	}

	document.getElementById("jspluginSearchText").onkeypress = function(e) {
		if (!e) e = window.event;
		var keyCode = e.keyCode || e.which;
		if (keyCode == '13'){
			pluginSearch();
			return false;
		}
	}
</script>
EOF;

		return $html;
	}

	public function install($position = 0)
	{
		parent::install($position);
		return $this->createCache();
	}

	// Method called when the user click on button save in the settings of the plugin
	public function post()
	{
		parent::post();
		return $this->createCache();
	}

	public function afterPageCreate()
	{
		$this->createCache();
	}

	public function afterPageModify()
	{
		$this->createCache();
	}

	public function afterPageDelete()
	{
		$this->createCache();
	}

	public function beforeAll()
	{
		// Check if the URL match with the webhook
		$webhook = 'search';
		if ($this->webhook($webhook, false, false)) {
			global $site;
			global $url;

			// Change the whereAmI to avoid load pages in the rule 69.pages
			// This is only for performance purpose
			$url->setWhereAmI('search');

			// Get the string to search from the URL
			$stringToSearch = $this->webhook($webhook, true, false);
			$stringToSearch = trim($stringToSearch, '/');

			// Search the string in the cache and get all pages with matches
			$list = $this->search($stringToSearch);
			$this->numberOfItems = count($list);

			// Split the content in pages
			// The first page number is 1, so the real is 0
			$realPageNumber = $url->pageNumber() - 1;
			$itemsPerPage = $site->itemsPerPage();
			if ($itemsPerPage <= 0) {
				if ($realPageNumber === 0) {
					$this->pagesFound = $list;
				}
			} else {
				$chunks = array_chunk($list, $itemsPerPage);
				if (isset($chunks[$realPageNumber])) {
					$this->pagesFound = $chunks[$realPageNumber];
				}
			}
		}
	}

	public function paginator()
	{
		$webhook = 'search';
		if ($this->webhook($webhook, false, false)) {
			// Get the pre-defined variable from the rule 99.paginator.php
			// Is necessary to change this variable to fit the paginator with the result from the search
			global $numberOfItems;
			$numberOfItems = $this->numberOfItems;
		}
	}

	public function beforeSiteLoad()
	{
		$webhook = 'search';
		if ($this->webhook($webhook, false, false)) {
			global $url;
			global $WHERE_AM_I;
			$WHERE_AM_I = 'search';

			// Get the pre-defined variable from the rule 69.pages.php
			// We change the content to show in the website
			global $content;
			$content = array();
			foreach ($this->pagesFound as $pageKey) {
				try {
					$page = new Page($pageKey);
					array_push($content, $page);
				} catch (Exception $e) {
					// continue
				}
			}
		}
	}

	// Generate the cache file
	// This function is necessary to call it when you create, edit or remove content
	private function createCache()
	{
		// Get all pages published
		global $pages;
		$list = $pages->getList($pageNumber = 1, $numberOfItems = -1, $published = true, $static = true, $sticky = true, $draft = false, $scheduled = false);

		$cache = array();
		foreach ($list as $pageKey) {
			$page = buildPage($pageKey);

			// Process content
			$words = $this->getValue('wordsToCachePerPage') * 5; // Asumming avg of characters per word is 5
			$content = $page->content();
			$content = Text::removeHTMLTags($content);
			$content = Text::truncate($content, $words, '');

			// Include the page to the cache
			$cache[$pageKey]['title'] = $page->title();
			$cache[$pageKey]['description'] = $page->description();
			$cache[$pageKey]['content'] = $content;
		}

		// Generate JSON file with the cache
		$json = json_encode($cache);
		return file_put_contents($this->cacheFile(), $json, LOCK_EX);
	}

	// Returns the absolute path of the cache file
	private function cacheFile()
	{
		return $this->workspace() . 'cache.json';
	}

	// Search text inside the cache
	// Returns an array with the pages keys related to the text
	// The array is sorted by score
	private function search($text)
	{
		// Read the cache file
		$json = file_get_contents($this->cacheFile());
		$cache = json_decode($json, true);

		// Inlcude Fuzz algorithm
		require_once($this->phpPath() . 'vendors/fuzz.php');
		$fuzz = new Fuzz($cache, 10, 1, true);
		$results = $fuzz->search($text, $this->getValue('minChars'));

		return (array_keys($results));
	}
}
