<?php

// dmx_shop_components.php
// -------------------------------------------------------------------------------------------------
// The 'renderer' for the dmShop family of XComponents
// Fetch data, as necessary, from the dmProtocol server, and prepare it for
// substitution in the appropriate template.
// 
// Revision   > $Rev: 155 $
// Date		  > $Date: 2009-12-02 16:44:54 +0000 (Wed, 02 Dec 2009) $
// Author     > RAK for DML
// Copyright  > (C) Digital Mail Limited (2005-2009)
// -------------------------------------------------------------------------------------------------

require_once('dmx_library.php');
require_once('dmx_run.php');

// -------------------------------------------------------------------------------------------------

function dmx_render($component, $comp_name = '', $xparams = array(), $user_tpl = '')
{
	// GENERATE AND RENDER NAMED XCOMPONENT,
	// handling any necessary communication with the shopping server

	global $dmx_session;
	global $dmx_init_response;
	global $dmx_tmp_var;
	global $dmx_debug;
	global $dmshop;
	global $json;

	$GLOBALS['time1'] = dmx_add_benchmark("Start of dmx_render($component, $comp_name)");
	$dmx_debug->heading("dmx_render($component, $comp_name)");
	
	$dmx_tmp_var = array(); // variables substituted in component template
	
	list($component_family, $component_class) = explode('.', $component); // Expects eg. 'dmshop.numberchooser'
	$component_family = strtolower($component_family); // $component_family is not used, yet...
	$component_class  = strtolower($component_class);
	$xparams 		  = dmx_cast_array_to_lc($xparams);

	// ----------------------------------------
	// GET COMPONENT DEFAULTS FROM OPTIONS FILE
	$options = dmx_read_component_options($component_class);
	extract($options);
	$dmshop->_R = isset($options['params']) ? $options['params'] : array();
	$dmshop->_R = dmx_resolve_params($dmshop->_R, $xparams, array('timeoutignore')); // $xparams can supply 'timeoutignore' - dmShop hit will not affect dmShop session timouts
	
	// -------------------------------------
	// ADD STANDARD DMSHOP PROTOCOL COMMANDS
	$dmshop->_R['TrolleyID'] = $dmx_session;

	// -----------------------------------------------------------------------
	// DETERMINE TROLLEY FOCUS (index), AND CURRENT SERVICE (cs) AND PLAN $cp)
	$tfocus = new stdClass;
	$num_items = isset($dmx_init_response['QntItems']) ? $dmx_init_response['QntItems'] : 0;
	// Look for history overrides of index (set when item given focus in trolley), if not set explicitly
	if (!isset($xparams['index']))
	{
		$ovparams = array('index');
		$xparams  = dmx_check_memory('trolley', $xparams, $ovparams);
	}
	// Now get number in trolley with focus
	if (isset($xparams['index']) && $xparams['index'] <= $num_items)
	{
		// The index of the item in the trolley is plausible, so use it
		$tfocus->index = (int) $xparams['index'];
	}
	else if ($num_items > 0)
	{
		// Default to the last item in the trolley
		$tfocus->index = $dmx_init_response['QntItems'];
	}
	else
	{
		// There's nothing in the trolley
		$tfocus->index = 0;
	}
	// Current service and plan of number with focus
	list($tfocus->cs, $tfocus->cp) = $tfocus->index && $dmx_init_response['EXTENDED'] ? explode(':', $dmx_init_response['Item'][$tfocus->index]['SvcPlan']) : array('', '');
	
	// ------------------------------------------------------------------
	// PREPARE RESULT CONDITIONS, FOR PASSING THROUGH TO DMX_SHOP_HANDLER
	// These can be used to control XComponent navigation
	$rc = array();
	while (list($key, $value) = each($xparams))
	{
		if (substr($key, 0, 7) == 'result_') $rc[] = substr($key, 7) . '=' . $value;
	}
	$dmx_tmp_var['result_conditions'] = dmx_serialize($rc);
	$dmx_tmp_var['err_msg'] = '';
	
	// -----------------------------------------------------------------
	// PREPARE STANDARD COMPONENT VARIABLES FOR SUBSTITUTION IN TEMPLATE
	// Look for 'page code' overrides for template control variables NOT overriden by component history
	$ovparams = array('showheader', 'showborder', 'showpreamble', 'maxheight', 'maxwidth', 'embedded');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);
	
	// Have maxheight and maxwidth conditions been specified? If so make CSS rule to enforce
	$dmx_tmp_var['comp_width'] 	= dmx_generate_comp_width_css_rule(@$dmx_tmp_var['maxwidth']);
	$dmx_tmp_var['box_size'] 	= dmx_generate_box_size_css_rule(@$dmx_tmp_var['maxheight']);
	
	// Has the component generated a message, or thrown an error message?
	$dmx_tmp_var['comp_msg'] = $dmx_tmp_var['comp_err_msg'] = '';
	$ovparams = array('comp_msg', 'comp_err_msg');
	$dmx_tmp_var = dmx_check_memory($comp_name, $dmx_tmp_var, $ovparams);
	
	$dmx_tmp_var['dmx_session'] 	= $dmx_session;
	$dmx_tmp_var['focus'] 			= $tfocus->index;
	$dmx_tmp_var['ajax'] 			= isset($xparams['ajax']) 			? 1 : 0;
	$dmx_tmp_var['ajax_update'] 	= isset($xparams['ajax_update']) 	? 1 : 0;
	$dmx_tmp_var['ajax_debug'] 		= isset($xparams['ajax_debug'])		? 1 : 0;
	$dmx_tmp_var['response_type'] 	= isset($xparams['response_type']) 	? $xparams['response_type'] : '';

	// Support for self-updating components (update via AJAX)
	$xp_json 			= $xparams;
	$xp_json['family']	= $component_family;
	$xp_json['xclass']	= $component_class;
	$xp_json['name']	= $comp_name;
	$dmx_tmp_var['xparams_json'] = $json->encode($xp_json);
	
	switch($component_class)
	{
	
		case 'benchmarks':
			// THE BENCHMARK COMPONENT
			$dmx_tmp_var = dmx_prepare_benchmarks($comp_name, $xparams, $options);
			break;

		case 'callcostexplorer':
			// THE CALL COST EXPLORER COMPONENT
			$dmx_tmp_var = dmx_prepare_callcostexplorer($comp_name, $xparams, $options, $tfocus);
			break;

		case 'debug':
			// THE DEBUGGING COMPONENT
			$dmx_tmp_var = dmx_prepare_debug($comp_name, $xparams, $options);
			break;

		case 'login':
			// THE LOGIN COMPONENT
			$dmx_tmp_var = dmx_prepare_login($comp_name, $xparams, $options);
			break;

		case 'loginstatus':
			// THE LOGINSTATUS COMPONENT
			$dmx_tmp_var = dmx_prepare_loginstatus($comp_name, $xparams, $options);
			break;

		case 'numberchooser':
			// THE NUMBER CHOOSER COMPONENT, INCLUDING ANY SEARCH RESULTS
			$dmx_tmp_var = dmx_prepare_numberchooser($comp_name, $xparams, $options);
			break;
			
		case 'orderdealership':
			// THE ORDERDEALERSHIP COMPONENT
			$dmx_tmp_var = dmx_prepare_orderdealership($comp_name, $xparams, $options);
			break;
			
		case 'register':
			// THE REGISTER COMPONENT
			$dmx_tmp_var = dmx_prepare_register($comp_name, $xparams, $options);
			break;

		case 'serviceplanselector':
			// THE SERVICE PLAN SELECTOR COMPONENT
			$dmx_tmp_var = dmx_prepare_serviceplanselector($comp_name, $xparams, $options, $tfocus);
			break;

		case 'tariffguide':
			// THE TARIFFGUIDE COMPONENT
			$dmx_tmp_var = dmx_prepare_tariffguide($comp_name, $xparams, $options, $tfocus);
			break;

		case 'trolley':
			// THE TROLLEY COMPONENT
			$dmx_tmp_var = dmx_prepare_trolley($comp_name, $xparams, $options);
			break;
	
		case 'typicalfirstinvoice':
			// THE TYPICAL FIRST INVOICE COMPONENT
			$dmx_tmp_var = dmx_prepare_typicalfirstinvoice($comp_name, $xparams, $options, $tfocus);
			break;

		default:
			$dmx_debug->msg('<b>Invalid call to dmx_fetch()</b> ' . $component_family . '.' . $component_class . " is not recognised\n");
			break;
	
	}
	
	// ---------------------------------------------------------------------------------------------
 
	// Parse the component template
	dmx_parse_template($component_class, $comp_name, $user_tpl);
	unset($GLOBALS['xparams']);

	// Erase any old error messages, so they are not repeated
	if ($dmx_tmp_var['comp_msg'] || $dmx_tmp_var['comp_err_msg'])
	{
		dmx_store($comp_name, array('comp_msg' => '', 'comp_err_msg' => '', 'form' => array()));
	}
	
}

// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------

