<?php
/**
 * <pre>
 * Invision Power Services
 * IP.Board v3.4.6
 * Localization Class.
 *
 * Used for handling language text, money formatting, etc.
 * Last Updated: $Date: 2013-09-04 23:08:17 -0400 (Wed, 04 Sep 2013) $
 * </pre>
 * 
 * @author		Joshua Williams
 * @version		$Rev: 12342 $
 * @since		1.0
 * @copyright	(c) 2001 - 2009 Invision Power Services, Inc.
 *
 *
 * @package		IP.Board
 */ 

class class_localization
{
   /**
    * Current offset
    *
    * @access	public
    * @var		integer
    */	
	public $offset;

   /**
    * Current day
    *
    * @access	public
    * @var		integer
    */	
	public $day;
	
	/**#@+
	* Registry Object Shortcuts
	*
	* @access	protected
	* @var		object
	*/
	protected $registry;
	protected $DB;
	protected $settings;
	protected $request;
	protected $lang;
	protected $member;
	protected $memberData;
	protected $cache;
	protected $caches;
	/**#@-*/
	
   /**
    * Set up time options
    *
    * @access	public
    * @var		array
    */	
	public $time_options = array();
	
   /**
    * Array of words
    *
    * @access	public
    * @var		array
    */	
	public $words = array();
	
   /**
    * Locale
    *
    * @access	public
    * @var		string
    */		
	public $local       = "en_US";
	
   /**
    * Array of loaded language files
    *
    * @access public
    * @var array
    */		
	public $loaded_lang_files = array();

   /**
    * Offset has been set
    *
    * @access	protected
    * @var		boolean
    */	
	protected $offset_set;
	
   /**
    * Determines if lang entries are loaded from the db or the filesystem
    *
    * @access public
    * @var bool
    */	
	public $load_from_db = false;
	
	/**
	 * Force UK/English language
	 *
	 * @access protected
	 * @var	   boolean
	 */
	protected $_forceEnglish = false;
	protected $_isRtl        = false;
	
