<?php

###############################################################################
#
# Dune STB API
#
# Данный модуль является сборником определений и простейших функций для
# удобного взаимодействия со встроенным Dune HD GUI Framework в php-плагинах.
# На полноценный API модуль не претендует, хотя по функционалу и возможностям
# близок к Dune JavaScript STB API.
#
# Использование модуля в своих проектах не возбраняется. Сторонняя помощь в
# развитии модуля всячески приветствуется. Замечания можно отправлять на
# brigadir@mydune.ru
#
# Автор (Author): Brigadir (forum.mydune.ru)
# Дата (Date): 23-07-2017
# Последнее обновление (Latest update): 25-10-2019
#
# PS: На разных прошивках отдельные части функционала могут не работать
# (надеюсь это будет исправляться с выходом новых).
#
###############################################################################

# Command execution status values
define('COMMAND_STATUS_SUCCESS',							'ok');
define('COMMAND_STATUS_FAIL',								'failed');
define('COMMAND_STATUS_TIMEOUT',							'timeout');

# Adding GUI event key defs
define('GUI_EVENT_KEY_DISCRETE_POWER_ON',					'key_power_on');
define('GUI_EVENT_KEY_DISCRETE_POWER_OFF',					'key_power_off');

# Standby modes
define('STANDBY_MODE_OFF',									0);
define('STANDBY_MODE_ON',									1);

# Zoom presets
define('VIDEO_ZOOM_NORMAL',									'normal');
define('VIDEO_ZOOM_ENLARGE',								'enlarge');
define('VIDEO_ZOOM_MAKE_WIDER',								'make_wider');
define('VIDEO_ZOOM_NON_LINEAR_STRETCH',						'fill_screen');
define('VIDEO_ZOOM_NON_LINEAR_STRETCH_TO_FULL_SCREEN',		'full_fill_screen');
define('VIDEO_ZOOM_MAKE_TALLER',							'make_taller');
define('VIDEO_ZOOM_CUT_EDGES',								'cut_edges');
define('VIDEO_ZOOM_FULL_SCREEN',							'full_enlarge');
define('VIDEO_ZOOM_STRETCH_TO_FULL_SCREEN',					'full_stretch');

# Player states
define('PLAYER_STATE_STANDBY',								'standby');
define('PLAYER_STATE_BLACK_SCREEN',							'black_screen');
define('PLAYER_STATE_NAVIGATOR',							'navigator');
define('PLAYER_STATE_FILE_PLAYBACK',						'file_playback');
define('PLAYER_STATE_DVD_PLAYBACK',							'dvd_playback');
define('PLAYER_STATE_BLURAY_PLAYBACK',						'bluray_playback');

# Playback states
define('PLAYBACK_STATE_STOPPED',							'stopped');
define('PLAYBACK_STATE_INITIALIZING',						'initializing');
define('PLAYBACK_STATE_PLAYING',							'playing');
define('PLAYBACK_STATE_PAUSED',								'paused');
define('PLAYBACK_STATE_SEEKING',							'seeking');
define('PLAYBACK_STATE_BUFFERING',							'buffering');
define('PLAYBACK_STATE_FINISHED',							'finished');
define('PLAYBACK_STATE_DEINITIALIZING',						'deinitializing');

# Mounted storages path
define('DUNE_MOUNTED_STORAGES_PATH',						'/tmp/mnt/storage/');

# Hard-coded constants.
if (!defined('FONT_SIZE_LARGE'))				define('FONT_SIZE_LARGE',			4);
if (!defined('ORIENTATION_VERTICAL'))			define('ORIENTATION_VERTICAL',		0);
if (!defined('ORIENTATION_HORIZONTAL'))			define('ORIENTATION_HORIZONTAL',	1);
if (!defined('CYCLE_MODE_GAP_AUTO'))			define('CYCLE_MODE_GAP_AUTO',		0);
if (!defined('CYCLE_MODE_GAP_YES'))				define('CYCLE_MODE_GAP_YES',		1);
if (!defined('CYCLE_MODE_GAP_NO'))				define('CYCLE_MODE_GAP_NO',			2);

