<?php

/**
 * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @package fusionLib
 * @copyright Copyright (c) 2007 - 2016 fusionLib. All rights reserved.
 * @link http://fusionlib.com
 */

/**
 * flFormElementWYSIWYGModule Class
 *
 * Base class for WYSIWYG editors.
 *
 * @package fusionLib
 */
abstract class flFormElementWYSIWYGModule {

	/**
	 * The host form for the element.
	 *
	 * @var flForm
	 */
	protected $form;

	/**
	 * The name of the element being used.
	 *
	 * @var string
	 */
	protected $name;

	/**
	 * flFormElementWYSIWYGModule constructor.
	 *
	 * @param flForm $form The host form object.
	 * @param string $name The name of the form element.
	 */
	function __construct($form, $name) {
		$this->form = $form;
		$this->name = $name;
	}

	/**
	 * Get the CSS class to add to the textarea.
	 *
	 * @return string The CSS class or null if not used.
	 */
	abstract function getCSSClass();

	/**
	 * Get if dimensions must be included in the style of the textarea.
	 *
	 * @return bool true if dimensions in style attribute; else false.
	 */
	abstract function dimensionsInStyle();

	/**
	 * Render the editor code.
	 *
	 * @param flDb $db The database object.
	 * @param flBufferCode $codeBuffer The code buffer.
	 * @param array $settings The array of settings for editor.
	 * @return string The HTML for inclusion.
	 */
	abstract function render($db, $codeBuffer, $settings);

	/**
	 * Transform the text read from the editor.
	 *
	 * @param $text string The editor text to transform.
	 * @return string The transformed text.
	 */
	function transformGet($text) {
		return $text;
	}

	/**
	 * Transform the text written to the editor.
	 *
	 * @param $text string The editor text to transform.
	 * @return string The transformed text.
	 */
	function transformPut($text) {
		return $text;
	}

	/**
	 * Render before the editor.
	 *
	 * @param flDb $db The database object.
	 * @param flBufferCode $codeBuffer The code buffer.
	 * @param array $settings The array of settings for editor.
	 * @return string The HTML for inclusion.
	 */
	function preRender($db, $codeBuffer, $settings) {
		return '';
	}

	/**
	 * Render after the editor.
	 *
	 * @param flDb $db The database object.
	 * @param flBufferCode $codeBuffer The code buffer.
	 * @param array $settings The array of settings for editor.
	 * @return string The HTML for inclusion.
	 */
	function postRender($db, $codeBuffer, $settings) {
		return '';
	}
}

/**
 * flFormElementWYSIWYGCodeModule Class
 *
 * Base class for code editors.
 *
 * @package fusionLib
 */
abstract class flFormElementWYSIWYGCodeModule extends flFormElementWYSIWYGModule {
}

/**
 * flFormElementWYSIWYG Class
 *
 * WYSIWYG text input form element.
 *
 * @package fusionLib
 */
class flFormElementWYSIWYG extends flFormElementTextArea {

	/**
	 * The instance of the module to load the editor from.
	 *
	 * @var flFormElementWYSIWYGModule
	 */
	protected $module = null;

	/**
	 * The name of the module.
	 *
	 * @var string
	 */
	protected $moduleName = '';

	/**
	 * Editor settings.
	 *
	 * @var array
	 */
	protected $settings = array(
		'css' => '',
		'internalLinks' => '',
		'fileBrowser' => '',
		'tags' => array(),
		'width' => '100%',
		'height' => '450',
		'contentType' => 'html',
		'allowFullScreen' => true,
		'readOnly' => false
	);

	/**
	 * The style to apply.
	 *
	 * @var string
	 */
	protected $style = '';

	/**
	 * The database object.
	 *
	 * @var type
	 */
	protected $db = null;

	/**
	 * Set database to use.
	 *
	 * @param flDb $db  The database object.
	 * @return flFormElementWYSIWYG This Object.
	 */
	function setDB($db) {
		$this->db = $db;
		return $this;
	}

	/**
	 * Set the editor module to use.
	 *
	 * @param string $module The name of the editor module to use.
	 * @return flFormElementWYSIWYG This Object.
	 */
	function editorModule($module) {
		// Create the object
		try {
			$cls = "{$module}WYSIWYG";
			$this->module = new $cls($this->form, $this->name);
			$this->moduleName = $module;
		} catch(flExceptionLoadClass $e) {
			$this->module = null;
		}

		return $this;
	}