	/**
	 * Constructor
	 * 
	 * @access	public
	 * @param	string	[$lang]		Language file to load, english by default
	 * @return	@e void
	 */		
	public function __construct( ipsRegistry $registry )
	{
		/* Make objects */
		$this->DB         =  $registry->DB();
		$this->settings   =  $registry->fetchSettings();
		$this->member     =  $registry->member();
		$this->cache      =  $registry->cache();
		$this->caches     =& $registry->cache()->fetchCaches();
		$this->request    =  $registry->fetchRequest();
		$this->memberData =& $registry->member()->fetchMemberData();
		
		/* Prevent notices */
		$this->memberData['member_id']	= !isset($this->memberData['member_id']) ? 0 : $this->memberData['member_id'];
		
		/* Load from database */
		if( $this->settings['safe_mode_skins'] && ! IN_DEV )
		{
			$this->load_from_db = true;
		}
		
		/* Rebuild the cache if needed */
		if( ! $this->caches['lang_data'] )
		{
			$this->rebuildLanguagesCache();		
		}
		
		/* Find the lang we need */
		if( $this->caches['lang_data'] )
		{ 
			foreach( $this->caches['lang_data'] as $_lang )
			{
				$this->languages[] = $_lang;
	
				if( $_lang['lang_default'] )
				{
					$this->local        = $_lang['lang_short'];
					$this->lang_id      = $_lang['lang_id'];
					$this->language_dir = $_lang['lang_id'];
					$this->_isRtl		= intval( $_lang['lang_isrtl'] );
					
					/* Guests get the default */
					if( ! $this->memberData['member_id'] )
					{
						$this->member->language_id = $this->lang_id;
					}
				}
			}
		}
		
		/* Got a guest cookie? */
		if ( ! $this->memberData['member_id'] )
		{
			$langCookie = IPSCookie::get('language');
			
			if ( $langCookie )
			{
				$this->member->language_id = trim( IPSText::parseCleanValue( $langCookie ) );
			}
		}
		
		/* Forcing Engrish? */
		if ( $forceCookie = IPSCookie::get('forceEnglish') )
		{
			if ( $forceCookie )
			{
				$this->_forceEnglish = true;
			}
		}
		
		//-----------------------------------------
		// Time options
		//-----------------------------------------
		
		/* 	%b is month abbr
			%B is full month
			%d is date 01-31
			%Y is 4 digit year
			%g is 2 digit year
			%I is hour 01-12
			%H - hour as a decimal number using a 24-hour clock (range 00 to 23) 
			%M is min 01-59
			%p is am/pm */
		
		$this->time_options = array( 'JOINED' => $this->settings['clock_joined'] ? $this->settings['clock_joined'] : '%d-%B %y',
								     'SHORT'  => $this->settings['clock_short']  ? $this->settings['clock_short']  : '%b %d %Y %I:%M %p',
									 'LONG'   => $this->settings['clock_long']   ? $this->settings['clock_long']   : '%d %B %Y - %I:%M %p',
									 'TINY'   => $this->settings['clock_tiny']   ? $this->settings['clock_tiny']   : '%d %b %Y - %H:%M',
									 'DATE'   => $this->settings['clock_date']   ? $this->settings['clock_date']   : '%d %b %Y',
									 'SHORT2' => $this->settings['clock_short2'] ? $this->settings['clock_short2']   : '%d %B %Y',
									 'TIME'   => '%I:%M %p',
									 'ACP'    => '%d %B %Y, %H:%M',
									 'ACP2'   => '%d %B %Y, %H:%M',
									 'YMD'    => '%Y-%m-%d',
								   );

		//--------------------------------
		// Did we choose a language?
		//--------------------------------

		if ( !empty( $this->request['setlanguage'] ) AND $this->request['langid'] )
		{
			/* Forcing english? */
			if ( $this->request['langid'] == '__english__' )
			{
				IPSDebug::addMessage( "forceEnglish cookie written" );
				IPSCookie::set('forceEnglish', 1, 0 );
				$this->_forceEnglish = true;
			}
			else if ( $this->request['k'] == $this->member->form_hash AND is_array( ipsRegistry::cache()->getCache('lang_data') ) and count( ipsRegistry::cache()->getCache('lang_data') ) )
			{
				foreach( ipsRegistry::cache()->getCache('lang_data') as $data )
				{
					if ( $data['lang_id'] == $this->request['langid'] )
					{
						if( $this->memberData['member_id'] )
						{
							/* Rest variables to prevent loop when this class is next constructed */
							unset( ipsRegistry::$request['langid'] );
							unset( ipsRegistry::$request['setlanguage'] );
							
							IPSMember::save( $this->memberData['member_id'], array( 'core' => array( 'language' => $data['lang_id'] ) ) );
						}
						else
						{
							IPSCookie::set('language', $data['lang_id'] );
						}

						$this->member->language_id = $data['lang_id'];
						$this->member->setProperty( 'language', $data['lang_id'] );
						break;
					}
				}
			}
		}

		//--------------------------------
		// Now set it
		//--------------------------------

		if( $this->member->language_id )
		{
			foreach( $this->caches['lang_data'] as $_lang )
			{
				if( $_lang['lang_id'] == $this->member->language_id )
				{
					$this->local        = $_lang['lang_short'];
					$this->lang_id      = $_lang['lang_id'];
					$this->language_dir = $_lang['lang_id'];
					$this->_isRtl		= intval( $_lang['lang_isrtl'] );
					break;
				}
			}
		}
		
		//-----------------------------------------
		// Set locale
		//-----------------------------------------
		
		//setlocale( LC_ALL, $this->local );
		IPSLib::setlocale( $this->local );
		$this->local_data = localeconv();

		//-----------------------------------------
		// Using in_dev override
		//-----------------------------------------
		
		if ( IN_DEV AND ! $this->_forceEnglish )
		{
			if ( is_dir( IPS_CACHE_PATH . 'cache/lang_cache/master_lang' ) )
			{
				$this->lang_id = 'master_lang';
			}
		}
	}
	