# Gui Event Keys
if (!defined('GUI_EVENT_KEY_FWD'))				define ('GUI_EVENT_KEY_FWD',			'key_fwd');
if (!defined('GUI_EVENT_KEY_REW'))				define ('GUI_EVENT_KEY_REW',			'key_rew');
if (!defined('GUI_EVENT_KEY_SLOW'))				define ('GUI_EVENT_KEY_SLOW',			'key_slow');
if (!defined('GUI_EVENT_KEY_STOP'))				define ('GUI_EVENT_KEY_STOP',			'key_stop');
if (!defined('GUI_EVENT_KEY_TOP_MENU'))			define ('GUI_EVENT_KEY_TOP_MENU',		'key_top_menu');
if (!defined('GUI_EVENT_KEY_POWER'))			define ('GUI_EVENT_KEY_POWER',			'key_power');
if (!defined('GUI_EVENT_KEY_EJECT'))			define ('GUI_EVENT_KEY_EJECT',			'key_eject');
if (!defined('GUI_EVENT_KEY_MODE'))				define ('GUI_EVENT_KEY_MODE',			'key_mode');
if (!defined('GUI_EVENT_KEY_VENDOR'))			define ('GUI_EVENT_KEY_VENDOR',			'key_vendor');
if (!defined('GUI_EVENT_KEY_SHUFFLE'))			define ('GUI_EVENT_KEY_SHUFFLE',		'key_shuffle');
if (!defined('GUI_EVENT_KEY_MUSIC'))			define ('GUI_EVENT_KEY_MUSIC',			'key_music');
if (!defined('GUI_EVENT_KEY_MUTE'))				define ('GUI_EVENT_KEY_MUTE',			'key_mute');
if (!defined('GUI_EVENT_KEY_V_PLUS'))			define ('GUI_EVENT_KEY_V_PLUS',			'key_v_plus');
if (!defined('GUI_EVENT_KEY_V_MINUS'))			define ('GUI_EVENT_KEY_V_MINUS',		'key_v_minus');
if (!defined('GUI_EVENT_KEY_SEARCH'))			define ('GUI_EVENT_KEY_SEARCH',			'key_search');
if (!defined('GUI_EVENT_KEY_ZOOM'))				define ('GUI_EVENT_KEY_ZOOM',			'key_zoom');
if (!defined('GUI_EVENT_KEY_SUBTITLE'))			define ('GUI_EVENT_KEY_SUBTITLE',		'key_subtitle');
if (!defined('GUI_EVENT_KEY_REPEAT'))			define ('GUI_EVENT_KEY_REPEAT',			'key_repeat');
if (!defined('GUI_EVENT_KEY_AUDIO'))			define ('GUI_EVENT_KEY_AUDIO',			'key_audio');
if (!defined('GUI_EVENT_KEY_REC'))				define ('GUI_EVENT_KEY_REC',			'key_rec');
if (!defined('GUI_EVENT_KEY_DUNE'))				define ('GUI_EVENT_KEY_DUNE',			'key_dune');
if (!defined('GUI_EVENT_KEY_URL'))				define ('GUI_EVENT_KEY_URL',			'key_url');
if (!defined('GUI_EVENT_KEY_KEYBRD'))			define ('GUI_EVENT_KEY_KEYBRD',			'key_keybrd');
if (!defined('GUI_EVENT_KEY_MOUSE'))			define ('GUI_EVENT_KEY_MOUSE',			'key_mouse');
if (!defined('GUI_EVENT_KEY_RECENT'))			define ('GUI_EVENT_KEY_RECENT',			'key_recent');
if (!defined('GUI_EVENT_KEY_TV'))				define ('GUI_EVENT_KEY_TV',				'key_tv');
if (!defined('GUI_EVENT_KEY_MOVIES'))			define ('GUI_EVENT_KEY_MOVIES',			'key_movies');
if (!defined('GUI_EVENT_KEY_MUSIC'))			define ('GUI_EVENT_KEY_MUSIC',			'key_music');
if (!defined('GUI_EVENT_KEY_ANGLE'))			define ('GUI_EVENT_KEY_ANGLE',			'key_angle');
# Discrete Power Control
if (!defined('GUI_EVENT_DISCRETE_POWER_ON'))	define ('GUI_EVENT_DISCRETE_POWER_ON',	'key_discrete_power_on');
if (!defined('GUI_EVENT_DISCRETE_POWER_OFF'))	define ('GUI_EVENT_DISCRETE_POWER_OFF',	'key_discrete_power_off');

# Dune colors consts.
# Common:
define('DEF_LABEL_TEXT_COLOR_BLACK',			0);  #0x000000	Black						IPTV plugin playback time and number of EPG item
define('DEF_LABEL_TEXT_COLOR_BLUE',				1);  #0x0000a0	Blue						unknown
define('DEF_LABEL_TEXT_COLOR_PALEGREEN',		2);  #0xc0e0c0	Light light grin			unknown
define('DEF_LABEL_TEXT_COLOR_LIGHTBLUE',		3);  #0xa0c0ff	Light blue					unknown
define('DEF_LABEL_TEXT_COLOR_RED',				4);  #0xff4040	Red							Symbol R Recorded Channel Kartina TV
define('DEF_LABEL_TEXT_COLOR_LIMEGREEN',		5);  #0xc0ff40	Light green					unknown
define('DEF_LABEL_TEXT_COLOR_GOLD',				6);  #0xffe040	Light yellow				unknown
define('DEF_LABEL_TEXT_COLOR_SILVER',			7);  #0xc0c0c0	Light grey					File browser (right subdescription)
define('DEF_LABEL_TEXT_COLOR_GRAY',				8);  #0x808080	Grey						IPTV plugin playback, categories
define('DEF_LABEL_TEXT_COLOR_VIOLET',			9);  #0x4040c0	Violet						unknown
define('DEF_LABEL_TEXT_COLOR_GREEN',			10); #0x40ff40	Green						VOD description rating(IMDB..)
define('DEF_LABEL_TEXT_COLOR_TURQUOISE',		11); #0x40ffff	Cyan						unknown
define('DEF_LABEL_TEXT_COLOR_ORANGE',			12); #0xff8040	Orange						unknown
define('DEF_LABEL_TEXT_COLOR_MAGENTA',			13); #0xff40ff	Purple						unknown
define('DEF_LABEL_TEXT_COLOR_LIGHTYELLOW',		14); #0xffff40	Light yellow				Widget(time, temp), path (last item), mesagges, IPTV playback (channels number, )
define('DEF_LABEL_TEXT_COLOR_WHITE',			15); #0xffffe0	White						Main color, widget, combobox etc
# Extra:
define('DEF_LABEL_TEXT_COLOR_DARKGRAY',			16); #0x404040	Dark grey					Color buttons,
define('DEF_LABEL_TEXT_COLOR_DIMGRAY',			17); #0xaaaaa0	Grey						Some VOD description text
define('DEF_LABEL_TEXT_COLOR_YELLOW',			18); #0xffff00	Yellow						VOD descr
define('DEF_LABEL_TEXT_COLOR_LIGHTGREEN',		19); #0x50ff50	Green						VOD descr
define('DEF_LABEL_TEXT_COLOR_SKYBLUE',			20); #0x5080ff	Blue						VOD descr
define('DEF_LABEL_TEXT_COLOR_CORAL',			21); #0xff5030	Light red					VOD descr
define('DEF_LABEL_TEXT_COLOR_DARKGRAY2',		22); #0x404040	Dark grey					VOD descr
define('DEF_LABEL_TEXT_COLOR_GAINSBORO',		23); #0xe0e0e0	Light light light grey		P+ P-

///////////////////////////////////////////////////////////////////////////////

# Use this class instead of ViewItemParams for compatibility
class FolderViewItemParams extends ViewItemParams
{
	const /* MY_Bool                          */ item_override_default_badge      = 'item_override_default_badge';
	const /* NonNegativeInt                   */ item_detailed_icon_width         = 'item_detailed_icon_width';
	const /* NonNegativeInt                   */ item_detailed_icon_height        = 'item_detailed_icon_height';
}