	/**
	 * Set the URI of the file to load style from.
	 *
	 * @param string $css The URI of the CSS file to include in the editor.
	 * @return flFormElementWYSIWYG This Object.
	 */
	function editorCSS($css) {
		$this->settings['css'] = $css;
		return $this;
	}

	/**
	 * Set the URI of the script used to generate internal links.
	 *
	 * @param string $uri The script location.
	 * @return flFormElementWYSIWYG This object.
	 */
	function editorInternalLinks($uri) {
		$this->settings['internalLinks'] = $uri;
		return $this;
	}

	/**
	 * Set the URI of the script to browse files.
	 *
	 * @param string $uri The script location.
	 * @return flFormElementWYSIWYG This object.
	 */
	function editorFileBrowser($uri) {
		$this->settings['fileBrowser'] = $uri;
		return $this;
	}

	/**
	 * Add a custom tag to the editor.
	 *
	 * @param string $name The display name of the tag.
	 * @param string $tag The tag to insert.
	 * @return flFormElementWYSIWYG This object.
	 */
	function editorAddTag($name, $tag) {
		$this->settings['tags'][] = "['" . fusionLib::htmlChars($name) . "', '" . str_replace(array('[', ']'), array('&#91;', '&#93;'), fusionLib::htmlChars($tag)) . "']";
		return $this;
	}

	/**
	 * Set the dimensions of the editor.
	 *
	 * @param string $w The width, e.g. 100% or 450.
	 * @param string $h The height.
	 * @return flFormElementWYSIWYG This object.
	 */
	function editorSize($w, $h) {
		$this->settings['width'] = $w;
		$this->settings['height'] = $h;
		return $this;
	}

	/**
	 * Set the type of content that the editor is working on.
	 *
	 * @param string $type The content type, 'html', 'chunk', 'snippet', 'xml', 'text', 'css' or mime type.
	 * @return flFormElementWYSIWYG This object.
	 */
	function editorContentType($type) {
		$this->settings['contentType'] = $type;
		return $this;
	}

	/**
	 * Get the escaped value, HTML elements and the characters [ ] are escaped.
	 *
	 * @return string The escaped value.
	 */
	protected function _getValueEscaped() {
		$r = parent::_getValueEscaped();

		if($this->module && !$this->module instanceof flFormElementWYSIWYGCodeModule) {
			$r = $this->module->transformPut($r);

			// Make URIs absolute from the root.
			return preg_replace('/(href|src)=&quot;(?!\/|https?|&#91;&#91;)/s', '\1="' . $this->form->getRequest()->getBasePath(), $r);
		}

		return $r;
	}

	/**
	 * Get the value of the element.
	 *
	 * @return string The value.
	 */
	function getValue() {
		// Make URIs relative that are absolute from the root and fix up http://[[ to just [[
		$r = preg_replace('/"' . preg_quote($this->form->getRequest()->getBasePath(), '/') . '/', '"', preg_replace('#="https?://\[\[#s', '="[[', parent::getValue()));
		return $this->module ? $this->module->transformGet($r) : $r;
	}

	/**
	 * Generate the HTML for common attributes.
	 *
	 * @return string HTML attributes.
	 */
	function attribHTML() {
		return parent::attribHTML() . $this->style;
	}

	/**
	 * Draw the element.
	 *
	 * @return string The HTML.
	 */
	function render() {
		if($this->module) {
			$this->setData('wysiwyg-editor', $this->moduleName);
			$this->setData('floating-label', 'disabled');

			$this->settings['readOnly'] = $this->readonly;

			$saveCSS = $this->class;
			if(($css = $this->module->getCSSClass()) !== null)
				$this->class = $css;

			if($this->module->dimensionsInStyle())
				$this->style = ' style="width: ' . $this->settings['width'] . (substr($this->settings['width'], -1) == '%' ? '' : 'px') . '; height: ' . $this->settings['height'] . (substr($this->settings['height'], -1) == '%' ? '' : 'px') . ';"';

			$html = $this->module->preRender($this->db, $this->form->getCodeBuffer(), $this->settings) . parent::render() . $this->module->render($this->db, $this->form->getCodeBuffer(), $this->settings) . $this->module->postRender($this->db, $this->form->getCodeBuffer(), $this->settings);

			$this->class = $saveCSS;
		}
		else
			$html = parent::render();

		return $html;
	}
}