	/**
	 * Returns if we're RTL or not
	 * @return boolean
	 */
	 public function isRtl()
	 {
		 return $this->_isRtl;
	 }
	
	/**
	 * Rebuilds the language cache
	 * 
	 * @access	public
	 * @return 	void
	 */	
	public function rebuildLanguagesCache()
	{
		$langs = array();
		
		$this->DB->build( array( 'select' => '*', 'from' => 'core_sys_lang' ) );
		$this->DB->execute();

		while( $lang = $this->DB->fetch() )
		{
			$langs[] = $lang;	
		}
		
		$this->cache->setCache( 'lang_data', $langs, array( 'array' => 1 ) );
	}
	
	/**
	 * Formats the amount and outputs it in a nice localized format
	 * 
	 * @access	public
	 * @param	float	$amount			Numeric value to format
	 * @param	bool	[$color]		Determines if the output is colored or not      
	 * @param	string	[$force_color]	Force the output to use specified color
	 * @return	string
	 */		 
	public function formatMoney( $amount, $color=true, $force_color='' )
	{
		/* Format the money */
		if( function_exists( 'money_format' ) )
		{
			$formatted = money_format( '%n', doubleval( $amount ) );
		}
		else 
		{
			$formatted = $this->local_data['currency_symbol'] . ' ' . $this->formatNumber( $amount, 2 );
		}

		/* Color the number */
		if( ! $force_color )
		{
			if( $color )
			{
				if( $amount >= 0 )
				{
					$formatted = "<span class='money positive'>{$formatted}</span>";
				}
				else
				{
					$formatted = "<span class='money negative'>{$formatted}</span>";
				}	
			}
		}
		else
		{
			if( $color )
			{
				$formatted = "<span class='money' style='color: {$color}'>{$formatted}</span>";	
			}			
		}

		return $formatted;		
	}
	
	/**
	 * Formats a number based on localized data
	 *
	 * @access	public
	 * @param	float	$number		Number to format
	 * @param	integer	[$places]	Decimal places
	 * @return	float
	 */
	public function formatNumber( $number, $places=0 )
	{ 
		return is_numeric( $number ) ? str_replace( 'x', $this->local_data['thousands_sep'], number_format( $number, $places, $this->local_data['decimal_point'], 'x' ) ) : 0;
	}
		
	/**
	 * Formats the current timestamp to make it read nicely
	 *
	 * @access	public
	 * @param	integer	[$ts]			Timestamp to format, $this->timestamp used if none specified
	 * @param	string	[$format]		Type of formatting to use: short or long
	 * @param	bool	[$relative]		Determines if date will be displayed in relative format
	 * @return	string
	 */	
	public function formatTime( $ts=0, $format='short', $relative=1 )
	{
		return $this->getDate( $ts, strtoupper( $format ), $relative ? 0 : 1 );
	}
	