# Use this class instead of ViewParams for compatibility
class FolderViewParams extends ViewParams
{
	const /* PositiveInt                      */ cycle_mode_gap_width             = 'cycle_mode_gap_width';
	const /* ImagePath                        */ cycle_mode_gap_icon_path         = 'cycle_mode_gap_icon_path';
	const /* MY_Bool                          */ paint_playback_help_line         = 'paint_playback_help_line';
	const /* MY_Bool                          */ paint_playback_status            = 'paint_playback_status';
	const /* MY_Bool                          */ paint_playback_volume_indicators = 'paint_playback_volume_indicators';
	const /* MY_Bool                          */ item_detailed_info_use_main_icon = 'item_detailed_info_use_main_icon';
	const /* NonNegativeInt                   */ max_icon_width                   = 'max_icon_width';
	const /* NonNegativeInt                   */ max_icon_height                  = 'max_icon_height';
}

class ExtTvChannel extends PluginTvChannel
{
    const /* bool                             */ ext_epg_enabled                  = 'ext_epg_enabled';
    const /* (char *)                         */ ext_epg_id                       = 'ext_epg_id';
    const /* (char *)                         */ ext_epg_icon_url                 = 'ext_epg_icon_url';
    const /* int                              */ epg_icon_width                   = 'epg_icon_width';
    const /* int                              */ epg_icon_height                  = 'epg_icon_height';
    const /* int                              */ epg_icon_x_offset                = 'epg_icon_x_offset';
    const /* int                              */ epg_icon_y_offset                = 'epg_icon_y_offset';
}

# Video zoom values for media_url string (|||dune_params|||zoom:value)
class DuneParamsVideoZoom
{
	const	normal						=	'0';
	const	enlarge						=	'1';
	const	make_wider					=	'2';
	const	fill_screen					=	'3';
	const	full_fill_screen			=	'4';
	const	make_taller					=	'5';
	const	cut_edges					=	'6';
	const	full_enlarge				=	'8';
	const	full_stretch				=	'9';
}

# Deinterlacing modes for media_url string (|||dune_params|||deint:value)
class DuneParamsDeintMode
{
	const	off							=	'1';
	const	bob							=	'0';
	const	adaptive					=	'4';
	const	adaptive_plus				=	'5';
}

class DuneIrControl
{
	static $key_codes = array(
			GUI_EVENT_KEY_VENDOR			=> '0',
			GUI_EVENT_KEY_ENTER				=> 'EB14BF00',
			GUI_EVENT_KEY_PLAY				=> 'B748BF00',
			GUI_EVENT_KEY_A_RED				=> 'BF40BF00',
			GUI_EVENT_KEY_B_GREEN			=> 'E01FBF00',
			GUI_EVENT_KEY_C_YELLOW			=> 'FF00BF00',
			GUI_EVENT_KEY_D_BLUE			=> 'BE41BF00',
			GUI_EVENT_KEY_POPUP_MENU		=> 'F807BF00',
			GUI_EVENT_KEY_INFO				=> 'AF50BF00',
			GUI_EVENT_KEY_LEFT				=> 'E817BF00',
			GUI_EVENT_KEY_RIGHT				=> 'E718BF00',
			GUI_EVENT_KEY_UP				=> 'EA15BF00',
			GUI_EVENT_KEY_DOWN				=> 'E916BF00',
			GUI_EVENT_KEY_P_PLUS			=> 'B44BBF00',
			GUI_EVENT_KEY_P_MINUS			=> 'B34CBF00',
			GUI_EVENT_KEY_NEXT				=> 'E21DBF00',
			GUI_EVENT_KEY_PREV				=> 'B649BF00',
			GUI_EVENT_KEY_SETUP				=> 'B14EBF00',
			GUI_EVENT_KEY_RETURN			=> 'FB04BF00',
			GUI_EVENT_KEY_SELECT			=> 'BD42BF00',
			GUI_EVENT_KEY_CLEAR				=> 'FA05BF00',
			GUI_EVENT_KEY_PAUSE				=> 'E11EBF00',
			GUI_EVENT_KEY_FWD				=> 'E41BBF00',
			GUI_EVENT_KEY_REW				=> 'E31CBF00',
			GUI_EVENT_KEY_SLOW				=> 'E51ABF00',
			GUI_EVENT_KEY_STOP				=> 'E619BF00',
			GUI_EVENT_KEY_TOP_MENU			=> 'AE51BF00',
			GUI_EVENT_KEY_POWER				=> 'BC43BF00',
			GUI_EVENT_KEY_EJECT				=> 'EF10BF00',
			GUI_EVENT_KEY_MODE				=> 'BA45BF00',
			GUI_EVENT_KEY_MUTE				=> 'B946BF00',
			GUI_EVENT_KEY_V_PLUS			=> 'AD52BF00',
			GUI_EVENT_KEY_V_MINUS			=> 'AC53BF00',
			GUI_EVENT_KEY_SEARCH			=> 'F906BF00',
			GUI_EVENT_KEY_ZOOM				=> 'FD02BF00',
			GUI_EVENT_KEY_SUBTITLE			=> 'AB54BF00',
			GUI_EVENT_KEY_REPEAT			=> 'B24DBF00',
			GUI_EVENT_KEY_AUDIO				=> 'BB44BF00',
			GUI_EVENT_KEY_REC				=> '9F60BF00',
			GUI_EVENT_KEY_DUNE				=> '9E61BF00',
			GUI_EVENT_KEY_URL				=> '9D62BF00',
			GUI_EVENT_KEY_0					=> 'F50ABF00',
			GUI_EVENT_KEY_1					=> 'F40BBF00',
			GUI_EVENT_KEY_2					=> 'F30CBF00',
			GUI_EVENT_KEY_3					=> 'F20DBF00',
			GUI_EVENT_KEY_4					=> 'F10EBF00',
			GUI_EVENT_KEY_5					=> 'F00FBF00',
			GUI_EVENT_KEY_6					=> 'FE01BF00',
			GUI_EVENT_KEY_7					=> 'EE11BF00',
			GUI_EVENT_KEY_8					=> 'ED12BF00',
			GUI_EVENT_KEY_9					=> 'EC13BF00',
			GUI_EVENT_KEY_SHUFFLE			=> 'B847BF00',
			GUI_EVENT_KEY_KEYBRD			=> 'FC03BF00',
			GUI_EVENT_KEY_MOUSE				=> 'B04FBF00',
			GUI_EVENT_KEY_RECENT			=> '9E61BF00',
			GUI_EVENT_KEY_TV				=> '9C63BF00',
			GUI_EVENT_KEY_MOVIES			=> 'B847BF00',
			GUI_EVENT_KEY_MUSIC				=> 'A758BF00',
			GUI_EVENT_KEY_ANGLE				=> 'B24DBF00',
			GUI_EVENT_DISCRETE_POWER_ON		=> 'A05FBF00',
			GUI_EVENT_DISCRETE_POWER_OFF	=> 'A15EBF00');
}


