<?php
/**
 * Provides the ECML service to plugins.
 *
 * @package ECML
 * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
 * @author Curverider Ltd
 * @copyright Curverider Ltd 2008-2010
 * @link http://elgg.org/
 *
 * @todo
 *	Granular access to keywords based upon view.
 *	Update docs / help
 * 	Check for SQL injection problems.
 * 	Check entity keyword views against fullview.  Force to FALSE?
 */

/**
 * Init ECML
 */
function ecml_init() {
	require_once(dirname(__FILE__) . '/ecml_functions.php');
	global $CONFIG;

	define('ECML_ATTR_SEPARATOR', ' ');
	define('ECML_ATTR_OPERATOR', '=');

	// find alphanumerics (keywords) possibly followed by everything that is not a ] (args) and all surrounded by [ ]s
	define('ECML_KEYWORD_REGEX', '/\[([a-z0-9\.]+)([^\]]+)?\]/');

	// help page
	register_page_handler('ecml', 'ecml_help_page_handler');

	// admin access page
	register_page_handler('ecml_admin', 'ecml_admin_page_handler');

	// ecml validator for embed
	register_page_handler('ecml_generate', 'ecml_generate_page_handler');

	// CSS for admin access
	elgg_extend_view('css', 'ecml/admin/css');

	// admin action to save permissions
	register_action('settings/ecml/save', FALSE, dirname(__FILE__) . '/actions/save_permissions.php', TRUE);

	// show ECML-enabled icon on free-text input areas
	//elgg_extend_view('input/longtext',  'ecml/input_ext', 0);
	//elgg_extend_view('input/plaintext', 'ecml/input_ext');
	//elgg_extend_view('input/text', 'ecml/input_ext');

	// add parsing for core views.
	register_plugin_hook('get_views', 'ecml', 'ecml_views_hook');

	// get register the views we want to parse for ecml
	// @todo will need to do profiling to see if it would be faster
	// to foreach through this list and register to specific views or
	// do the check in a single plugin hook.
	// Wants array('view_name' => 'Short Description')
	$CONFIG->ecml_parse_views = trigger_plugin_hook('get_views', 'ecml', NULL, array());

	foreach ($CONFIG->ecml_parse_views as $view => $desc) {
		register_plugin_hook('view', $view, 'ecml_parse_view');
	}

	// provide a few built-in ecml keywords.
	// @todo could pull this out into an array here to save an API call.
	register_plugin_hook('get_keywords', 'ecml', 'ecml_keyword_hook');

	// grab the list of keywords and their views from plugins
	$CONFIG->ecml_keywords = trigger_plugin_hook('get_keywords', 'ecml', NULL, array());

	// grab permissions for specific views/contexts
	// this is a black list.
	// it's more efficient to use this as a blacklist
	// but probably makes more sense from a UI perspective as a whitelist.
	// uses [views][view_name] = array(keywords, not, allowed)
	$CONFIG->ecml_permissions = unserialize(get_plugin_setting('ecml_permissions', 'ecml'));

	// 3rd party media embed section
	register_plugin_hook('embed_get_sections', 'all', 'ecml_embed_web_services_hook');

	// remove ecml when stripping tags
	register_plugin_hook('format', 'strip_tags', 'ecml_strip_tags');
}

/**
 * Display a help page for valid ECML keywords on this page.
 *
 * @param array $page
 */
function ecml_help_page_handler($page) {
	if (!isset($page[0]) || empty($page[0])) {
		$content = elgg_view('ecml/help');
		$body = elgg_view_layout('one_column_with_sidebar', $content);
		echo page_draw(elgg_echo('ecml:help'), $body);
	} else {
		// asking for detailed help about a keyword
		$keyword = $page[0];
		$content = elgg_view('ecml/keyword_help', array('keyword' => $keyword));

		if (get_input('ajax', FALSE)) {
			echo $content;
			exit;
		} else {
			$body = elgg_view_layout('one_column_with_sidebar', $content);
			echo page_draw(elgg_echo('ecml:help'), $body);
		}
	}

	return TRUE;
}

/**
 * Generate ECML given a URL or embed link and service.
 * Doesn't check if the resource actually exists.
 * Outputs JSON.
 *
 * @param unknown_type $page
 */