function dmx_prepare_benchmarks($comp_name, $xparams)
{
	global $dmx_tmp_var, $dmx_options;

	// Prepare variables substituted in component template
	if ($dmx_options['debug_level'])
	{
		global $dmx_gmt, $dmx_benchmarks;
		// Prepare variables substituted in component template
		$dmx_tmp_var['num_benchmarks'] 	= count($dmx_benchmarks);
		$dmx_tmp_var['timestamp'] 		= $dmx_gmt['weekday'] . ' ' . $dmx_gmt['mday'] . ' ' . $dmx_gmt['month'] . ' ' . sprintf('%02d', $dmx_gmt['hours']) . ':' . sprintf('%02d', $dmx_gmt['minutes']) . ':' . sprintf('%02d', $dmx_gmt['seconds']);
		$dmx_tmp_var['dmx_benchmarks'] 	= $dmx_benchmarks;
	}
	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------

function dmx_prepare_callcostexplorer($comp_name, $xparams, $options, $tfocus)
{
	global $dmx_tmp_var, $dmx_init_response, $dmshop, $dmx_debug, $json;

	// Variables fromcallcostexplorer_options.php
	$def 		= $options['def'];
	$period_val = $options['period_val'];
	
	$focus 	= $tfocus->index;
	$cs 	= $tfocus->cs;
	$cp 	= $tfocus->cp;
	
	if (!$focus) 
	{
		$dmx_tmp_var['err_msg'] = 'There is nothing in your shopping trolley at the moment, so the call cost explorer cannot be used.';
		return $dmx_tmp_var;
	}
	
	// Fetch service and plan options
	$dmshop->_R['Item.Idx'] = $focus; // ITEM NOT YET IMPLEMENTED
	$dmshop->_R['Number'] 	= $dmx_init_response['Item'][$focus]['Number'];
	$ovparams = array('TariffFilter', 'ServiceFilter', 'PlanFilter');
	$dmshop->_R = dmx_resolve_params($dmshop->_R, $xparams, $ovparams);

	// Look for page code overrides of destination, duration and period
	$ovparams = array('destinations', 'duration', 'period');
	$def = dmx_resolve_params($def, $xparams, $ovparams);
	
	// Compile DestDurList
	$d = explode(',', $def['destinations']);
	$period = strtoupper($def['period'][0]);
	$ddl = '';
	foreach ($d as $dest) $ddl .= $dest . ':' . $period . ':' . $def['duration'] . ',';
	$dmshop->_R['DestDurList'] = substr($ddl, 0, -1);

	$dmshop->request();
	$dmx_debug->msg($dmshop->debug->flush());

	if ($dmshop->result->status == false || !count($dmshop->result->response))
	{
		$dmx_tmp_var['err_msg'] = $dmx_options['err_msg']['comserr'];
		return $dmx_tmp_var;
	}
	$dmx_response = $dmshop->result->response;
	dmx_add_benchmark('Response from ' . $dmshop->url, $GLOBALS['time1']);
	if ($dmx_response['Cmd'] == 'GetSvcPlanOptionsNak')
	{
		$dmx_tmp_var['err_msg'] = 'Could not get service and plan options';
		return $dmx_tmp_var;
	}

	// Get Service info
	if (isset($dmx_response['S']))
	{
		foreach($dmx_response['S'] as $i => $service) if (strtolower($cs) == strtolower($service['Name'])) $csi = $i - 1; // Current Service index
	}
	if (!isset($csi))
	{
		$dmx_tmp_var['err_msg'] = 'Number\'s service (' . $cs . ') not amongst returned options.';
		return $dmx_tmp_var;
	}

	// Get Plan info
	if (isset($dmx_response['P']))
	{
		foreach($dmx_response['P'] as $i => $plan)
		{
			$dmx_tmp_var['plans'][] 	= $plan['Name'];
			$dmx_tmp_var['plans_lc'][] 	= strtolower($plan['Name']);
			if (strtolower($cp) == strtolower($plan['Name'])) $cpi = $i - 1; // Current Plan index
		}
	}
	if (!isset($cpi))
	{
		$dmx_tmp_var['err_msg'] = 'Number\'s plan (' . $cp . ') not amongst returned options.';
		return $dmx_tmp_var;
	}

	// Traverse pricing grid
	foreach($dmx_response['S'] as $i => $serv)
	{
		$dmx_tmp_var['grid'][$i - 1]['tariff_set'] 	= substr($serv['P'][1]['Tariff'], 0, strrpos($serv['P'][1]['Tariff'], '-')) . '-*';
		$dmx_tmp_var['grid'][$i - 1]['service']		= $serv['Name'];
		foreach($serv['P'] as $j => $t)
		{
			$costs 	= explode(',', $t['Costs']);
			$ppm 	= explode(',', $t['PPM']);
			foreach($costs as $k => $cost)
			{
				$costs[$k] = $cost != '-' ? sprintf('%.2f', $cost * 100) : '&mdash;';
				$class[$k] = $cost < 0 ? ' payout' : '';
			}
			foreach($ppm as $k => $p)
			{
				$ppm[$k] = $p != '-' ? sprintf('%.2f', $p) : '&mdash;';
			}
			$dmx_tmp_var['grid'][$i - 1]['plans'][$j - 1] = array(
				'plan'	 => $dmx_tmp_var['plans'][$j-1],
				'costs'	 => $costs,
				'ppm'	 => $ppm,
				'css_cl' => $class
			);
		}
	}
	
	// Get Destination info
	if (isset($dmx_response['D']))
	{
		foreach($dmx_response['D'] as $dest)
		{
			$dmx_tmp_var['dest'][] = array(
				'zone' 		=> $dest['Zone'],
				'zone_truc'	=> strlen($dest['Zone']) > 20 ? substr($dest['Zone'], 0, 18) . '...' : $dest['Zone'],
				'native'	=> $dest['Number'],
				'formatted'	=> $dest['FmtNum']
			);
			$simp_dest[] = $dest['Number']; // For JSON
		}
	}
	$dmx_tmp_var['num_dest'] = count($dmx_tmp_var['dest']);
	$dmx_tmp_var['duration']['min'] = floor($def['duration'] / 60);
	$dmx_tmp_var['duration']['sec'] = floor($def['duration'] % 60);
	$dmx_tmp_var['period'] = $period;
	$dmx_tmp_var['grid']['dest'] = $dmx_tmp_var['dest'];
	
	$dmx_tmp_var['cs'] 	= $cs; 	// Current Service
	$dmx_tmp_var['cp'] 	= $cp; 	// Current Plan
	$dmx_tmp_var['csi'] = $csi; // Current Service index
	$dmx_tmp_var['cpi'] = $cpi; // Current Plan    index

	$dmx_tmp_var['grid']['csi'] = $csi; // For JSON data exchange
	$dmx_tmp_var['grid']['cpi'] = $cpi; // For JSON data exchange

	// Now make available to javascript
	$dmx_tmp_var['grid_json'] = $json->encode($dmx_tmp_var['grid']);
	$dmx_tmp_var['dest_json'] = $json->encode($simp_dest);

	$dmx_tmp_var['colspan'] = count($dmx_tmp_var['plans']) + 2;
	
	// Generate select drop-down menu containing period
	$dmx_tmp_var['period_options'] = dmx_generate_select($period_val, $period);

	$dmx_tmp_var['tariff_set'] = $dmx_tmp_var['grid'][$csi]['tariff_set'];

	// ---------------------------------------------------------
	// PREPARE ADDITIONAL VARIABLES FOR SUBSTITUTION IN TEMPLATE

	// Look for 'page code' overrides for template control variables
	$ovparams = array('advanced_mode');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);
	
	$dmx_tmp_var['durper_display'] = $dmx_tmp_var['advanced_mode'] ? 'block' : 'none';

	$dmx_tmp_var['panel'] = dmx_init_panel(); // Make the panel object available to template

	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------

function dmx_prepare_debug($comp_name, $xparams, $options)
{
	global $dmx_tmp_var, $dmx_debug, $dmx_options;

	// Prepare variables substituted in component template
	if ($dmx_options['debug_level']) $dmx_tmp_var['dmx_debug_msg'] = $dmx_debug->display(1);
	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------

function dmx_prepare_login($comp_name, $xparams, $options)
{
	global $dmx_tmp_var, $dmx_init_response;

	// Prepare variables substituted in component template
	$dmx_tmp_var['grabut_suffix'] = isset($xparams['result_login']) ? 'forward' : 'reload';
	
	// Retrieve form field values for redisplay, if necessary
	$dmx_tmp_var['form'] = dmx_construct_form_array($comp_name, array('dmx_email', 'dmx_pin'));

	// Fill in email address if possible
	$dmx_tmp_var['form']['value']['dmx_email'] = isset($dmx_init_response['DMID']) ? $dmx_init_response['DMID'] : '';

	// Look for 'page code' overrides for template control variables
	$ovparams = array('variant');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);
	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------

function dmx_prepare_loginstatus($comp_name, $xparams, $options)
{
	global $dmx_tmp_var, $dmx_init_response;

	// Prepare variables substituted in component template
	// Look for 'page code' overrides for template control variables
	$ovparams = array('show_dmid', 'textonly', 'max_dmid_length');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);

	$dmx_tmp_var['logged_in'] 		= isset($dmx_init_response['LoggedIn'])		 && $dmx_init_response['LoggedIn'] 		== 'Y' 	? 1 							: 0;
	$dmx_tmp_var['authenticated'] 	= isset($dmx_init_response['Authenticated']) && $dmx_init_response['Authenticated'] == 'Y' 	? 1 							: 0;
	$dmx_tmp_var['dmid'] 			= isset($dmx_init_response['DMID']) 														? $dmx_init_response['DMID'] 	: '';
	
	$maxlen = $dmx_tmp_var['max_dmid_length'];
	if (strlen($dmx_tmp_var['dmid']) > $maxlen) $dmx_tmp_var['dmid'] = substr($dmx_tmp_var['dmid'], 0, $maxlen) . '&hellip;';
	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------

function dmx_prepare_numberchooser($comp_name, $xparams, $options)
{
	global $dmx_tmp_var, $dmx_session, $dmx_memory, $dmshop, $dmx_debug, $dmx_options, $dmx_response;
	
	// Variables from numberchooser_options.php
	$goldmenu 				= $options['goldmenu'];
	$params_ch_opt 			= $options['params_ch_opt'];
	$params		 			= $options['params'];
	$dmx_ncp_limit_tariffs 	= $options['dmx_ncp_limit_tariffs'];
	
	// Look for 'page code' overrides for template control variables
	$ovparams = array('showsearch', 'showtariffs');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);

	$matching_tariffs = array();
	if ($dmx_tmp_var['showsearch'] && $dmx_tmp_var['showtariffs'])
	{
		// ---------------------------
		// FETCH MATCHING TARIFFS
		$dmshop->_R = $params_ch_opt;
		$dmshop->_R['TrolleyID'] = $dmx_session;

		// Look for 'page code' overrides for request variables
		$xparams['tariffspec'] = isset($xparams['tariffs']) ? $xparams['tariffs'] : NULL; // NEEDS EXPANDING TO COPE WITH LISTS!
		$ovparams = array('TariffSpec', 'Range', 'NOG');
		$dmshop->_R = dmx_resolve_params($dmshop->_R, $xparams, $ovparams);

		// Handle memory:We could do this to only get tariffs matching incoming NCP, but then you can't change around so easily
		if ($dmx_ncp_limit_tariffs && ($root || $range || $service || $plan)) $dmshop->_R['TariffSpec'] = dmx_modify_tariff($dmshop->_R['TariffSpec'], $root, $range, $service, $plan); 
		
		$dmshop->request();
		$dmx_debug->msg($dmshop->debug->flush());
		
		if ($dmshop->result->status == false || !count($dmshop->result->response))
		{
			$dmx_tmp_var['err_msg'] = $GLOBALS['dmx_options']['err_msg']['comserr'];
			return $dmx_tmp_var;
		}
		$dmx_response = $dmshop->result->response;
		
		dmx_add_benchmark('Response from ' . $dmshop->url, $GLOBALS['time1']);
		if ($dmx_response['Cmd'] == 'GetChooserOptionsNak')
		{
			$dmx_tmp_var['err_msg'] = 'Could not get tariff options';
			return $dmx_tmp_var;
		}
		if (!isset($dmx_response['QntOpts']) || $dmx_response['QntOpts'] == 0)
		{	
			$dmx_tmp_var['err_msg'] = 'No matching tariffs found';
			return $dmx_tmp_var;
		}
		$matching_tariffs = $dmx_response['Opt'];
	}

	// ----------------------
	// NOW PREPARE THE SEARCH
	
	$sp = array(); // Search parameter overrides
	
	$dmshop->_R = $params;
	$dmshop->_R['TrolleyID'] = $dmx_session;

	// (1) Look for 'page code' overrides for request variables
	// First juggle the different naming conventions, ie differences between xparam names and corresponding shopping protocol names
	// $sp['tariffspec'] = isset($xparams['tariffs']) ? $xparams['tariffs'] : isset($matching_tariffs[1]['TariffSpec']) ? $matching_tariffs[1]['TariffSpec'] : NULL;
	$sp['tariffspec'] = isset($xparams['tariffs']) ? $xparams['tariffs'] : '*';
	$sp['filter'] = '';
	if (isset($xparams['spseq']) && $xparams['spseq'])
	{
		$f = explode(',', $xparams['spseq']);
		$sp['filter'] = dmx_generate_filter(NULL, $f);
	}
	$g = isset($xparams['gold']) ? explode('-', $xparams['gold']) : NULL;
	$sp['gvfrom'] 	= isset($g[0]) ? $g[0] : NULL;
	$sp['gvto'] 	= isset($g[1]) ? $g[1] : NULL;
	if (isset($xparams['sortedby'])) $sp['sortedby'] = $xparams['sortedby'];
	
	$ovparams = array('TariffSpec', 'Filter', 'GVFrom', 'GVTo', 'Page', 'SortedBy');
	$dmshop->_R = dmx_resolve_params($dmshop->_R, $sp, $ovparams);
	
	// (2) Now look for memory overrides
	//     Memory may be saet by user-interaction or NumberChooser Control Parameters

	// dmx_initialise_nc_memory($comp_name);
	
	$mem_state	= dmx_query_nc_memory($comp_name);
	$root		= $mem_state->root;
	$range		= $mem_state->range;
	$service 	= $mem_state->service;
	$plan 		= $mem_state->plan;
	$gold 		= $mem_state->gold;
	$areacode 	= $mem_state->areacode;
	$areaname 	= $mem_state->areaname;
	$prefix 	= $mem_state->prefix;
	
	// Modify tariff
	$dmshop->_R['TariffSpec'] = dmx_modify_tariff($dmshop->_R['TariffSpec'], $root, $range, $service, $plan); 

	// Get range, service and plan from the tariff
	$nc = dmx_translate_tariff($dmshop->_R['TariffSpec']);
	if ($nc->range == 'ukgeo' && $areacode)	$prefix	= '!44' . substr($areacode, 1); // areacode overrules prefix, if range is ukgeo
	
	// Gold range
	if ($gold)
	{
		$gbits = explode('-', $gold);
		if ( count($gbits) != 2 || !is_numeric($gbits[0]) || !is_numeric($gbits[1]) )
		{
			$dmx_debug->msg('INVALID GOLD RANGE: ' . $gold);
		}
		else
		{
			$dmshop->_R['GVFrom'] 	= min($gbits);
			$dmshop->_R['GVTo'] 	= max($gbits);
			$dmx_debug->msg('Gold range is: ' . $dmshop->_R['GVFrom'] . '-' . $dmshop->_R['GVTo']);
			$dmx_debug->msg();
		}
	}
	if (isset($xparams['gold_not_zero']) && $xparams['gold_not_zero'])
	{
		// This is a NumberChooser dedicated to selling gold numbers, so don't allow 0 values
		if ($dmshop->_R['GVFrom'] == 0) $dmshop->_R['GVFrom'] = 1;
		if ($dmshop->_R['GVTo']   == 0) $dmshop->_R['GVTo']   = $params['GVTo'];
	}

	// Generate filter from prior search or areacode selection - retrieve patterns from form memory
	$patterns = array();
	$pat1 = NULL;
	$pat2 = NULL;
	if (isset($dmx_memory[strtoupper($comp_name)]['form']['value']['dmx_pattern1']))
	{
		$pat1 = $dmx_memory[strtoupper($comp_name)]['form']['value']['dmx_pattern1'];
		$pat2 = $dmx_memory[strtoupper($comp_name)]['form']['value']['dmx_pattern2'];
	}
	if ($pat1) array_push($patterns, $pat1);
	if ($pat2) array_push($patterns, $pat2);
	if ($prefix || !empty($patterns)) $dmshop->_R['Filter'] = dmx_generate_filter($prefix, $patterns);
	$dmshop->_R['Filter'] = str_replace('!', '', $dmshop->_R['Filter']); // HACK: dmShop protocol doesn't understand ! (meant to mean starts with) so cut out

	// Page of results, and result sort order
	$ovparams = array('Page', 'SortedBy');
	$dmshop->_R = dmx_check_memory($comp_name, $dmshop->_R, $ovparams);

	// (3) Calculate number of numbers to ask for
	// Look for 'page code' overrides for template control variables NOT overriden by component history
	$ovparams = array('rows', 'cols');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);
	$dmshop->_R['PageSize'] = $dmx_tmp_var['rows'] * $dmx_tmp_var['cols'];

	// (4) Do the search
	$dmshop->request();
	$dmx_debug->msg($dmshop->debug->flush());
	
	if ($dmshop->result->status == false || !count($dmshop->result->response))
	{
		$dmx_tmp_var['err_msg'] = $GLOBALS['dmx_options']['err_msg']['comserr'];
		return $dmx_tmp_var;
	}
	$dmx_response = $dmshop->result->response;
	dmx_add_benchmark('Response from ' . $dmshop->url, $GLOBALS['time1']);
	if ($dmx_response['Cmd'] == 'ChooseNumberNak')
	{ 
		$dmx_response['Reason'] = urldecode($dmx_response['Reason']); // Hack to tackle double-URL encoding problem
		switch($dmx_response['Reason'])
		{
			case 'Bad PageSize':
				$details = 'BadPageSize';
				$dmx_tmp_var['err_msg'] = dmx_translate_err_code('numberchooser', $details);
				return $dmx_tmp_var;
			case 'Bad Filter':
				$details = 'BadFilter';
				break;
			default:
				$details = $dmx_response['Reason'];
		}
		$dmx_tmp_var['comp_err_msg'] = dmx_translate_err_code('numberchooser', $details);
	}
	
	$tariff = isset($dmx_response['TariffSpec']) ? $dmx_response['TariffSpec'] : NULL;

	// ---------------------------------------------------------
	// PREPARE ADDITIONAL VARIABLES FOR SUBSTITUTION IN TEMPLATE

	// Look for 'page code' overrides for template control variables
	$ovparams = array('showresults', 'showsearch', 'showspseq', 'showtariffs', 'showclass', 'showgold', 'prefixmenu', 'showpages', 'tariffs', 'gold', 'transfer_target');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);

	// Now look for user/history overrides on these named parameters
	$ovparams = array('showresults');
	$dmx_tmp_var = dmx_check_memory($comp_name, $dmx_tmp_var, $ovparams);
	
	// What tariff are we searching for?
	$dmx_tmp_var['tariff'] = $tariff;

	// $nc is generated by translating the modified tariff (see above);
	$dmx_tmp_var['range'] 	= $nc->range;
	$dmx_tmp_var['service'] = $nc->service;
	$dmx_tmp_var['plan']	= $nc->plan;
	
	if ($nc->range == 'ukgeo' && $areaname)
	{
		$dmx_tmp_var['icon_range']	= '<span class="infotext">' . $areacode . '<span class="tipcontents">' . $areacode . ' (' . $areaname . ') numbers</span></span>';
	}
	else
	{
		$dmx_tmp_var['icon_range']	= '{GLOS:icon_range_' . $nc->range . '}';
	}

	if ($dmx_tmp_var['showtariffs'])
	{
		// Generate select drop-down menu containing valid tariffs
		$values = array();
		foreach ($matching_tariffs as $t)
		{
			$values[] = $t['TariffSpec'] . ':' . ($dmx_options['debug_level'] ? $t['TariffSpec'] : $t['Description']) . "\n";
		}
		$dmx_tmp_var['tariffs'] = dmx_generate_select($values, $tariff);
	}
	
	// Populate form
	$dmx_tmp_var['form'] = array();
	$dmx_tmp_var['form']['value']['dmx_prefix_pattern'] = '';
	$dmx_tmp_var['form']['value']['dmx_pattern1'] 		= $pat1;
	$dmx_tmp_var['form']['value']['dmx_pattern2'] 		= $pat2;
	$fields = array('dmx_tariff', 'dmx_prefix_pattern', 'dmx_pattern1', 'dmx_pattern2', 'dmx_goldrange');
	$dmx_tmp_var['form'] = dmx_construct_form_array($comp_name, $fields, $dmx_tmp_var['form']);

	// Gold menu
	// Generate select drop-down menu containing gold values
	// What gold values are we searching for?
	$selected = '';
	if (isset($dmshop->_Last_R['GVFrom']))
	{
		// Get gold value from the last request
		$from 		= $dmshop->_Last_R['GVFrom'];
		$to			= $dmshop->_Last_R['GVTo'];
		$selected 	= $from . '-' . $to;
		$add_to_goldmenu = TRUE;
		foreach($goldmenu as $gm)
		{
			if ($selected == substr($gm, 0, strpos($gm, ':'))) $add_to_goldmenu = FALSE;
		}
		if ($add_to_goldmenu) array_push($goldmenu, $selected . ':£' . $from . ' - £' . $to);
	}
	if (isset($xparams['gold_not_zero']) && $xparams['gold_not_zero'])
	{
		// Unset 0-0 in goldmenu
		foreach($goldmenu as $i => $def)
		{
			$temp 	= explode(':', $def);
			$values = explode('-', $temp[0]);
			if (in_array(0, $values)) unset($goldmenu[$i]);
		}
		$goldmenu = array_values(array_filter($goldmenu));
	}

	$dmx_tmp_var['gold_drop_down'] = dmx_generate_select($goldmenu, $selected);

	// Prefix menu (display if defined already, or if areacode is not null)
	//
	// Areacode, if defined and sensible, always trumps anything in xparams
	if ($areacode && $nc->range === 'ukgeo')
	{
		$acsearch = '!44' . substr($areacode, 1);
		$dmx_tmp_var['prefixmenu'] = array( 
			$acsearch . ':' . $areacode . ' (' . $areaname . ') numbers only',
			'!44:None (all UK local numbers)'
		);
	}
	if (count($dmx_tmp_var['prefixmenu']))
	{
		$dmx_tmp_var['prefix_drop_down'] 	= dmx_generate_select($dmx_tmp_var['prefixmenu'], $prefix);
	}
	else
	{
		$dmx_tmp_var['prefix_drop_down'] 	= dmx_generate_select(array($prefix), $prefix);
	}
	$dmx_tmp_var['prefix_display'] = count($dmx_tmp_var['prefixmenu']) > 1 ? 'inline' : 'none';

	// Calculate colspan for entire results table
	$dmx_tmp_var['num_r_table_cols'] = $dmx_tmp_var['cols'] * (3 - !$dmx_tmp_var['showclass'] - !$dmx_tmp_var['showgold']) + $dmx_tmp_var['cols'] - 1;
	
	// Work our currency symbol
	$currency_symbol = dmx_get_currency_symbol(isset($dmx_response['Currency']) ? $dmx_response['Currency'] : 'UKPX');			

	// Place returned numbers is array
	$numbers = isset($dmx_response['Num']) ? explode(',', $dmx_response['Num']) : array();
	$dmx_tmp_var['num_results'] = count($numbers) - 1;
	if ($dmx_tmp_var['num_results'] > 0)
	{
		$dmx_tmp_var['tariffspec'] = $dmshop->_Last_R['TariffSpec'];
		for ($i=0; $i<$dmx_tmp_var['num_results']; $i++)
		{
			$n = explode(':', $numbers[$i]);
			if (isset($n[1]))
			{
				$dmx_tmp_var['numbers'][$i]['native']     = $n[0];
				$dmx_tmp_var['numbers'][$i]['formatted']  = $n[1];
				$dmx_tmp_var['numbers'][$i]['goldval']    = $currency_symbol . $n[2];
				$dmx_tmp_var['numbers'][$i]['class_icon'] = 'pro_p_8.gif';
			}
		}
		// Calculate number of rows in results table
		if ( ceil($dmx_tmp_var['num_results']/ $dmx_tmp_var['cols']) < $dmx_tmp_var['rows'] )
		{
			$dmx_tmp_var['rows'] = ceil($dmx_tmp_var['num_results'] / $dmx_tmp_var['cols']);
		}
		// Make sure their are no undefined offsets in the numbers array!
		$i =  $dmx_tmp_var['cols'] * ($dmx_tmp_var['rows'] - 1);
		for ($j=0; $j<$dmx_tmp_var['cols']; $j++)
		{
			if (!isset($dmx_tmp_var['numbers'][$i+$j]['native']))
			{
				$dmx_tmp_var['numbers'][$i+$j]['native'] = $dmx_tmp_var['numbers'][$i+$j]['formatted']	= $dmx_tmp_var['numbers'][$i+$j]['goldval'] = '';		
			}
		}
	}
	
	// How many pages are there?
	if ($dmx_tmp_var['showpages'] && isset($dmx_response['QntPages']) && $dmx_response['QntPages'] > 1)
	{
		$dmx_tmp_var['showpages'] = 1;
		$dmx_tmp_var['page_no']   = $dmx_response['Page'];
		$dmx_tmp_var['num_pages'] = $dmx_response['QntPages'];
		$dmx_tmp_var['from_page'] = $dmx_tmp_var['page_no'] - 2 > 1 ?  $dmx_tmp_var['page_no'] - 2 : 1;
		$dmx_tmp_var['to_page']   = $dmx_tmp_var['page_no'] + 2 < $dmx_tmp_var['num_pages'] ? $dmx_tmp_var['page_no'] + 2 : $dmx_tmp_var['num_pages'];
		if ($dmx_tmp_var['to_page'] - $dmx_tmp_var['from_page'] <  5)
		{
			$dmx_tmp_var['to_page'] = $dmx_tmp_var['from_page'] + 5 < $dmx_tmp_var['num_pages'] ? $dmx_tmp_var['from_page'] + 5 : $dmx_tmp_var['num_pages'];
		}
		if ($dmx_tmp_var['to_page'] - $dmx_tmp_var['from_page'] <  5 && $dmx_tmp_var['from_page'] < 3)
		{
			$dmx_tmp_var['from_page'] = 1;
		}
	}
	else
	{
		$dmx_tmp_var['showpages'] = 0;
	}
	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------