###############################################################################
# System functions
###############################################################################

# Return: string value
function get_platform_kind()
{
	static $result = null;
	if (is_null($result))
	{
		if (getenv("HD_APK"))
			$result = 'apk';
		else	
			$result = trim(shell_exec('grep "platform_kind" /tmp/run/versions.txt | sed "s/^.*= *//"'));
	}
	return $result;
}

function get_android_platform()
{
	static $result = null;	
	if (is_null($result))
	{
		if (getenv("HD_APK"))
			$result = 'apk';
		else
		{
			$ini_arr = parse_ini_file('/tmp/run/versions.txt');
			if (isset($ini_arr['android_platform']))
				$result = $ini_arr['android_platform'];
		}
	}	
	return $result;
}

# Return: string value
function get_product_id()
{
	static $result = null;
	if (is_null($result))
	{
		$result = trim(shell_exec('grep "product_id:" /tmp/sysinfo.txt | sed "s/^.*: *//"'));
	}
	return $result;
}

function get_firmware_version()
{
	static $result = null;
	if (is_null($result))
		$result = trim(shell_exec('grep "firmware_version:" /tmp/sysinfo.txt | sed "s/^.*: *//"'));
	return $result;
}

# Return array, example:
#   array(
#     'string' => '150729_0139_r10_js_stb_opera33',
#     'build_date' => '150729',
#     'build_num' => '0139',
#     'branch_number' => '10',
#     'features' => 'js_stb_opera33')
function get_parsed_firmware_ver()
{
	static $result = null;
	if (is_null($result))
	{
		preg_match_all('/^(\d*)_(\d*)_\D*(\d*)(.*)$/', get_firmware_version(), $matches, PREG_SET_ORDER);
		$matches[0][4] = ltrim($matches[0][4], '_');
		$result = array_combine(array('string', 'build_date', 'build_num', 'branch_number', 'features'), $matches[0]);
	}
	return $result;
}

function get_shell_settings()
{
	if (file_exists('/config/settings.properties'))
		if ($settings = parse_ini_file('/config/settings.properties', 0, INI_SCANNER_RAW))
			return $settings;

	return array();
}

# Return: string value
function get_serial_number()
{
	static $result = null;
	if (is_null($result))
	{
	$result = trim(shell_exec('grep "serial_number:" /tmp/sysinfo.txt | sed "s/^.*: *//"'));
	}
	return $result;
}

# Return: string value
function get_ip_address()
{
	if (get_platform_kind() == '8670')
	{
		$active_network_connection = parse_ini_file('/tmp/run/active_network_connection.txt', 0, INI_SCANNER_RAW);
		if (isset($active_network_connection['ip']))
			return trim($active_network_connection['ip']);
		else return 'n/a';
 	}
 	else return trim(shell_exec('ifconfig eth0 | head -2 | tail -1 | sed "s/^.*inet addr:\([^ ]*\).*$/\1/"'));
}

# Return: string value

function get_mac_address()
{
	if (is_apk())
	{
		if ((bool) getenv("HD_FW_APK"))
			$mac_addr = trim(shell_exec('ifconfig eth0 | head -1 | sed "s/^.*HWaddr //"'));
		else
			$mac_addr = shell_exec("getprop dev.com.mft.ethmac");
	}
	else
		$mac_addr = trim(shell_exec('ifconfig eth0 | head -1 | sed "s/^.*HWaddr //"'));
	return $mac_addr;
}

function is_apk()
{
    return (bool) getenv("HD_APK");
}

# Return: integer value of offset in seconds
function get_local_time_zone_offset()
{
	exec((file_exists('/etc/TZ')? 'TZ=`cat /etc/TZ` ' : '') . 'date +%z', $tz, $rc);
	$local_tz = (($rc != 0) || (count($tz) != 1) || !is_numeric($tz[0]))? '' : $tz[0];
	if ($local_tz <> '')
	{
		$sign = 1;
		$sign_ch = substr($local_tz, 0, 1);
		if ($sign_ch == '-')
			$sign = +1;
		else if ($sign_ch == '+')
			$sign = -1;
		else return '';	
		$tz_hh = intval(substr($local_tz, 1, 2));
		$tz_mm = intval(substr($local_tz, 3, 2));	
		return $sign * ($tz_hh * 60 + $tz_mm) * 60;
	}	
	return 0;
}

# Return: array(
#			'app_name' => {value},
#			'app_caption' => {value},
#			'app_label' => {value},
#			'app_version' => {value},
#			'app_version_idx' => {value},
#			'simple_node1' => {value},
#			'simple_node2' => {value},
#			...)
function get_plugin_info()
{
	$plugin_manifest = @file_get_contents(DuneSystem::$properties['install_dir_path'] . '/dune_plugin.xml', true);	
	if (empty($plugin_manifest))
	{
		throw new Exception("Dune STB API: Plugin manifest not found!");
	}	
	$xml = parse_xml_document($plugin_manifest);
	$result = array(
	'app_name' => strval($xml->name),
	'app_caption' => strval($xml->caption),
	'app_version' => strval($xml->version),
	'app_version_idx' => isset($xml->version_index)? strval($xml->version_index) : '0');	
	foreach(func_get_args() as $node_name)
	{
		$result[$node_name] = json_decode(json_encode($xml->xpath("//$node_name")), true);
	}	
	return $result;
}