	/**
	 * Generate Human formatted date string
	 * Return a date or '--' if the date is undef.
	 * We use the rather nice gmdate function in PHP to synchronise our times
	 * with GMT. This gives us the following choices:
	 * If the user has specified a time offset, we use that. If they haven't set
	 * a time zone, we use the default board time offset (which should automagically
	 * be adjusted to match gmdate.         
	 *
	 * @access	public
	 * @param	integer		Unix date
	 * @param	method		LONG, SHORT, JOINED, TINY
	 * @param	integer		Do not use relative dates
	 * @param	integer		Use fully relative dates
	 * @return	string		Parsed time
	 * @since	2.0
	 */
    public function getDate($date, $method, $norelative=0, $full_relative=0, $overrideOffset=NULL)
    {
		//-----------------------------------------
		// INIT
		//-----------------------------------------
		
		$format = '';

		//-----------------------------------------
		// Manual format?
		//-----------------------------------------
	
		if ( empty($method) )
        {
        	$format = $this->time_options['LONG'];
        }
		else if ( ! in_array( strtoupper($method), array_keys( $this->time_options ) ) )
		{
			if ( preg_match( '#^manual\{([^\{]+?)\}#i', $method, $match ) )
			{
				$format = $match[1];
				
				//-----------------------------------------
				// Shut off relative dates if using manual{} tag
				//-----------------------------------------
				
				$norelative	= true;
			}
			else
			{
				$format = $this->time_options['LONG'];
			}
		}
		else
		{
			$format = str_replace( "&#092;", "\\", $this->time_options[ strtoupper( $method ) ] );
		}
				
		if( strpos( $date, "custom" ) !== false )
		{
			if( preg_match( "/{custom:(.+?)}/i", $date, $matches ) )
			{
				if( $matches[1] )
				{
					if( ! preg_match( "#^[0-9]{10}$#", $matches[1] ) )
					{
						$_time = strtotime( $matches[1] );
	
						if ( $_time === FALSE OR $_time == -1 )
						{
							$date = 0;
						}
						else
						{
							$date = $_time;
						}
					}
					else
					{
						$date	= $matches[1];
					}
				}
			}
		}

        if ( ! $date )
        {
            return '--';
        }
        
        if ($this->offset_set == 0 OR ! $this->today_time)
        {
        	// Save redoing this code for each call, only do once per page load
        	
			$this->offset = $this->getTimeOffset();
			
			if ( $this->settings['time_use_relative'] )
			{
				$this->today_time     = $this->_fix( @gmstrftime('%m,%d,%Y', ( time() + $this->offset ) ) );
				$this->yesterday_time = $this->_fix( @gmstrftime('%m,%d,%Y', ( ( time() - 86400 ) + $this->offset ) ) );
			}	
			
			$this->offset_set = 1;
        }
        
        if ( $overrideOffset !== NULL )
        {
        	$this->offset = $overrideOffset;
        	$this->offset_set = 0;
        }
                
        //-----------------------------------------
        // Full relative?
        //-----------------------------------------
        
        if ( $this->settings['time_use_relative'] == 3 )
        {
        	$full_relative = 1;
        }
        
        //-----------------------------------------
        // Future date?
        //-----------------------------------------
        
        if( $date > ( time() + $this->offset ) )
        {
        	$full_relative = 0;
        }
        
        //-----------------------------------------
        // FULL Relative
        //-----------------------------------------

        if ( $full_relative and ( $norelative != 1 ) )
		{
			$diff = time() - $date;
			
			if ( $diff < 3600 )
			{
				if ( $diff < 120 )
				{
					return $this->words['time_less_minute'];
				}
				else
				{
					return sprintf( $this->words['time_minutes_ago'], intval($diff / 60) );
				}
			}
			else if ( $diff < 7200 )
			{
				return $this->words['time_less_hour'];
			}
			else if ( $diff < 86400 )
			{
				return sprintf( $this->words['time_hours_ago'], intval($diff / 3600) );
			}
			else if ( $diff < 172800 )
			{
				return $this->words['time_less_day'];
			}
			else if ( $diff < 604800 )
			{
				return sprintf( $this->words['time_days_ago'], intval($diff / 86400) );
			}
			else if ( $diff < 1209600 )
			{
				return $this->words['time_less_week'];
			}
			else if ( $diff < 3024000 )
			{
				return sprintf( $this->words['time_weeks_ago'], intval($diff / 604800) );
			}
			else
			{
				return $this->_fix( @gmstrftime($format, ($date + $this->offset) ) );
			}
		}
		
		//-----------------------------------------
		// Yesterday / Today
		//-----------------------------------------
		
		else if ( $this->settings['time_use_relative'] and ( $norelative != 1 ) )
		{
			$this_time = $this->_fix( @gmstrftime( '%m,%d,%Y', ($date + $this->offset) ) );
			
			//-----------------------------------------
			// Use level 2 relative?
			//-----------------------------------------
			
			if ( $this->settings['time_use_relative'] == 2 AND ($date <= time()) )
			{
				$diff = time() - $date;

				if ( $diff < 3600 )
				{
					if ( $diff < 120 )
					{
						return $this->words['time_less_minute'];
					}
					else
					{
						return sprintf( $this->words['time_minutes_ago'], intval($diff / 60) );
					}
				}
			}
			
			//-----------------------------------------
			// Still here? 
			//-----------------------------------------
			
			if ( $this_time == $this->today_time )
			{
				return str_replace( '{--}', $this->words['time_today'], $this->_fix( @gmstrftime($this->settings['time_use_relative_format'], ($date + $this->offset) ) ) );
			}
			else if  ( $this_time == $this->yesterday_time )
			{
				return str_replace( '{--}', $this->words['time_yesterday'], $this->_fix( @gmstrftime($this->settings['time_use_relative_format'], ($date + $this->offset) ) ) );
			}
			else
			{
				return $this->_fix( @gmstrftime( $format, ($date + $this->offset) ) );
			}
		}
		
		//-----------------------------------------
		// Normal
		//-----------------------------------------
		
		else
		{
        	return $this->_fix( @gmstrftime($format, ($date + $this->offset) ) );
        }
    }