function dmx_prepare_orderdealership($comp_name, $xparams)
{
	global $dmx_tmp_var;

	// Prepare variables substituted in component template
	
	// Look for 'page code' overrides for template control variables
	$ovparams = array('dealer_type');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);

	// Retrieve form field values for redisplay, if necessary
	$fields = array('dmx_companyname', 'dmx_brandname', 'dmx_contactname',
					'dmx_contactemail', 'dmx_custservemail', 'dmx_contactphone', 'dmx_contactfax',
					'dmx_mainwebsiteurl', 'dmx_custbasebiz', 'dmx_custbaseres', 'dmx_prodfocus', 'dmx_sellinboundnum', 'dmx_selltelserv', 'dmx_selltelhard',
					'dmx_comments');
	$dmx_tmp_var['form'] = dmx_construct_form_array($comp_name, $fields);

	// Preserve checkboxes if redisplaying form
	if ($dmx_tmp_var['form']['value']['dmx_sellinboundnum']) $dmx_tmp_var['form']['value']['dmx_sellinboundnum'] = 'checked="checked"';
	if ($dmx_tmp_var['form']['value']['dmx_selltelserv']   ) $dmx_tmp_var['form']['value']['dmx_selltelserv'] 	 = 'checked="checked"';
	if ($dmx_tmp_var['form']['value']['dmx_selltelhard']   ) $dmx_tmp_var['form']['value']['dmx_selltelhard'] 	 = 'checked="checked"';
	
	$dmx_tmp_var['grabut_suffix'] = isset($xparams['result_order']) ? 'forward' : 'reload';
	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------