# No return value
function send_ir_code($key) {
	if (isset(DuneIrControl::$key_codes[$key]))
		shell_exec('echo ' . DuneIrControl::$key_codes[$key] . ' > /proc/ir/button');
	else
		hd_print("Error in class " . get_class($this) . "::" . __FUNCTION__ . "! Code of key '$key' not found in base!");
}

# Return: command execution status
function send_ir_code_return_status($key) {
	if (isset(DuneIrControl::$key_codes[$key]))
		return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=ir_code&ir_code=' . DuneIrControl::$key_codes[$key] . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
	hd_print("Error in class " . get_class($this) . "::" . __FUNCTION__ . "! Code of key '$key' not found in base!");
}

# Return: PLAYER_STATE_STANDBY | PLAYER_STATE_BLACK_SCREEN | PLAYER_STATE_NAVIGATOR |
#         PLAYER_STATE_FILE_PLAYBACK | PLAYER_STATE_DVD_PLAYBACK | PLAYER_STATE_BLURAY_PLAYBACK
function get_player_state() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "player_state" | sed -n "s/^.*player_state = /\1/p"'), "\n");
}

# Return: assoc array of state
function get_player_state_assoc() {
	return parse_ini_file('/tmp/run/ext_command.state', 0, INI_SCANNER_RAW);
}

# Return: STANDBY_MODE_OFF | STANDBY_MODE_ON
function get_standby_mode() {
	return intval(rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "player_state" | sed -n "s/^.*player_state = /\1/p"'), "\n") == PLAYER_STATE_STANDBY);
}

# Argument: STANDBY_MODE_OFF | STANDBY_MODE_ON
# Return: command execution status
function set_standby_mode($mode) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=ir_code&ir_code=' . (($mode == STANDBY_MODE_OFF)? 'A05FBF00' : 'A15EBF00') . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

function stb_reboot() {

	if (defined('RESTART_ACTION_ID'))
        return array(
             GuiAction::handler_string_id => RESTART_ACTION_ID,
             GuiAction::data => array(
                RestartActionData::reboot => true));

	if (defined('CHANGE_SETTINGS_ACTION_ID'))
		return array(
			 GuiAction::handler_string_id => CHANGE_SETTINGS_ACTION_ID,
			 GuiAction::data => array(
			 	ChangeSettingsActionData::reboot => true,
			 	ChangeSettingsActionData::post_action => null));

	exec('reboot');
}

function stb_shell_reboot() {

	if (defined('RESTART_ACTION_ID'))
        return array(
             GuiAction::handler_string_id => RESTART_ACTION_ID,
             GuiAction::data => array(
                RestartActionData::reboot => false));

	if (defined('CHANGE_SETTINGS_ACTION_ID'))
		return array(
			 GuiAction::handler_string_id => CHANGE_SETTINGS_ACTION_ID,
			 GuiAction::data => array(
			 	ChangeSettingsActionData::restart_gui => true,
			 	ChangeSettingsActionData::post_action => null));

	exec('killall shell');
}

###############################################################################
# Playback functions
###############################################################################

# Return: PLAYBACK_STATE_STOPPED | PLAYBACK_STATE_INITIALIZING | PLAYBACK_STATE_PLAYING |
#         PLAYBACK_STATE_PAUSED | PLAYBACK_STATE_SEEKING | PLAYBACK_STATE_BUFFERING |
#         PLAYBACK_STATE_FINISHED | PLAYBACK_STATE_DEINITIALIZING
function get_playback_state() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_state" | sed -n "s/^.*playback_state = /\1/p"'), "\n");
}

# Return: command execution status
function stop() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=light_stop" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return true | false
function can_pause() {
	return (rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "pause_is_available" | sed -n "s/^.*pause_is_available = /\1/p"'), "\n") == 1);
}

# Return: command execution status
function pause() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&speed=0" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: command execution status
function resume() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&speed=256" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return value:      |-8192|-4096|-2048|-1024|-512|-256| -128|  -64|  -32|   -16|    -8|    0|    8|   16|   32|  64| 128|  256|  512| 1024| 2048|  4096|  8192|
# Corresponds speed: | -32x| -16x|  -8x|  -4x| -2x| -1x|-1/2x|-1/4x|-1/8x|-1/16x|-1/32x|pause|1/32x|1/16x| 1/8x|1/4x|1/2x|   1x|   2x|   4x|   8x|   16x|   32x|
function get_speed() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_speed" | sed -n "s/^.*playback_speed = /\1/p"'), "\n");
}

# Argument: -8192|-4096|-2048|-1024|-512|-256|-128|-64|-32|-16|-8|0|8|16|32|64|128|256|512|1024|2048|4096|8192
# Return: command execution status
function set_speed($value) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&speed=' . $value . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: string value of length in seconds
function get_length_seconds() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_duration" | sed -n "s/^.*playback_duration = /\1/p"'), "\n");
}

# Return: true if length of media is known
function has_length() {
	return (get_length_seconds() > 0);
}

# Return: string value of position in seconds
function get_position_seconds() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_position" | sed -n "s/^.*playback_position = /\1/p"'), "\n");
}

# Argument: value of position in seconds
# Return: command execution status
function set_position_seconds($value) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&position=' . $value . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Argument: values of speed and position in seconds
# Return: command execution status
function set_speed_and_position_seconds($speed, $position) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&speed=' . $speed . '&position=' . $position . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Returns true if scrambled stream is detected during current playback
function is_scrambling_detected() {
	return (rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "scrambling_detected" | sed -n "s/^.*scrambling_detected = /\1/p"'), "\n") == 1);
}

# Return: string value of length of one media segment for segment-based media.
#         For HLS, returns the value of X-EXT-TARGETDURATION
function get_segment_length_seconds() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "segment_length" | sed -n "s/^.*segment_length = /\1/p"'), "\n");
}

