<?php

/**
 * Wikipedia formatting to HTML translator
 *
 * Parses input and return formatted HTML output based on Wiki formatting.
 * Implements State design pattern to switch between editing modes.
 * To add custom translator mode use register() method.
 * To remove existing mode use unregister() method.
 *
 * @version DR1.7
 */
class WikiTranslator implements ITranslator {



	protected $mode;
	protected $out = array();
	protected $toc;
	protected $registeredModes = array(
		'WikiTranslatorHeadingMode',
		'WikiTranslatorListMode',
		'WikiTranslatorPreformattedMode',
		'WikiTranslatorToCMode'
	);



	/**
	 * Constructor
	 *
	 * Creates Table of Contents object for use with WikiTranslatorHeadingMode objects.
	 */
	public function __construct() {
		$this->toc = new WikiTranslatorToC();
	}



	/**
	 * Registers translator mode class name for inclusion
	 *
	 * Use this method to add custom modes. Mode class must implement
	 * public static method buidIfMatch(string, WikiTranslatorToC)
	 * that returns mode instance if passed string matches activation condition.
	 */
	public function register($className) {
		if (!in_array($className, $this->registeredModes)) {
			$this->registeredModes[] = $className;
		}
	}



	/**
	 * Removes registered translator mode class name
	 *
	 * Use this method to exclude some Wiki syntax elements,
	 * e.g. unregister('WikiTanslatorHeadingMode') will ignore all headings.
	 */
	public function unregister($className) {
		if (false !== ($pos = array_search($className, $this->registeredModes))) {
			unset($this->registeredModes[$pos]);
		}
	}



	/**
	 * Does no converion from view to model, saves as Wiki text
	 */
	public function vtom($value) {
		return $value;
	}



	/**
	 * Converts from Wiki text to HTML
	 */
	public function mtov($value) {
		foreach (explode("\n", $value) as $ln) {
			// unset mode if empty line given and proceed to next line
			if ($ln == '') {
				$this->mode = null;
				continue;
			}
			$mode = null;
			// perform mode recognition
			foreach ($this->registeredModes as $className) {
				eval('$mode = ' . $className . '::buildIfMatch($ln, $this->toc);');
				if ($mode) {
					$this->setMode($mode);
					break;
				}
			}
			// if no mode matched the string, use text mode
			if (!$mode) {
				$this->setMode(new WikiTranslatorTextMode());
			}
			$this->out[] = $this->mode->parse($ln);
		}
		// close pending modes and return HTML
		$this->setMode(new WikiTranslatorTextMode());
		return implode("\n", $this->out);
	}




	/**
	 * Switches parser mode to handle given Wiki syntax element
	 *
	 * @param WikiTranslatorMode
	 */
	protected function setMode(WikiTranslatorMode $mode) {
		if (get_class($mode) == get_class($this->mode)) {
			return;
		}
		if ($this->mode) {
			$this->out[] = $this->mode->close();
		}
		$this->mode = $mode;
		$this->out[] = $this->mode->open();
	}



} // class WikiTranslator

?>