function dmx_prepare_register($comp_name, $xparams, $options)
{
	global $dmx_tmp_var;

	// Variables from register_options.php
	$title 				= $options['title'];
	$country 			= $options['country'];
	$country_selected 	= $options['country_selected'];

	// Prepare variables substituted in component template
	// Retrieve form field values for redisplay, if necessary
	//
	$fields = array('dmx_title', 'dmx_first', 'dmx_last', 'dmx_email', 'dmx_newslevel',
					'dmx_company', 'dmx_addr1', 'dmx_addr2', 'dmx_addr3', 'dmx_towncity', 'dmx_pc_zip', 'dmx_country',
					'dmx_tel_day', 'dmx_tel_home', 'dmx_tel_mobile', 'dmx_fax',
					'dmx_pin1', 'dmx_pin2', 'dmx_mem_date', 'dmx_mem_word');
	$form['value']['dmx_newslevel'] = 2;
	$dmx_tmp_var['form'] = dmx_construct_form_array($comp_name, $fields, $form);

	// Generate select drop-down menu containing titles
	$dmx_tmp_var['title_drop_down'] = dmx_generate_select($title, $dmx_tmp_var['form']['value']['dmx_title']);
	// Generate select drop-down menu containing countries
	$country_selected = $dmx_tmp_var['form']['value']['dmx_country'] ? $dmx_tmp_var['form']['value']['dmx_country'] : $country_selected;
	$dmx_tmp_var['country_drop_down'] = dmx_generate_select($country, $country_selected);

	$dmx_tmp_var['grabut_suffix'] = isset($xparams['result_register']) ? 'forward' : 'reload';

	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------

function dmx_prepare_serviceplanselector($comp_name, $xparams, $options, $tfocus)
{
	global $dmx_tmp_var, $dmx_init_response, $dmshop, $dmx_debug, $json;
	
	$focus 	= $tfocus->index;
	$cs 	= $tfocus->cs;
	$cp 	= $tfocus->cp;

	if (!$focus) 
	{
		$dmx_tmp_var['err_msg'] = 'There is nothing in your shopping trolley at the moment, so the service plan selector cannot be used.';
		return $dmx_tmp_var;
	}
	
	// Fetch service and plan options
	$dmshop->_R['Item.Idx'] = $focus;
	$dmshop->_R['Number'] 	= $dmx_init_response['Item'][$focus]['Number'];
	$ovparams = array('TariffFilter', 'ServiceFilter', 'PlanFilter');
	$dmshop->_R = dmx_resolve_params($dmshop->_R, $xparams, $ovparams);
	$dmshop->request();
	$dmx_debug->msg($dmshop->debug->flush());

	if ($dmshop->result->status == false || !count($dmshop->result->response))
	{
		$dmx_tmp_var['err_msg'] = $dmx_options['err_msg']['comserr'];
		return $dmx_tmp_var;
	}
	$dmx_response = $dmshop->result->response;
	dmx_add_benchmark('Response from ' . $dmshop->url, $GLOBALS['time1']);
	if ($dmx_response['Cmd'] == 'GetSvcPlanOptionsNak')
	{
		$dmx_tmp_var['err_msg'] = 'Could not get service and plan options';
		return $dmx_tmp_var;
	}

	// Get Service info
	if (isset($dmx_response['S']))
	{
		foreach($dmx_response['S'] as $i => $service)
		{
			$dmx_tmp_var['services'][] = array(
				'name' => $service['Name'],
				'desc' => $service['Desc'],
				'icon' => dmx_get_number_icon($service['Name']),
				'func' => dmx_get_function_icons($service['Name'])
			);
			if (strtolower($cs) == strtolower($service['Name'])) $csi = $i - 1; // Current Service index
		}
	}
	if (!isset($csi))
	{
		$dmx_tmp_var['err_msg'] = 'Number\'s service (' . $cs . ') not amongst returned options.';
		return $dmx_tmp_var;
	}
	$dmx_tmp_var['num_servs'] = count($dmx_tmp_var['services']);

	// Get Plan info
	if (isset($dmx_response['P']))
	{
		foreach($dmx_response['P'] as $i => $plan)
		{
			$dmx_tmp_var['plans'][] = array(
				'name' => $plan['Name'],
				'desc' => $plan['Desc'],
				'icon' => dmx_get_plan_icon($plan['Name'])
			);
			if (strtolower($cp) == strtolower($plan['Name'])) $cpi = $i - 1; // Current Plan index
		}
	}
	if (!isset($cpi))
	{
		$dmx_tmp_var['err_msg'] = 'Number\'s plan (' . $cp . ') not amongst returned options.';
		return $dmx_tmp_var;
	}
	$dmx_tmp_var['num_plans'] = count($dmx_tmp_var['plans']);

	// Traverse pricing grid
	foreach($dmx_response['S'] as $i => $serv)
	{
		foreach($serv['P'] as $j => $t)
		{
			list($s, $r, $m, $p) = explode(',', $t['Pricing']);
			$dmx_tmp_var['grid'][$i - 1][$j - 1] = array(
				'tariff'		=> $t['Tariff'],
				'service'		=> $dmx_tmp_var['services'][$i-1]['name'],
				'plan'			=> $dmx_tmp_var['plans'][$j-1]['name'],
				'setup'			=> $s ? sprintf('%.2f', $s) : '0.00',
				'rental'		=> $r ? sprintf('%.2f', $r) : '0.00',
				'months_min'	=> $m,
				'ppm_text'		=> substr($p, 0, 20)
			);
		}
	}
	
	// Now make available to javascript
	$dmx_tmp_var['grid_json'] = $json->encode($dmx_tmp_var['grid']);
	
	// Prepare variables substituted in component template
	// Look for 'page code' overrides for template control variables
	$ovparams = array('showservices', 'showplans', 'link_cce', 'div_typinv', 'div_fulltariff', 'hook_typinv', 'hook_fulltariff', 'width');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);
	
	if ($dmx_tmp_var['showborder']) $dmx_tmp_var['width'] = $dmx_tmp_var['width'] - 22;
	
	if ($dmx_tmp_var['div_fulltariff'] 	== 'internal') $dmx_tmp_var['div_fulltariff']	= $comp_name . '_tariffguide';
	if ($dmx_tmp_var['div_typinv']  	== 'internal') $dmx_tmp_var['div_typinv'] 		= $comp_name . '_typinv';
	
	$dmx_tmp_var['number_native'] 	 = $dmx_init_response['Item'][$focus]['Number'];
	$dmx_tmp_var['number_formatted'] = $dmx_init_response['Item'][$focus]['FmtNum'];
	$dmx_tmp_var['index'] 			 = $focus;

	$dmx_tmp_var['cs'] 	= $cs; 	// Current Service
	$dmx_tmp_var['cp'] 	= $cp; 	// Current Plan
	$dmx_tmp_var['csi'] = $csi; // Current Service index
	$dmx_tmp_var['cpi'] = $cpi; // Current Plan    index

	$dmx_tmp_var['sg_num'] 			 = dmx_format_sgm_number($dmx_tmp_var['number_formatted']);
	$dmx_tmp_var['sg_service']		 = dmx_get_number_icon($cs);
	$dmx_tmp_var['sg_plan']		 	 = dmx_get_plan_icon($cp);
	$dmx_tmp_var['sg_functions']	 = dmx_get_function_icons($cs);

	$dmx_tmp_var['currency_symbol'] = dmx_get_currency_symbol($dmx_response['Currency']);			

	// Get current tariff & pricing info
	$t = $dmx_tmp_var['grid'][$csi][$cpi];
	$dmx_tmp_var['cur_tariff']		 = $t['tariff'];
	$dmx_tmp_var['cur_setup']		 = $t['setup'];
	$dmx_tmp_var['cur_rental']		 = $t['rental'];
	$dmx_tmp_var['cur_months_min']	 = $t['months_min'];
	$dmx_tmp_var['cur_ppm_text']	 = $t['ppm_text'];

	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------

function dmx_prepare_tariffguide($comp_name, $xparams, $options, $tfocus)
{
	global $dmx_tmp_var, $dmx_init_response, $dmshop, $dmx_debug, $dmx_session;

	// Variables from tarfiffguide_options.php
	$range 			= $options['range'];
	$params_ch_opt	= $options['params_ch_opt'];

	$focus 	= $tfocus->index;
	$cs 	= $tfocus->cs;
	$cp 	= $tfocus->cp;

	if (!$focus) 
	{
		$dmx_tmp_var['err_msg'] = 'There is nothing in your shopping trolley at the moment, so the tariff guide cannot be used.';
		return $dmx_tmp_var;
	}
	
	// Fetch service and plan alternatives for current tariff
	$dmshop->_R['Item.Idx'] = $focus;
	$dmshop->_R['Number'] 	= $dmx_init_response['Item'][$focus]['Number'];
	$ovparams = array('TariffFilter', 'ServiceFilter', 'PlanFilter');
	$dmshop->_R = dmx_resolve_params($dmshop->_R, $xparams, $ovparams);
	$dmshop->request();
	$dmx_debug->msg($dmshop->debug->flush());

	if ($dmshop->result->status == false || !count($dmshop->result->response))
	{
		$dmx_tmp_var['err_msg'] = $dmx_options['err_msg']['comserr'];
		return $dmx_tmp_var;
	}
	$dmx_response = $dmshop->result->response;
	dmx_add_benchmark('Response from ' . $dmshop->url, $GLOBALS['time1']);
	if ($dmx_response['Cmd'] == 'GetSvcPlanOptionsNak')
	{
		$dmx_tmp_var['err_msg'] = 'Could not get service and plan options';
		return $dmx_tmp_var;
	}

	// Look for history overrides of service and plan - MAYBE JUST LOOK IN $_REQUEST INSTEAD?
	$ovparams = array('service', 'plan');
	$xparams  = dmx_check_memory('tariffguide', $xparams, $ovparams);

	// Have $xparams set the service and/or plan? - otherwise it comes from trolley focus
	if (isset($xparams['service'])) $cs = $xparams['service']; 
	if (isset($xparams['plan'])) 	$cp = $xparams['plan']; 

	// Get current service index
	if (isset($dmx_response['S']))
	{
		foreach($dmx_response['S'] as $i => $service) if (strtolower($cs) == strtolower($service['Name'])) $csi = $i - 1; // Current Service index
	}
	if (!isset($csi))
	{
		$dmx_tmp_var['err_msg'] = 'Number\'s service (' . $cs . ') not amongst returned options.';
		return $dmx_tmp_var;
	}

	// Get current plan index
	if (isset($dmx_response['P']))
	{
		foreach($dmx_response['P'] as $i => $plan) if (strtolower($cp) == strtolower($plan['Name'])) $cpi = $i - 1; // Current Plan index
	}
	if (!isset($cpi))
	{
		$dmx_tmp_var['err_msg'] = 'Number\'s plan (' . $cp . ') not amongst returned options.';
		return $dmx_tmp_var;
	}

	// Traverse grid to get panel ids
	foreach($dmx_response['S'] as $i => $serv)
	{
		foreach($serv['P'] as $j => $t) $grid[$i - 1][$j - 1] = strtolower($t['Tariff']);
	}

	// -------------------------------------------------
	// 1 - Get T2 panel id for  current service and plan
	$dmx_tmp_var['t2_current'] = $grid[$csi][$cpi];
	
	// -------------------------------------------------------------------
	// 2 - Get T2 panel ids for other ranges, for current service and plan

	/*
	
	Public.EC-	   X	UK-NGN-Free		X 	Bas
	Public.EXV-			UK-NGN-G6			Pro
	Public.EXF-			UK-NGN-Local		Ent
	Public.EXS-			UK-NGN-Nat
						UK-NGN-G7
						UK-GEO-All
						UK-PN-D
						UK-PN-K
						UK-PN-PN2
	
	*/
	
	$service_prefix = substr($grid[$csi][$cpi], 0, strpos($grid[$csi][$cpi], '-'));
	$plan_suffix 	= substr($grid[$csi][$cpi], strrpos($grid[$csi][$cpi], '-') + 1);
	
	// $range array comes from tariffguide_options.php
	foreach($range as $r)
	{
		$id = strtolower($service_prefix . '-' . $r . '-' . $plan_suffix);
		if ($id != $grid[$csi][$cpi]) $dmx_tmp_var['t2_ranges'][] = $id;
	}
	
	// -------------------------------------------------------------------
	// 3 - Get T2 panel ids for other services, for current range and plan
	$i = 0;
	while (each($grid))
	{
		$dmx_tmp_var['t2_services'][] = $grid[$i][$cpi];
		$i++;
	}
	unset($dmx_tmp_var['t2_services'][$csi]);

	// -------------------------------------------------------------------
	// 4 - Get T2 panel ids for other plans, for current range and service
	$dmx_tmp_var['t2_plans'] = $grid[$csi];
	unset($dmx_tmp_var['t2_plans'][$cpi]);
	
	// ------------------------------------------------------------------
	// 5 - Get outbound panel ids for current T2 tariff
	$dmshop->_R  = $params_ch_opt;
	$dmshop->_R['TrolleyID']  = $dmx_session;
	$dmshop->_R['TariffSpec'] = $grid[$csi][$cpi];
	$dmshop->request();
	$dmx_debug->msg($dmshop->debug->flush());
	
	if ($dmshop->result->status == false || !count($dmshop->result->response))
	{
		$dmx_tmp_var['err_msg'] = $dmx_options['err_msg']['comserr'];
		return $dmx_tmp_var;
	}
	$dmx_response = $dmshop->result->response;
	dmx_add_benchmark('Response from ' . $dmshop->url, $GLOBALS['time1']);
	if ($dmx_response['Cmd'] == 'GetChooserOptionsNak')
	{
		$dmx_tmp_var['err_msg'] = 'Could not get outbound tariffs';
		return $dmx_tmp_var;
	}
	
	$ob_tariffs = explode(',', $dmx_response['Opt'][1]['vOBTariffList']);
	foreach($ob_tariffs as $t)
	{
		$dmx_tmp_var['ob_tariffs'][] = strtolower(str_replace('_', '-', $t));
	}
	
	$dmx_tmp_var['panel'] = dmx_init_panel(); // Make the panel object available to template

	dmx_store('tariffguide', ''); // Clear memory

	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------

function dmx_prepare_trolley($comp_name, $xparams, $options)
{
	global $dmx_tmp_var, $dmx_init_response, $dmx_debug, $json;

	// Look for 'page code' overrides for template control variables
	$ovparams 	 = array('variant', 'showicons', 'showoptions', 'showtotals', 'showactions', 'usepopup',
						 'div_typinv', 'hook_typinv', 'div_cce', 'hook_cce', 'hook_cce_update',
						 'headerurl', 'transfer_target', 'auto_sync_interval');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);

	if (isset($dmx_init_response['EXTENDED']))
	{
		// Use extended response from 
		$dmx_response = $dmx_init_response;
		$dmx_debug->msg("<b>Using extended response from initialise trolley</b>\n");
	}
	else
	{
		global $dmshop;
		$dmshop->request();
		$dmx_debug->msg($dmshop->debug->flush());
		
		if ($dmshop->result->status == false || !count($dmshop->result->response))
		{
			$dmx_tmp_var['err_msg'] = $dmx_options['err_msg']['comserr'];
			return $dmx_tmp_var;
		}
		$dmx_response = $dmshop->result->response;
		dmx_add_benchmark('Response from ' . $dmshop->url, $GLOBALS['time1']);
		if ($dmx_response['Cmd'] == 'ListTrolleyNak')
		{
			$dmx_tmp_var['err_msg'] = 'Could not get trolley listing';
			return $dmx_tmp_var;
		}
	}

	// Prepare variables substituted in component template
	$dmx_tmp_var['logged_in'] 			 = $dmx_response['LoggedIn'] == 'Y';
	$dmx_tmp_var['cust_id'] 			 = $dmx_response['DMID'] ? $dmx_response['DMID'] : '';
	$dmx_tmp_var['authenticated'] 		 = $dmx_response['Authenticated'] == 'Y';
	$dmx_tmp_var['checkout_ready'] 		 = $dmx_response['CheckoutReady'] == 'Y';
	$dmx_tmp_var['status_icon_infotext'] = $dmx_tmp_var['checkout_ready'] ? 'trolley_go' : ($dmx_response['QntItems'] ? 'trolley_log' : 'trolley_empty'); // Set js variable that contains validicon infotext
	$dmx_tmp_var['usepopup'] 			 = $dmx_tmp_var['usepopup'] ? '_blank' : '_self';
	$dmx_tmp_var['price_class'] 		 = $dmx_tmp_var['usepopup'] == '_blank' || $dmx_tmp_var['div_typinv'] ? 'popup' : 'forward';

	if ($dmx_tmp_var['div_typinv']  == 'internal') $dmx_tmp_var['div_typinv'] 	= $comp_name . '_typinv';
	if ($dmx_tmp_var['div_cce']  	== 'internal') $dmx_tmp_var['div_cce'] 		= $comp_name . '_cce';
	
	// Work our currency symbol
	$dmx_tmp_var['currency_symbol'] = dmx_get_currency_symbol($dmx_response['Currency']);			

	// Trolley items
	$dmx_tmp_var['num_items'] = $dmx_response['QntItems'];
	$t = array();
	for ($i=0; $i<$dmx_tmp_var['num_items']; $i++)
	{
		// Items in trolley
		$n = $dmx_response['Item'][$i+1];
		$t[$i]['native']       = $n['Number'];
		$t[$i]['formatted']    = $n['FmtNum'];				
		$t[$i]['gold']         = $n['GV'];				
		$t[$i]['details']      = $n['Description'];				
		$t[$i]['tariff']       = $n['Tariff'];				
		$t[$i]['setup']        = $n['Initial']  ? sprintf('%.2f', $n['Initial'])  : '0.00';				
		$t[$i]['rental']       = $n['Monthly']  ? sprintf('%.2f', $n['Monthly'])  : '0.00';				
		$t[$i]['ukllppm']      = $n['UKLLPPM']  ? sprintf('%.2f', $n['UKLLPPM'])  : '0.00';				
		$t[$i]['payout']       = $n['Payout'] == 'P';				
		$t[$i]['price']        = $n['SubTotal'] ? sprintf('%.2f', $n['SubTotal']) : '0.00';				
		$t[$i]['info_var']     = 'ready'; // Which js variable to use for infotext, HARDCODED for now		
		$t[$i]['status_icon']  = 'valid'; // Which validicon to display beside number, HARDCODED for now			
		list($s, $p) = explode(':', $n['SvcPlan']);
		$t[$i]['service'] 	   = $s;
		$t[$i]['plan'] 	   	   = $p;
		$t[$i]['sg_icon'] 	   = dmx_get_number_icon($s);
		$t[$i]['sg_plan'] 	   = dmx_get_plan_icon($p);
		$t[$i]['sg_num'] 	   = dmx_format_sgm_number($t[$i]['formatted']);
	}
	$dmx_tmp_var['item'] = $t;			

	// Totals
	$dmx_tmp_var['total_net'] = $dmx_response['TotalNet'];
	$dmx_tmp_var['total_tax'] = $dmx_response['TotalTax'];
	$dmx_tmp_var['total_inc'] = $dmx_response['TotalInc'];
	
	// Outstanding items in user's account
	if (isset($dmx_response['QntOSOrders']))
	{
		$dmx_tmp_var['outst_num']   = $dmx_response['QntOSOrders'];
		$dmx_tmp_var['outst_total'] = $dmx_response['OSTotalInc'];
	}
	else
	{
		$dmx_tmp_var['outst_num'] = $dmx_tmp_var['outst_total'] = 0;
	}
	$dmx_tmp_var['total_plus_outst'] = $dmx_tmp_var['total_inc'] + $dmx_tmp_var['outst_total']; 
	$dmx_tmp_var['ganal_accno']     = $GLOBALS['dmx_options']['ganal']['accno']; // Google analytics account no for offsite redirect
	$dmx_tmp_var['ganal_trans_rep'] = $GLOBALS['dmx_options']['ganal']['accno'] != 'OFF' && $GLOBALS['dmx_options']['ganal']['send_trans_rep'] ? urlencode(dmx_generate_ganal_report($dmx_response)) : '';

	// JSON summary, for trolley polling
	$temp['total_inc'] = $dmx_response['TotalInc'];
	if ($dmx_tmp_var['cust_id'])
	{
		$temp['session_status'] = $dmx_tmp_var['cust_id'] . ' (' . ($dmx_tmp_var['authenticated'] ? '+'  : '-') . ')';
	}
	else
	{
		$temp['session_status'] = '';
	}
	$temp['source'] 	= $_SESSION['DMSHOP']['source'];
	$temp['trolley_id'] = $dmx_init_response['TrolleyID'];
	$temp['life_s'] 	= $dmx_init_response['LifetimeTimeoutSecs'];
	$temp['auth_s'] 	= $dmx_init_response['SecsToHitTimeout'];
	$dmx_tmp_var['trolley_summary_json'] = $json->encode($temp);
	
	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------

function dmx_prepare_typicalfirstinvoice($comp_name, $xparams, $options, $tfocus)
{
	global $dmx_tmp_var, $dmx_init_response, $dmshop, $dmx_debug;

	$focus 	= $tfocus->index;
	$cs 	= $tfocus->cs;
	$cp 	= $tfocus->cp;
	
	// Look for 'page code' overrides for template control variables
	$ovparams = array('showincludes', 'showbutton');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);
	
	$dmshop->_R['Item.Idx'] = $focus;
	
	if (!isset($xparams['tariff']))
	{
		$ovparams = array('tariff'); // Get the number from the data store
		$xparams = dmx_check_memory('trolley', $xparams, $ovparams);
	}
	if (isset($xparams['tariff'])) $dmshop->_R['Item.ModTariff'] = $xparams['tariff']; // Value supplied in page always takes precedence
	$dmshop->request();
	$dmx_debug->msg($dmshop->debug->flush());
	
	if ($dmshop->result->status == false || !count($dmshop->result->response))
	{
		$dmx_tmp_var['err_msg'] = $GLOBALS['dmx_options']['err_msg']['comserr'];
		return $dmx_tmp_var;
	}
	$dmx_response = $dmshop->result->response;
	dmx_add_benchmark('Response from ' . $dmshop->url, $GLOBALS['time1']);
	if ($dmx_response['Cmd'] == 'GetItemBreakdownNak')
	{
		$dmx_tmp_var['err_msg'] = 'Could not generate typical first invoice';
		return $dmx_tmp_var;
	}
	
	// Prepare variables substituted in component template
	$ovparams = array('number', 'popup', 'button_url'); // Get the number from the data store
	$dmx_tmp_var = dmx_check_memory('trolley', $dmx_tmp_var, $ovparams);
	// xparams override history
	$ovparams = array('number', 'popup');
	$dmx_tmp_var = dmx_resolve_params($dmx_tmp_var, $xparams, $ovparams);
	
	$dmx_tmp_var['number'] = $dmx_init_response['Item'][$focus]['FmtNum'];
	
	// Generate range for service graphic number icon
	list($s, $p) = explode(':', $dmx_response['SvcPlan']);
	$dmx_tmp_var['service'] 	= $s;
	$dmx_tmp_var['plan'] 	   	= $p;
	$dmx_tmp_var['sg_service'] 	= dmx_get_number_icon($s);
	$dmx_tmp_var['sg_num']  	= dmx_format_sgm_number($dmx_tmp_var['number']);
	$dmx_tmp_var['sg_plan'] 	= dmx_get_plan_icon($p);
	
	// Work our currency symbol
	$dmx_tmp_var['currency_symbol'] = dmx_get_currency_symbol($dmx_response['Line'][1]['Curr']);	
	
	// Number of lines in invoice
	$dmx_tmp_var['num_lines'] = count($dmx_response['Line']);
	
	// Text for button
	$dmx_tmp_var['button_text'] = isset($xparams['buttontext']) ? $xparams['buttontext'] : ($dmx_tmp_var['popup'] ? 'Close Window' : 'Back');
	
	// Javascript function attached to button
	$dmx_tmp_var['button_func'] = isset($xparams['buttonfunc']) ? $xparams['buttonfunc'] : ($dmx_tmp_var['popup'] ? 'window.close()' : 'return true');
	
	for ($i=1; $i<=$dmx_tmp_var['num_lines']; $i++)
	{
		$dmx_tmp_var['title'][$i] = $dmx_response['Line'][$i]['SvcItem'];
		$dmx_tmp_var['description'][$i] = $dmx_response['Line'][$i]['Description'];
		$dmx_tmp_var['includes'][$i] = isset($dmx_response['Line'][$i]['Includes']) ? $dmx_response['Line'][$i]['Includes'] : '';
		$dmx_tmp_var['price'][$i] = sprintf('%.2f', $dmx_response['Line'][$i]['LineChg']);
		// Process description HTML for use in template
		// PHP 5
		//$dmx_tmp_var['description'][$i] = str_ireplace('<b>', '<strong>', $dmx_tmp_var['description'][$i]);
		//$dmx_tmp_var['description'][$i] = str_ireplace('</b>', '</strong> ', $dmx_tmp_var['description'][$i]);
		//$dmx_tmp_var['description'][$i] = str_ireplace('<small>', '', $dmx_tmp_var['description'][$i]);
		//$dmx_tmp_var['description'][$i] = str_ireplace('</small>', '', $dmx_tmp_var['description'][$i]);
		// PHP 4 equivalent
		$dmx_tmp_var['description'][$i] = eregi_replace('<b>', '<strong>', $dmx_tmp_var['description'][$i]);
		$dmx_tmp_var['description'][$i] = eregi_replace('</b>', '</strong> ', $dmx_tmp_var['description'][$i]);
		$dmx_tmp_var['description'][$i] = eregi_replace('<small>', '', $dmx_tmp_var['description'][$i]);
		$dmx_tmp_var['description'][$i] = eregi_replace('</small>', '', $dmx_tmp_var['description'][$i]);
	}
	
	// Show 'includes' column if any row of the 'includes' column is populated, and showincludes is on
	// $dmx_tmp_var['includes'][2] = "Point 1\nCuddly Bear\nEtc etc etc ...";
	$dmx_tmp_var['showincludes'] = trim(implode($dmx_tmp_var['includes'])) && $dmx_tmp_var['showincludes'] ? 1 : 0;
	
	// Totals
	$dmx_tmp_var['total_net'] = $dmx_response['TotalItemNet'];
	$dmx_tmp_var['total_tax'] = $dmx_response['TotalItemTax'];
	$dmx_tmp_var['total_inc'] = $dmx_response['TotalItemInc'];
	
	return $dmx_tmp_var;
}

// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------

function dmx_generate_box_size_css_rule($h = NULL)
{
	// Generate CSS rule to enforce component size
	$style = isset($h) && $h != '*' ? 'max-height: ' . $h . 'px; overflow: auto;' : 'max-height: none;';
	return $style;
}

// -------------------------------------------------------------------------------------------------

function dmx_generate_comp_width_css_rule($w = NULL)
{
	// Generate CSS rule to enforce header width
	$style = isset($w) && $w != '*' ? 'max-width: ' . $w . 'px;' : 'max-width: none;';
	return $style;
}

// -------------------------------------------------------------------------------------------------
//  P A R S E   &   O U T P U T   X C O M   T E M P L A T E 
// -------------------------------------------------------------------------------------------------

function dmx_parse_template($tpl, $comp_name = '', $user_tpl = '')
{
	// Parse component template and output HTML to display component	
	global $dmx_tmp_var, $dmx_options, $dmx_debug;
	
	$dmx_glib = $dmx_options['glib'];
	
	$time1 = dmx_add_benchmark('Start of dmx_parse_template(' . $tpl . ')');

	$dmx_debug->divide();
	
	// Work out what template to render
	$response_type = strtolower($dmx_tmp_var['response_type']);
	if ($dmx_tmp_var['ajax'] && $response_type == 'json')
	{
		$render = DOCROOT . $dmx_options['templates'] . 'json/' . $tpl . '.json';
	}
	else
	{
		if ($user_tpl)
		{
			// Override default template
			$tpl = $user_tpl;
			$dmx_debug->msg('<b>Using customised template</b>');
			$render = DOCROOT . $dmx_options['my_templates'];
		}
		else
		{
			$render = DOCROOT . $dmx_options['templates'];
		}
		$render .= ($dmx_options['doctype'] == 'XHTML 1.0 Strict' || $dmx_options['doctype'] == 'XHTML 1.1') ? 'xhtml/' :  'html/';
		$render .= $tpl . '.tpl';
	}
	
	if ($dmx_options['debug_level'])
	{
		$dmx_debug->msg('<b>PASSING VARIABLES TO TEMPLATE: ' . $render . '</b>');
		reset($dmx_tmp_var);
		ksort($dmx_tmp_var);
		while (list($key, $value) = each($dmx_tmp_var))
		{
			$var  = strtolower($key);
			$$var = $value;
			$dmx_debug->msg('$' . $var . ' = ' . htmlentities(print_r($value, true)));
		}
	}
	else
	{
		$dmx_tmp_var = array_change_key_case($dmx_tmp_var, CASE_LOWER);
		extract($dmx_tmp_var);
	}
	
	// Prepare two values of the 'result conditions', one for use in links and one for use in forms (prevents double encoding)
	$rc_forms = isset($dmx_tmp_var['result_conditions']) ? $dmx_tmp_var['result_conditions'] : '';
	$rc_links = urlencode($rc_forms);
	$dmx_debug->msg();

	// Now parse the html / php template
	$dmx_options['abs'] ? ob_start(array($GLOBALS['abs_glos'], 'substitute')) : ob_start(array($GLOBALS['dmx_glos'], 'substitute'));
	$success = @include($render);
	if ($success === FALSE)
	{
		echo('<b>Call to non-existant XComponent template: ' . $tpl . '</b><br />');
		echo('Using customised template: ' . ($user_tpl ? 'true' : 'false') . '<br />');
	}
	ob_end_flush();

	dmx_add_benchmark('End of dmx_parse_template()', $time1);
	
	if ($ajax && $ajax_debug && $response_type != 'json') $dmx_debug->display();
}

// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------

function dmx_read_component_options($component_class)
{
	@include DOCROOT . $GLOBALS['dmx_options']['templates'] . 'options/' . $component_class . '_options.php';
	unset($component_class);
	return(compact(array_keys(get_defined_vars())));
}

// -------------------------------------------------------------------------------------------------

function dmx_construct_form_array($comp_name, $fields, $form = array())
{
	// Returns an array representing form fields, fetching historical values as necessary
	// This function helps user-entered values to be preserved and redisplayed when form validation fails
	// The $form parameter can be used to pass in defaults
	
	$r = dmx_check_memory($comp_name, array(), array('form'));
	$mem = isset($r['form']) ? $r['form'] : array();
	$loop_limit = count($fields);
	for ($i=0; $i<$loop_limit; $i++)
	{
		$form['value'][$fields[$i]] = isset($mem['value'][$fields[$i]]) ? $mem['value'][$fields[$i]] : (isset($form['value'][$fields[$i]]) ? $form['value'][$fields[$i]] : '');
		$form['error'][$fields[$i]] = isset($mem['error'][$fields[$i]]) ? $mem['error'][$fields[$i]] : '';
	}
	return $form;
}

// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------

function dmx_generate_ganal_report($trolley)
{
	// Generate the transaction report for Google Analytics
	// This is a helper function for dmx_render('dmshop.trolley')
	// AND MAY BE DELETED
	//
	// ... Get $order_id, $affiliate, $total, $tax, etc ...
	//
	$order_id  = $GLOBALS['dmx_session'];
	$affiliate = $GLOBALS['dmx_options']['dealer_id'];
	$total     = $trolley['TotalInc'];
	$tax       = $trolley['TotalTax'];
	$shipping  = '0';
	$city      = 'london';
	$state     = 'england';
	$country   = 'uk';
	// Total line in transaction report (UTM:T)
	$r  = "UTM:T|$order_id|$affiliate|$total|$tax|$shipping|$city|$state|$country\n";
	
	// Item lines in transaction report (UTM:I)
	for ($i=1; $i<=$trolley['QntItems']; $i++)
	{
		// For each item (line) in the order
		// ... Get $product_code, $product_name, etc ...
		//
		$product_code     = $trolley['Item'][$i]['FmtNum']; // Perhaps hyphens are not allowed
		$product_name     = dmx_gen_product_name($trolley['Item'][$i]['Number']); // Pass unformated intnat number
		$product_category = strtolower($trolley['Item'][$i]['Service']);
		$price            = $trolley['Item'][$i]['SubTotal'];
		$quantity         = 1;
		$r 				 .= "UTM:I|$order_id|$product_code|$product_name|$product_category|$price|$quantity"  .  "\n";
	}

	// Return the transaction report as a string
	return $r;
}

// -------------------------------------------------------------------------------------------------

function dmx_gen_product_name($number)
{
	// If the number is a non-0207 UK GEO, report as 'UKGEO', otherwise send 1st 5 digits (eg. 44800, 44207...)
	
	$pr_name = substr($number, 0 , 5);
	if (ereg('44[12]..', $pr_name) && $pr_name != '44207') $pr_name = 'UKGEO';
	return $pr_name;
}

// -------------------------------------------------------------------------------------------------
// R E S O L V E   P A R A M E T E R   P R E C E D E N C E
// -------------------------------------------------------------------------------------------------

function dmx_resolve_params($params, $xparams, $ovparams)
{
	// xparams supplied in the page code can override defualts
	// for the parameters named in the $ovparams array
	
	global $dmx_debug;
	$dmx_debug->msg('<b>HANDLING X PARAMETER PRECEDENCE</b>');
	foreach ($ovparams as $p)
	{
		$dmx_debug->msg('Looking for override for ' . $p . '... ');
		if ( isset( $xparams[strtolower($p)] ) )
		{
			$params[$p] = $xparams[strtolower($p)];
			$dmx_debug->msg('<b>Found override: ' . $xparams[strtolower($p)] . '</b>');
		}
	}
	$dmx_debug->msg();
	return $params;
}

// -------------------------------------------------------------------------------------------------

function dmx_check_memory($comp_name, $params, $ovparams)
{
	// Look for paramters that override defaults for component instance $comp_name
	// from component history

	global $dmx_memory, $dmx_debug;
	$dmx_debug->msg('<b>CHECKING MEMORY FOR '. $comp_name . '</b>');
	
	$comp_name_upper = strtoupper($comp_name);
	if (! isset($dmx_memory[$comp_name_upper]) )
	{
		$dmx_debug->msg('Memory for ' . $comp_name .' not found');
		$dmx_debug->msg();
		return $params;
	}
	foreach ($ovparams as $p)
	{
		$dmx_debug->msg('Looking for override for ' . $p . '... ');
		if ( isset($dmx_memory[$comp_name_upper][$p]) )
		{
			$params[$p] = $dmx_memory[$comp_name_upper][$p];
			$dmx_debug->msg('<b>Found override: ' . $dmx_memory[$comp_name_upper][$p] . '</b>');
		}
	}
	$dmx_debug->msg();
	return $params;
}

// -------------------------------------------------------------------------------------------------

function dmx_filter_panels($panel_id)
{
	return(ereg($GLOBALS['dmx_tmp_var']['search'], $panel_id) !== FALSE);
}

// -------------------------------------------------------------------------------------------------

?>