# Return: string value of playback URL
function get_playback_url() {
	$url = rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_url" | sed -n "s/^.*playback_url = /\1/p"'), "\n");
	if (preg_match_all('/\/\/(127\.0\.0\.1|localhost).*((htt|rt|rtc|rts|ud)p:\/\/.*$)/i', $url, $matches)) {
		if (!empty($matches[2][0])) return $matches[2][0];
	}

	return $url;
}

###############################################################################
# Audio functions
###############################################################################

# Return: string value 0..100 - current volume in percents
function get_volume() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_volume" | sed -n "s/^.*playback_volume = /\1/p"'), "\n");
}

#Argument: 0..100 - volume in percents
# Return: command execution status
function set_volume($value) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&volume=' . $value . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: boolean value of mute enabled status
function is_mute_enabled() {
	return (rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_mute" | sed -n "s/^.*playback_mute = /\1/p"'), "\n") == 1);
}

# Return: command execution status
function enable_mute() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&mute=1" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: command execution status
function disable_mute() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&mute=0" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: array of audio tracks
#   [first_track_index] =>
#       array (
#          'lang' => [value],
#          'pid' => [value],
#          'codec' => [value],
#          'type' => [value]),
#   [next_track_index] =>
#       array (
#          'lang' => [value],
#          'pid' => [value],
#          'codec' => [value],
#          'type' => [value])...
function get_audio_tracks_description() {

	preg_match_all('/audio_track\.(\d)\.(.*)\s=\s(.*$)/mx', file_get_contents('/tmp/run/ext_command.state'), $matches);

	$result = array();
	foreach($matches[1] as $key => $value) {
		$result[$value][$matches[2][$key]] = $matches[3][$key];
	}

	return $result;
}

# Return: 0..N - current audio track index
function get_audio_track() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "audio_track" | sed -n "s/^.*audio_track = /\1/p"'), "\n");
}

# Argument: 0..N - audio track index
# Return: command execution status
function set_audio_track($track) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&audio_track=' . $track . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}


###############################################################################
# Teletext functions
###############################################################################

# Return: boolean value of teletext available in the current stream
function is_teletext_available() {
	return (rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "teletext_available" | sed -n "s/^.*teletext_available = /\1/p"'), "\n") == 1);
}

# Return: boolean value of teletext mode is turned
function is_teletext_enabled() {
	return (rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "teletext_enabled" | sed -n "s/^.*teletext_enabled = /\1/p"'), "\n") == 1);
}

# Return: command execution status
function enable_teletext() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&teletext_enabled=1" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: command execution status
function disable_teletext() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&teletext_enabled=0" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: string value of current teletext page number
function get_teletext_page_number() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "teletext_page_number" | sed -n "s/^.*teletext_page_number = /\1/p"'), "\n");
}

# Argument: 100..899 - page number
# Return: command execution status
function set_teletext_page_number($value) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&teletext_page_number=' . $value . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: boolean value of teletext mix mode is turned
function is_teletext_mix_mode_enabled() {
	return (rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "teletext_mix_mode" | sed -n "s/^.*teletext_enabled = /\1/p"'), "\n") == 1);
}

# Return: command execution status
function enable_teletext_mix_mode() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&teletext_mix_mode=1" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: command execution status
function disable_teletext_mix_mode() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&teletext_mix_mode=0" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}


###############################################################################
# Video functions
###############################################################################

# Returns true if primary video showing during primary video playback is enabled.
# When primary video playback is performed and primary video showing is disabled,
# primary video playback internally runs in the usual way, but primary video is
# hidden. By default, primary video showing is enabled.
function is_video_enabled() {
	return (rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "video_enabled" | sed -n "s/^.*video_enabled = /\1/p"'), "\n") == 1);
}

# Return: command execution status
function enable_video() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&video_enabled=1" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Disables showing of primary video when primary video playback is running. Does
# not affect primary video playback itself (i.e. the primary video playback
# internally continues, only primary video becomes hidden).
# Return: command execution status
function disable_video() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&video_enabled=0" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: string value of current Z-order of primary video
function get_video_zorder() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "video_zorder" | sed -n "s/^.*video_zorder = /\1/p"'), "\n");
}

# Sets Z-order of primary video. If primary video playback is not running or primary
# video showing is disabled, primary video layer is absent and this setting has no
# effect. Z-ordering of primary video, PiP video and OSD layers works in the following
# way. Layers with greater Z-order are put above layers with lesser Z-order. Default
# Z-order values for primary video, PiP video, OSD are: 200, 400, 500. If some of the
# layers (primary video, PiP video, OSD) have the same Z-order, the following ordering
# rules are used: OSD is above PiP video, PiP video is above primary video.
# Argument: 0..1000 - Z-order
# Return: command execution status
function set_video_zorder($value) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&video_zorder=' . $value . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: string value of current Z-order of OSD
function get_osd_zorder() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "osd_zorder" | sed -n "s/^.*osd_zorder = /\1/p"'), "\n");
}

# Argument: 0..1000 - Z-order
# Return: command execution status
function set_osd_zorder($value) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&osd_zorder=' . $value . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: true if primary video has Z-order greater than Z-order of OSD
function is_video_on_top() {
	return (rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "video_on_top" | sed -n "s/^.*video_on_top = /\1/p"'), "\n") == 1);
}

# Puts primary video above OSD. The function is equivalent to setVideoZOrder(900) and
# setOSDZOrder(500). NOTE: This function is intended to be used by applications which
# do not use PiP video; if PiP video is used, it is recommended not to use this function
# and instead use set{Video,PIP,OSD}ZOrder functions directly.
# Return: command execution status
function enable_video_on_top() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&video_on_top=1" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Puts primary video below OSD. The function is equivalent to setVideoZOrder(200) and
# setOSDZOrder(500)). NOTE: This function isintended to be used by applications which
# do not use PiP video; if PiP video is used, it is recommended not to use this function
# and instead use set{Video,PIP,OSD}ZOrder functions directly.
# Return: command execution status
function disable_video_on_top() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&video_on_top=0" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: boolean value of window full screen mode enabled
function is_window_full_screen() {
	return (rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_window_fullscreen" | sed -n "s/^.*playback_window_fullscreen = /\1/p"'), "\n") == 1);
}

# Return: command execution status
function enable_window_full_screen() {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&window_fullscreen=1" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: string value of window rect x
function get_window_rect_x() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_window_rect_x" | sed -n "s/^.*playback_window_rect_x = /\1/p"'), "\n");
}

# Return: string value of window rect y
function get_window_rect_y() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_window_rect_y" | sed -n "s/^.*playback_window_rect_y = /\1/p"'), "\n");
}

# Return: string value of window rect width
function get_window_rect_width() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_window_rect_width" | sed -n "s/^.*playback_window_rect_width = /\1/p"'), "\n");
}

# Return: string value of window rect height
function get_window_rect_height() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_window_rect_height" | sed -n "s/^.*playback_window_rect_height = /\1/p"'), "\n");
}