    /**
	 * Return current TIME (not date)
	 *
	 * @access	public
	 * @param	integer		Unix date
	 * @param	string		PHP strftime() formatting options
	 * @return	string
	 * @since	2.0
	 */
    public function getTime($date, $method='%I:%M %p')
    {
        if ($this->offset_set == 0)
        {
        	// Save redoing this code for each call, only do once per page load

			$this->offset = $this->getTimeOffset();

			$this->offset_set = 1;
        }

        return $this->_fix( @gmstrftime($method, ($date + $this->offset) ) );
    }

    /**
	 * Returns the member's time zone offset
	 *
	 * @access	public
	 * @param	bool	Ignore the ACP adjustment
	 * @return	string
	 * @since	2.0
	 */
    public function getTimeOffset( $ignoreAdjustment=false )
    {
    	$r = 0;
		
    	$this->settings['time_offset']   = ( ! empty( $this->settings['time_offset'] ) ) ? $this->settings['time_offset'] : 0;
    	$this->memberData['time_offset'] = ( isset( $this->memberData['time_offset'] ) ) ? $this->memberData['time_offset'] : null;
    	
    	$r = ( ( $this->memberData['time_offset'] !== null ) ? $this->memberData['time_offset'] : $this->settings['time_offset'] ) * 3600;

		if ( $this->settings['time_adjust'] AND !$ignoreAdjustment )
		{
			$r += ($this->settings['time_adjust'] * 60);
		}
		
		if ( !empty($this->memberData['dst_in_use']) )
		{
			$r += 3600;
		}
    	
    	return $r;
	}
	
    /**
	 * Converts user's date to GMT unix date
	 *
	 * @access	public
	 * @param	array		array( 'year', 'month', 'day', 'hour', 'minute' )
	 * @return	integer
	 * @since	2.0
	 */
    public function convertDateToTimestamp( $time=array() )
    {
		//-----------------------------------------
		// Get the local offset
		//-----------------------------------------

		if( $this->offset_set == 0 )
        {
			$this->offset = $this->getTimeOffset();
			$this->offset_set = 1;
		}
		
		$time = gmmktime( intval($time['hour']), intval($time['minute']), 0, intval($time['month']), intval($time['day']), intval($time['year']) );

 		return $time - $this->offset;
	}
	
