<?php
/**
 * Prolog plug-in : Rule-based System for Groupware.
 * 
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Paweł Kupka <pawel.kupka@gmail.com>
 */
 
// must be run within Dokuwiki
$webroot = reset(split('lib',dirname(__FILE__)));
if(!defined('DOKU_INC')) define('DOKU_INC', $webroot);
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins');
if(!defined('DOKU_PAGES')) define('DOKU_PAGES',DOKU_INC.'data/pages');
if(!defined('DOKU_TMP')) define('DOKU_TMP',DOKU_INC.'data/tmp');
require_once (DOKU_INC.'inc/pageutils.php');
require_once (DOKU_INC.'inc/utf8.php');

class PrologTag {

	var $entryTagPattern = '/<prolog.*>/';
	var $exitTagPattern = '/<\/prolog>/';
	
	var $attributeEntryPattern = '\(';
	var $attributeExitPattern = '\)';
	var $attributeValuePattern = '[^\)]*';
	var $attributeName;
	var $attributePattern;

	/**
	 * Constructor
	 */
	function PrologTag() 
	{
	}
	
	/**
	 * Gets all prolog entry tags from the text file
	 * @param string $file file path
	 * @return array $matchedTags found prolog entry tags
	 */
	function getEntryTags($file = null) 
	{
		$fileContent = file_get_contents($file);
		$foundTags = preg_match_all($this->entryTagPattern, $fileContent, $matchedTags);
		return $matchedTags[0];
	}
	
	/**
	 * Sets attribute pattern
	 * @param string $attributeName attribute name
	 */
	function setAttributePattern($attributeName) 
	{
		$this->attributeName = $attributeName;
		$this->attributePattern = '/';
		$this->attributePattern .= '([a-zA-Z0-9]+)';
		$this->attributePattern .= $this->attributeEntryPattern;
		$this->attributePattern .= '('.$this->attributeValuePattern.')';
		$this->attributePattern .= $this->attributeExitPattern;
		$this->attributePattern .= '/';
	}
	
	/**
	 * Gets the attribute value from the prolog entry tag
	 * @param string $prologTag prolog entry tag
	 * @return string $matched matched attribute value
	 */
	function getAttributeValue($prologTag = null) 
	{
		$found = preg_match_all($this->attributePattern, $prologTag, $matched);
		$attrValue = '';
		foreach($matched[1] as $i => $attrName) {
			if($attrName == $this->attributeName) {
				$attrValue = $matched[2][$i];
				break;

			}
		}
		return $attrValue;
	}

	/**
	 * Executes prolog code in the Prolog interpreter
	 * @param string $prologCode the prolog source code
	 * @param string $maxExecutionTime the limit for maximum interpretation time (in seconds)
	 * @return array $executed array with output and errors from the interpreter
	 */
	function execute($prologCode = null, $maxExecutionTime = 5) 
	{
		$executed = array('','');

		if(!isset($prologCode))
			return $executed;
			
		$maxExecutionTime = intval($maxExecutionTime);		
		if($maxExecutionTime < 1 || $maxExecutionTime > 5) //1sec - 30sec
			$maxExecutionTime = 5;

		$tmpname = tempnam(DOKU_TMP, 'pl_');
		$stdin = $tmpname.'.pl';
		unlink($tmpname);

		$handleStdin = fopen($stdin, 'w');
		fwrite($handleStdin, $prologCode);
		fclose($handleStdin);


		$descriptorspec = array(
			0 => array('pipe', 'r'),  // stdin 
			1 => array('pipe', 'w'),  // stdout
			2 => array('pipe', 'w')   // stderr
		);

		$process = proc_open('pl', $descriptorspec, $pipes);

		if(is_resource($process)) {
			fwrite($pipes[0], '[\''.substr($stdin, 0, -3).'\'].');
			fclose($pipes[0]);
			
			$step = 10000; //0.01 second
			$maxExecutionTime = $maxExecutionTime * 1000000;
			$status = proc_get_status($process);
			while($status['running'] && $maxExecutionTime != 0) {
				
  				$maxExecutionTime -= $step;
				usleep($step);
				$status = proc_get_status($process);
			}

														if($status['running'] == true) { 
    				fclose($pipes[1]); //stdout
    				fclose($pipes[2]); //stderr
				proc_terminate($process);
				$executed[1] .= 'Process reached the maximum execution time and has been terminated! ';
				proc_close($process);
				
			}
			else {
				$executed[0] = stream_get_contents($pipes[1]);
				$executed[1] = stream_get_contents($pipes[2]);
				fclose($pipes[1]); //stdout
    				fclose($pipes[2]); //stderr
				proc_close($process);
    			}
			fclose($pipes[1]); //stdout
    			fclose($pipes[2]); //stderr
			proc_close($process);
    			
		}
		unlink($stdin);

		return $executed;
	}
}
?>