# Return: command execution status
function set_window_rect($x, $y, $width, $height) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&window_fullscreen=0&window_rect_x=' . $x . '&window_rect_y=' . $y . '&window_rect_width=' . $width . '&window_rect_height=' . $height . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: string value of clip rect x
function get_clip_rect_x() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_clip_rect_x" | sed -n "s/^.*playback_clip_rect_x = /\1/p"'), "\n");
}

# Return: string value of clip rect y
function get_clip_rect_y() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_clip_rect_y" | sed -n "s/^.*playback_clip_rect_y = /\1/p"'), "\n");
}

# Return: string value of clip rect width
function get_clip_rect_width() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_clip_rect_width" | sed -n "s/^.*playback_clip_rect_width = /\1/p"'), "\n");
}

# Return: string value of clip rect height
function get_clip_rect_height() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_clip_rect_height" | sed -n "s/^.*playback_clip_rect_height = /\1/p"'), "\n");
}

# Return: command execution status
function set_clip_rect($x, $y, $width, $height) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&clip_rect_x=' . $x . '&clip_rect_y=' . $y . '&clip_rect_width=' . $width . '&clip_rect_height=' . $height . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: string value of video source rect x
function get_video_source_rect_x() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_video_source_rect_x" | sed -n "s/^.*playback_video_source_rect_x = /\1/p"'), "\n");
}

# Return: string value of video source rect y
function get_video_source_rect_y() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_video_source_rect_y" | sed -n "s/^.*playback_video_source_rect_y = /\1/p"'), "\n");
}

# Return: string value of video source rect width
function get_video_source_rect_width() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_video_source_rect_width" | sed -n "s/^.*playback_video_source_rect_width = /\1/p"'), "\n");
}

# Return: string value of video source rect height
function get_video_source_rect_height() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_video_source_rect_height" | sed -n "s/^.*playback_video_source_rect_height = /\1/p"'), "\n");
}

# Sets coordinates of a portion of the original video for displaying in window or on full
# screen as specified via set_window_rect(). The specification of the portion coordinates is
# in 0-4096 scale for all arguments instead of OSD size scale in set_window_rect() and
# set_clip_rect() thus set_video_source_rect(0, 0, 4096, 4096) specifies complete original video.
# The coordinates are specified relative to the original video dimensions with no dependence
# on display/window aspect ratio so if there is, say, 4:3 video that should be displayed in a
# 3:1 window and set_video_source_rect(0, 0, 1024, 4096) is called then the resulting video will
# have 1:3 aspect ratio with appropriate black bars added in the window if normal zoom mode is
# specified. The video source rectangle specification is also compatible with
# VIDEO_ZOOM_STRETCH_TO_FULL_SCREEN preset, in this case the portion of the original video is
# stretched to full screen or window as expected. Other zoom presets are not compatible, just
# like with set_clip_rect() call - set_video_source_rect() fails if an incompatible zoom preset is
# set and set_video_zoom() fails with an incompatible zoom preset if a partial video source
# rectangle is already in effect. Note that both video source rectangle and clip rectangle may
# be specified with set_video_source_rect() and set_clip_rect() respectively but if both are in effect
# then the clip rectangle setting is ignored until set_video_source_rect() is set to complete
# original video so programr should take care to avoid such situations.
# Return: command execution status
function set_video_source_rect($x, $y, $width, $height) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&video_source_rect_x=' . $x . '&video_source_rect_y=' . $y . '&video_source_rect_width=' . $width . '&video_source_rect_height=' . $height . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

# Return: string value of current video width
function get_video_width() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_video_width" | sed -n "s/^.*playback_video_width = /\1/p"'), "\n");
}

# Return: string value of current video height
function get_video_height() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "playback_video_height" | sed -n "s/^.*playback_video_height = /\1/p"'), "\n");
}

# Return: string value of current video zoom
function get_video_zoom() {
	return rtrim(shell_exec('cat /tmp/run/ext_command.state | grep -w "video_zoom" | sed -n "s/^.*video_zoom = /\1/p"'), "\n");
}

# Argument: VIDEO_ZOOM_NORMAL | VIDEO_ZOOM_ENLARGE | VIDEO_ZOOM_MAKE_WIDER | VIDEO_ZOOM_NON_LINEAR_STRETCH |
#           VIDEO_ZOOM_NON_LINEAR_STRETCH_TO_FULL_SCREEN | VIDEO_ZOOM_MAKE_TALLER | VIDEO_ZOOM_CUT_EDGES |
#           VIDEO_ZOOM_FULL_SCREEN | VIDEO_ZOOM_STRETCH_TO_FULL_SCREEN
# Return: command execution status
function set_video_zoom($value) {
	return rtrim(shell_exec('env REQUEST_METHOD="GET" QUERY_STRING="cmd=set_playback_state&video_zoom=' . $value . '" /firmware/ext_command/cgi-bin/do | grep "command_status" | sed -n "s/^<param name=\"command_status\" value=\"\(.*\)\"\/>/\1/p"'), "\n");
}