	/**
	 * Determines whether the system has a specific pack ({app}_{pack}
	 * @param string	Pack
	 * @param string	App
	 * @return boolean
	 */
	public function hasLanguagePack( $pack, $app='core' )
	{
		if ( $this->load_from_db )
		{
			$count = $this->DB->buildAndFetch( array( 'select'  => 'COUNT(*) as count',
										    		  'from'    => 'core_sys_lang_words',
										    		  'where'   => "lang_id={$this->lang_id} AND word_app='" . $this->DB->addSlashes( $app ) . "' AND word_pack='" . $this->DB->addSlashes( $pack ) . "'" )	);
										    		  
			if ( $count['count'] )
			{
				return true;
			}
		}
		else
		{
			if ( is_file( IPS_CACHE_PATH . 'cache/lang_cache/' . $this->lang_id . '/' . $app . '_' . $pack . '.php' ) )
			{
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * Loads the language file, also loads the global lang file if not loaded
	 * 
	 * @access	public
	 * @param	array 	[$load]			Array of lang files to load
	 * @param	string	[$app]			Specify application to use
	 * @param	string	[$lang]			Language pack to use
	 * @param	boolean	[$forceReload]	Force a language pack to load regardless if it has already
	 * @return	@e void
	 */	 
	public function loadLanguageFile( $load=array(), $app='', $lang='', $forceReload=false )
	{	
		$_MASTER2	= IPSDebug::getMemoryDebugFlag();
				
		/* App */
		$app     = ( $app )  ? $app : IPS_APP_COMPONENT;
		$load    = ( $load ) ? $load : array();
		$global  = ( IPS_AREA == 'admin' ) ? 'core_admin_global' : 'core_public_global';
		$_global = str_replace( 'core_', '', $global );
		
		if ( $lang AND ! IN_DEV )
		{
			$tempLangId		= $this->lang_id;
			$this->lang_id	= $lang;
		}
		
		/* Some older calls may still think $load is a string... */
		if( is_string( $load ) )
		{
			$load = array( $load );
		}
		
		/* Has the global language file been loaded? */
		if ( ! in_array( $global, $this->loaded_lang_files ) AND ( $app == 'core' AND ! in_array( $_global, $load ) ) )
		{
			$load[] = $_global;
		}
		
		/* Load the language file */
		$errors = '';
		
		if( $this->load_from_db OR $this->_forceEnglish )
		{
			$_apps = array( 0 => "'" . $app . "'" );
			
			if( is_array( $load ) AND count( $load ) )
			{
				/* Reformat for query and make sure we're not loading something twice */
				$_load = array();
				
				foreach( $load as $l )
				{
					/* Load global from the core app */
					if ( $l == $_global )
					{
						$_apps[] = "'core'";
					}
					
					/* Already loaded? */
					if ( ! in_array( $app . '_' . $l, $this->loaded_lang_files ) OR $forceReload === TRUE )
					{	
						/* Reformat */
						$_load[] = "'{$l}'";					
					}
					
					/* Add to the loaded array */
					$this->loaded_lang_files[] = $app . '_' . $l;
				}
				
				if( count($_load) )
				{
					/* Query the lang entries */
					$this->DB->build( array( 'select' => 'word_key, word_default, word_custom',
											 'from'   => 'core_sys_lang_words',
											 'where'  => "lang_id={$this->lang_id} AND word_app IN (" . implode( ',', $_apps ) . ") AND word_pack IN ( " . implode( ',', $_load ) . " )" )	);
					$this->DB->execute();

					/* Add to the language array */
					while( $r = $this->DB->fetch() )
					{
						$this->words[$r['word_key']] = ( $this->_forceEnglish ) ? $r['word_default'] : ( $r['word_custom'] ? $r['word_custom'] : $r['word_default'] );
					}
				}
			}
		}
		else
		{
			if( is_array( $load ) AND count( $load ) )
			{
				foreach( $load as $l )
				{
					/* Load global from the core app */
					if ( $l == $global )
					{
						$_file = IPS_CACHE_PATH . 'cache/lang_cache/' . $this->lang_id . '/' . $l . '.php';
						$_test = $l;
					}
					else 			
					{
						$_file = IPS_CACHE_PATH . 'cache/lang_cache/' . $this->lang_id . '/' . $app . '_' . $l . '.php';
						$_test = $app . '_' . $l;
					}
					
					if ( ! in_array( $_test, $this->loaded_lang_files ) OR $forceReload === TRUE )
					{
						if ( is_file( $_file ) )
						{
							include( $_file );/*noLibHook*/
				
							foreach( $lang as $k => $v )
							{
								$this->words[$k] = $v;
							}
				
							$this->loaded_lang_files[] = $_test;
							
							IPSDebug::setMemoryDebugFlag( "Loaded Language File: " . str_replace( IPS_CACHE_PATH, '', $_file ), $_MASTER2 );
						}
						else 
						{
							$errors .= "<li>Missing Language File: " . $_file . "</li>";
							
							IPSDebug::setMemoryDebugFlag( "NO SUCH Language File: " . str_replace( IPS_CACHE_PATH, '', $_file ), $_MASTER2 );
						}
					}
					else
					{
						IPSDebug::setMemoryDebugFlag( "ALREADY LOADED Language File: " . str_replace( IPS_CACHE_PATH, '', $_file ), $_MASTER2 );
					}
				}
			}
		}
		
		if( !empty( $tempLangId ) )
		{
			$this->lang_id	= $tempLangId;
		}
		
		if( $errors && IN_ACP )
		{
			return "<ul>{$errors}</ul>";
		}
	}
	
	/**
	 * Bug in strftime and locals can mean some UTF-8 chars are mangled
	 * @link http://stackoverflow.com/questions/8993971/php-strftime-french-characters
	 * @param	string
	 * @return	string
	 */
	private function _fix( $date )
	{
		/* Reverted for http://community.---.com/resources/bugs.html/_/ip-board/problem-with-a-date-r40950
		if ( IPS_DOC_CHAR_SET == 'UTF-8' )
		{
			return utf8_encode( $date );
		}
		*/	 
		return $date;
	}

	/**
	 * Change Language URL
	 *
	 * @see		http://community.---.com/resources/bugs.html/_/ip-board/switching-language-packs-over-and-over-keeps-adding-to-the-url-r40284
	 * @param	int			Language ID
	 * @return	string
	 */
	 public function changeLanguageUrl( $langId )
	 {
	 	/* Get the real query string */
	 	if( $this->settings['url_type'] == 'query_string' )
	 	{
	 		preg_match( "/\?([^\?]+?)$/", ipsRegistry::$settings['this_url'], $matches );
	 		$_qs	= $matches[1];
	 	}
	 	else
	 	{
	 		$_qs	= parse_url( ipsRegistry::$settings['this_url'], PHP_URL_QUERY );
	 	}
	
	 	parse_str( str_replace( '&amp;', '&', $_qs ), $params );
	
	 	unset( $params['k'] );
	 	unset( $params['setlanguage'] );
	 	unset( $params['cal_id'] );
	 	unset( $params['langid'] );
	 	
	 	$parts = explode(ipsRegistry::$settings['this_url'], "?");
	 	$parts[1] = str_replace( $_qs, '', $parts[1] );
	 	
	 	$url = rtrim( implode( "?", $parts ), '?' );
	 	
	 	$link = ipsRegistry::getClass('output')->buildUrl( $url . '?' . ( count($params) ? ( str_replace( '&', '&amp;', http_build_query( $params ) ) . '&amp;' ) : '' ) . "k={$this->member->form_hash}&amp;setlanguage=1&amp;cal_id={$this->request['cal_id']}&amp;langid={$langId}", 'none' ); 
	 	
		return str_replace( "index=&amp;", "index?", $link);
	 }
	
}