function ecml_generate_page_handler($page) {
	$service = trim(get_input('service'));
	$resource = trim(get_input('resource'));

	// if standard ECML is passed, guess the service from that instead
	// only support one.
	if (elgg_substr($resource, 0, 1) == '[') {
		if ($keywords = ecml_extract_keywords($resource)) {
			$keyword = $keywords[0]['keyword'];
			$ecml_info = ecml_get_keyword_info($keyword);
			$html = ecml_parse_string($resource);

			echo json_encode(array(
				'status' => 'success',
				'ecml' => $resource,
				'html' => $html
			));

			exit;
		}
	}

	if (!$service || !$resource) {
		echo json_encode(array(
			'status' => 'error',
			'message' => elgg_echo('ecml:embed:invalid_web_service_keyword')
		));

		exit;
	}

	$ecml_info = ecml_get_keyword_info($service);

	if ($ecml_info) {
		// don't allow embedding for restricted.
		if (isset($ecml_info['restricted'])) {
			$result = array(
				'status' => 'error',
				'message' => elgg_echo('ecml:embed:cannot_embed'),
			);
		} else {
			// @todo pull this out into a function.  allow optional arguments.
			$ecml = "[$service " . sprintf($ecml_info['embed_format'], $resource) . ']';
			$html = ecml_parse_string($ecml, NULL);
			$result = array(
				'status' => 'success',
				'ecml' => $ecml,
				'html' => $html
			);
		}
	} else {
		$result = array(
			'status' => 'error',
			'message' => elgg_echo('ecml:embed:invalid_web_service_keyword')
		);
	}

	echo json_encode($result);
	exit;
}

/**
 * Display a admin area for ECML
 *
 * @param array $page
 */
function ecml_admin_page_handler($page) {
	admin_gatekeeper();
	set_context('admin');
	$content = elgg_view('ecml/admin/ecml_admin');
	$body = elgg_view_layout('one_column_with_sidebar', $content);
	echo page_draw(elgg_echo('ecml:admin'), $body);
}

/**
 * Parses a registered view / context for supported keywords.
 *
 * @param unknown_type $hook
 * @param unknown_type $entity_type
 * @param unknown_type $return_value
 * @param unknown_type $params
 * @return string
 */
function ecml_parse_view($hook, $entity_type, $return_value, $params) {
	global $CONFIG;

	return ecml_parse_string($return_value, $params['view']);
}


/**
 * Register default keywords.
 *
 * @param unknown_type $hook
 * @param unknown_type $type
 * @param unknown_type $value
 * @param unknown_type $params
 * @return unknown_type
 */
function ecml_keyword_hook($hook, $type, $value, $params) {
	// I keep going back and forth about entity and view. They're powerful, but
	// a great way to let a site get hacked if the admin doesn't lock them down.
	$keywords = array(
		'youtube' => array('params' => array('src', 'width', 'height'), 'embed_format' => 'src="%s"'),
		'slideshare' => array('params' => array('id', 'width', 'height'), 'embed_format' => 'id="%s"'),
		'vimeo' => array('params' => array('src', 'width', 'height'), 'embed_format' => 'src="%s"'),
		'googlemaps' => array('params' => array('src', 'width', 'height'), 'embed_format' => 'src="%s"'),
		//'scribd'
		'blip.tv' => array('params' => array('width', 'height'), 'embed_format' => '%s'),
		'dailymotion' => array('params' => array('src', 'width', 'height'), 'embed_format' => 'src="%s"'),
		'livevideo' => array('params' => array('src', 'width', 'height'), 'embed_format' => 'src="%s"'),
		'redlasso' => array('params' => array('id', 'width', 'height'), 'embed_format' => 'id="%s"'),
	);

	foreach ($keywords as $keyword => $info) {
		$value[$keyword] = array(
			'name' => elgg_echo("ecml:keywords:$keyword"),
			'view' => "ecml/keywords/$keyword",
			'description' => elgg_echo("ecml:keywords:$keyword:desc"),
			'usage' => elgg_echo("ecml:keywords:$keyword:usage"),
			'type' => 'web_service',
			'params' => $info['params'],
			'embed_format' => $info['embed_format']
		);
	}

	// default entity keyword
	$value['entity'] = array(
		'name' => elgg_echo('ecml:keywords:entity'),
		'view' => "ecml/keywords/entity",
		'description' => elgg_echo("ecml:keywords:entity:desc"),
		'usage' => elgg_echo("ecml:keywords:entity:usage")
	);

	return $value;
}

/**
 * Register default views to parse
 *
 * @param unknown_type $hook
 * @param unknown_type $type
 * @param unknown_type $value
 * @param unknown_type $params
 */
function ecml_views_hook($hook, $type, $value, $params) {
	$value['annotation/generic_comment'] = elgg_echo('ecml:views:annotation_generic_comment');

	return $value;
}

/**
 * Show the special Web Services embed section.
 *
 * @param unknown_type $hook
 * @param unknown_type $type
 * @param unknown_type $value
 * @param unknown_type $params
 */
function ecml_embed_web_services_hook($hook, $type, $value, $params) {
	// we're using a view override for this section's content
	// so only need to pass the name.
	$value['web_services'] = array(
		'name' => elgg_echo('ecml:embed:web_services')
	);

	return $value;
}

/**
 * Remove ecml code for elgg_strip_tags()
 *
 * @param unknown_type $hook
 * @param unknown_type $type
 * @param unknown_type $value
 * @param unknown_type $params
 */
function ecml_strip_tags($hook, $type, $value, $params) {
	return preg_replace(ECML_KEYWORD_REGEX, '', $value);
}

// be sure to run after other plugins
register_elgg_event_handler('init', 'system', 'ecml_init', 9999);