###############################################################################
# Storage access
###############################################################################

# Return: array of local storages
function get_local_storages_list() {
	$i = 0;
	$result = array();
	foreach(scandir(DUNE_MOUNTED_STORAGES_PATH) as $item) {
		if (($item == '.') || ($item == '..') || !is_dir(DUNE_MOUNTED_STORAGES_PATH . $item)) continue;
		$disk_name = '';
		foreach(explode('_', $item) as $chunk) {
			$disk_name .= is_numeric('0x' . $chunk)? '' : $chunk;
		}
		$aliase = (($disk_name == 'DuneHDD')? 'D:' : 'usb' . $i++ . ':');
		$result['list'][$item] = $aliase;
		$result['names'][] = $item;
		$result['aliases'][] = $aliase;
		$result['labels'][] = (($disk_name == 'usbstorage')? '' : $disk_name);
	}

	return $result;
}

###############################################################################
# HTTP Functions
###############################################################################

function http_get_document($url, $opts = null, $silent = false)
{

	$ch = curl_init();
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 	0);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 	0);
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,    6);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER,    true);
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION,	true);
	curl_setopt($ch, CURLOPT_TIMEOUT,           6);
	curl_setopt($ch, CURLOPT_USERAGENT,         'DuneHD/1.0' . get_client_extra_info());
	curl_setopt($ch, CURLOPT_URL,               $url);
	if (is_array($opts))
	{
		foreach ($opts as $k => $v)
		{
			curl_setopt($ch, $k, $v);
		}
	}
	if (!$silent) 
	{
		hd_print("HTTP fetching '$url'...");
	}

	$content = curl_exec($ch);
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

	if ($content === false) {
		hd_print("HTTP error: $http_code; " . "CURL errno: " . curl_errno($ch) . " (" . curl_error($ch) . ')');
	}

	curl_close($ch);

	if ($http_code != 200) {
		hd_print("HTTP request failed ($http_code)");
		return null;
	} else if (!$silent) {
		hd_print("HTTP OK ($http_code)");
	}

	return $content;
}

///////////////////////////////////////////////////////////////////////

function http_post_document($url, $post_data, $opts = null, $silent = false) {

	$header = array(
		CURLOPT_POST => true,
		CURLOPT_POSTFIELDS => $post_data);

	if (isset($opts)) {
		foreach ($opts as $key => $value)
		   $header[$key] = $value;
	}

	return http_get_document($url, $header, $silent);
}


###############################################################################
# XML Docs
###############################################################################

function parse_xml_document($doc) {

	$xml = simplexml_load_string($doc, null, LIBXML_NOCDATA | LIBXML_NOEMPTYTAG);

	if ($xml === false) {
		hd_print("Error: can not parse XML document.");
		hd_print("XML-text: $doc.");
		throw new Exception('Dune STB API: Illegal XML document');
	}

	return $xml;
}

###############################################################################
# Miscellaneous
###############################################################################

# Возвращает путь к директории активного скина (без слеша на конце)
function get_active_skin_path() {

	if (file_exists('/tmp/dune_skin_dir.txt')) {
		return rtrim(trim(preg_replace('/^.*=/', '', file_get_contents('/tmp/dune_skin_dir.txt'))), '/');
	}
	hd_print("Error in class " . get_class($this) . "::" . __FUNCTION__ . "! Can not determine the path to the active skin.");
}

# Возвращает указанный путь (без слеша на конце), попутно создавая каталоги
function get_paved_path($path, $dir_mode = 0777) {
	if (!file_exists($path)) {
		@mkdir($path, $dir_mode, true);
	}
	return rtrim($path, '/');
}

# Аналог json_encode() c опцией JSON_UNESCAPED_UNICODE доступной в PHP 5.4.0 и выше
function json_encode_unicode($data) {
	array_walk_recursive(
		$data,
		function(&$item, $key) {
		    if (is_string($item))
     			$item = mb_encode_numericentity($item, array(0x80, 0xffff, 0, 0xffff), 'UTF-8');
		}
	);

	return mb_decode_numericentity(json_encode($data), array(0x80, 0xffff, 0, 0xffff), 'UTF-8');
}

# Возвращает строку из аппаратного идентификатора и версии прошивки
function get_client_extra_info() {

	static	$client_extra_info = null;

	if (is_null($client_extra_info)) {
	    $client_extra_info = '';
	    if (file_exists('/tmp/sysinfo.txt')) {
		    if ($sys_info = file('/tmp/sysinfo.txt', FILE_IGNORE_NEW_LINES)) {
		        foreach ($sys_info as $line) {
		            if (preg_match('/product_id:|firmware_version:/', $line)) {
	            		$client_extra_info .= (empty($client_extra_info)? ' (' : ', ') . $line;
		            }
		        }
		        $client_extra_info .= empty($client_extra_info)? '' : ') ';
		    }
		}
	}

	return $client_extra_info;
}

# Возвращает канонизированную строку в нижнем регистре
function get_canonize_string($str, $encoding = 'UTF-8') {
	return str_replace(
				array('а','в','е','к','м','н','о','р','с','т','у','х'),
				array('a','b','e','k','m','h','o','p','c','t','y','x'),
				mb_strtolower(trim($str), $encoding));
}

# Возвращает строковую константу на языке системы по ключу
function get_system_language_string_value($string_key) {
	if ($sys_settings = parse_ini_file('/config/settings.properties', false, INI_SCANNER_RAW)) {
		$sys_lang = file_exists('/firmware/translations/dune_language_' . $sys_settings['interface_language'] . '.txt')? $sys_settings['interface_language'] : 'english';
		if (($lang_txt = file_get_contents("/firmware/translations/dune_language_$sys_lang.txt")) &&
			preg_match("/^$string_key\\s*=(.*)$/m", $lang_txt, $m))
				return trim($m[1]);
	}
	hd_print("Error in class " . get_class($this) . "::" . __FUNCTION__ . "! Not found value for key '$string_key'!");
	return '';
}

?>