<?php
/**
* @version	$Id: multilang_formatter.php 15137 2012-03-04 08:06:21Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

defined('FULL_PATH') or die('restricted access!');

class kMultiLanguage extends kFormatter
{

	/**
	 * Multilanguage helper
	 *
	 * @var kMultiLanguageHelper
	 */
	var $helper = null;

	public function __construct()
	{
		parent::__construct();

		$this->helper = $this->Application->recallObject('kMultiLanguageHelper');
	}

	/**
	 * Returns ML field equivalent to field name specifed
	 *
	 * @param string $field_name
	 * @param bool $from_primary use primary/current language for name custruction
	 * @return string
	 */
	function LangFieldName($field_name, $from_primary = false)
	{
		static $primary_language = null;

		if (preg_match('/^l[0-9]+_/', $field_name)) {
			return $field_name;
		}

		if (!isset($primary_language)) {
			$primary_language = $this->Application->GetDefaultLanguageId();
		}

		$lang = $from_primary ? $primary_language : $this->Application->GetVar('m_lang');

		if (!$lang || ($lang == 'default')) {
			$lang = $primary_language;
		}

		return 'l' . $lang . '_' . $field_name;
	}

	/**
	 * The method is supposed to alter config options or cofigure object in some way based on its usage of formatters
	 * The methods is called for every field with formatter defined when configuring item.
	 * Could be used for adding additional VirtualFields to an object required by some special Formatter
	 *
	 * @param string $field_name
	 * @param array $field_options
	 * @param kDBBase $object
	 */
	function PrepareOptions($field_name, &$field_options, &$object)
	{
		if (getArrayValue($field_options, 'master_field') || getArrayValue($field_options, 'options_processed')) {
			return ;
		}

		$lang_field_name = $this->LangFieldName($field_name);

		//substitute title field
		$title_field = $this->Application->getUnitOption($object->Prefix, 'TitleField');
		if ($title_field == $field_name) {
			$this->Application->setUnitOption($object->Prefix, 'TitleField', $lang_field_name);
		}

		$languages = $this->helper->getLanguages();
		$primary_language_id = $this->Application->GetDefaultLanguageId();
		$fields = $this->Application->getUnitOption($object->Prefix, 'Fields', Array ());
		$virtual_fields = $this->Application->getUnitOption($object->Prefix, 'VirtualFields', Array ());

		// substitute real field
		if (array_key_exists($field_name, $fields)) {
			$tmp_field_options = $fields[$field_name];
			$tmp_field_options['master_field'] = $field_name;
			$tmp_field_options['error_field'] = $field_name;
			$field_required = array_key_exists('required', $tmp_field_options) && $tmp_field_options['required'];

			foreach ($languages as $language_id) {
				// make all non-primary language fields not required
				if ($language_id != $primary_language_id) {
					unset($tmp_field_options['required']);
				}
				elseif ($field_required) {
					$tmp_field_options['required'] = $field_required;
				}

				$translated_field = 'l' . $language_id . '_' . $field_name;
				$fields[$translated_field] = $tmp_field_options;
				$object->SetFieldOptions($translated_field, $tmp_field_options);
			}

			// makes original field non-required
			$object_fields = $object->getFields(); // use kDBBase::getFields, since there are no kDBList::setRequired
			unset($fields[$field_name]['required'], $object_fields[$field_name]['required']);
			$object->setFields($object_fields);

			// prevents real field with formatter set to be saved in db
			$virtual_fields[$field_name] = $object_fields[$field_name];
			$object->SetFieldOptions($field_name, $object_fields[$field_name], true);
		}
		elseif (array_key_exists($field_name, $virtual_fields)) {
			// substitute virtual field
			$calculated_fields = $this->Application->getUnitOption($object->Prefix, 'CalculatedFields', Array ());
			$calculated_field_special = array_key_exists($object->Special, $calculated_fields) ? $object->Special : (array_key_exists('', $calculated_fields) ? '' : false);
			/* @var $calculated_fields Array */

			$tmp_field_options = $virtual_fields[$field_name];
			$tmp_field_options['master_field'] = $field_name;
			$tmp_field_options['error_field'] = $field_name;
			$field_required = array_key_exists('required', $tmp_field_options) && $tmp_field_options['required'];

			foreach ($languages as $language_id) {
				// make all non-primary language fields not required
				if ($language_id != $primary_language_id) {
					unset($tmp_field_options['required']);
				}
				elseif ($field_required) {
					$tmp_field_options['required'] = $field_required;
				}

				$translated_field = 'l' . $language_id . '_' . $field_name;
				$virtual_fields[$translated_field] = $tmp_field_options;
				$object->SetFieldOptions($translated_field, $tmp_field_options, true);

				// substitute calculated fields associated with given virtual field
				foreach ($calculated_fields as $special => $special_fields) {
					if (!array_key_exists($field_name, $special_fields)) {
						continue;
					}

					$calculated_fields[$special][$translated_field] = str_replace('%2$s', $language_id, $special_fields[$field_name]);

					if ($special === $calculated_field_special) {
						$object->addCalculatedField($translated_field, $calculated_fields[$special][$translated_field]);
					}
				}

				// manually copy virtual field back to fields (see kDBBase::setVirtualFields about that)
				$fields[$translated_field] = $tmp_field_options;
				$object->SetFieldOptions($translated_field, $tmp_field_options);
			}

			// remove original calculated field
			foreach ($calculated_fields as $special => $special_fields) {
				unset($calculated_fields[$special][$field_name]);
			}

			$object_calculated_fields = $object->getCalculatedFields();
			unset($object_calculated_fields[$field_name]);
			$object->setCalculatedFields($object_calculated_fields);

			// save back calculated fields
			$this->Application->setUnitOption($object->Prefix, 'CalculatedFields', $calculated_fields);

			// makes original field non-required
			$object_fields = $object->getFields(); // use kDBBase::getFields, since there are no kDBList::setRequired
			unset($fields[$field_name]['required'], $object_fields[$field_name]['required']);
			$object->setFields($object_fields);

			$virtual_field_options = $object->GetFieldOptions($field_name, true);
			unset($virtual_fields[$field_name]['required'], $virtual_field_options['required']);
			$object->SetFieldOptions($field_name, $virtual_field_options, true);
		}

		// substitute grid fields
		$grids = $this->Application->getUnitOption($object->Prefix, 'Grids', Array ());
		/* @var $grids Array */

		foreach ($grids as $name => $grid) {
			if ( getArrayValue($grid, 'Fields', $field_name) ) {
				// used by column picker to track column position
				$grids[$name]['Fields'][$field_name]['formatter_renamed'] = true;

				if (!array_key_exists('format', $grids[$name]['Fields'][$field_name])) {
					// prevent displaying value from primary language
					// instead of missing value in current language
					$grids[$name]['Fields'][$field_name]['format'] = 'no_default';
				}

				if ( !isset($grid['Fields'][$field_name]['title']) ) {
					$grids[$name]['Fields'][$field_name]['title'] = 'column:la_fld_' . $field_name;
				}

				kUtil::array_rename_key($grids[$name]['Fields'], $field_name, $lang_field_name);
			}

			// update sort fields - used for sorting and filtering in SQLs
			foreach ($grid['Fields'] as $grid_fld_name => $fld_options) {
				if (isset($fld_options['sort_field']) && $fld_options['sort_field'] == $field_name) {
					$grids[$name]['Fields'][$grid_fld_name]['sort_field'] = $lang_field_name;
				}
			}
		}
		$this->Application->setUnitOption($object->Prefix, 'Grids', $grids);

		// substitute default sortings
		$sortings = $this->Application->getUnitOption($object->Prefix, 'ListSortings', Array ());
		/* @var $sortings Array */

		foreach ($sortings as $special => $the_sortings) {
			if (isset($the_sortings['ForcedSorting'])) {
				kUtil::array_rename_key($sortings[$special]['ForcedSorting'], $field_name, $lang_field_name);
			}
			if (isset($the_sortings['Sorting'])) {
				kUtil::array_rename_key($sortings[$special]['Sorting'], $field_name, $lang_field_name);
			}
		}
		$this->Application->setUnitOption($object->Prefix, 'ListSortings', $sortings);

		//TODO: substitute possible language-fields sortings after changing language
		if ( $object->isVirtualField($field_name) ) {
			$virtual_fields[$field_name]['options_processed'] = true;
		}
		else {
			$fields[$field_name]['options_processed'] = true;
		}

		$field_options['options_processed'] = true;
		$this->Application->setUnitOption($object->Prefix, 'Fields', $fields);
		$this->Application->setUnitOption($object->Prefix, 'VirtualFields', $virtual_fields);
	}

	/*function UpdateSubFields($field, $value, &$options, &$object)
	{

	}
	*/

	/**
	 * Checks, that field value on primary language is set
	 *
	 * @param string $field
	 * @param mixed $value
	 * @param Array $options
	 * @param kDBItem $object
	 */
	function UpdateMasterFields($field, $value, &$options, &$object)
	{
		$master_field = array_key_exists('master_field', $options) ? $options['master_field'] : false;
		if (!$master_field) {
			return ;
		}

		// moved here from Parse, because at Parse time not all of the fields may be set - this is extremly actual, when working with PopulateMlFields mode
		$lang = $this->Application->GetVar('m_lang');
		$def_lang = $this->Application->GetDefaultLanguageId();

		if ( !$this->Application->GetVar('allow_translation') && ($lang != $def_lang) && $object->isRequired($field) ) {
			$def_lang_field = 'l' . $def_lang . '_' . $master_field;

			if ( !$object->ValidateRequired($def_lang_field, $options) ) {
				$object->SetError($master_field, 'primary_lang_required');

				if ( $object->isField($def_lang_field) ) {
					$object->SetError($def_lang_field, 'primary_lang_required');
				}
			}
		}
	}

	/**
	 * Formats value of a given field
	 *
	 * @param string $value
	 * @param string $field_name
	 * @param kDBItem|kDBList $object
	 * @param string $format
	 * @return string
	 */
	function Format($value, $field_name, &$object, $format=null)
	{
		$master_field = $object->GetFieldOption($field_name, 'master_field');

		if (!$master_field) { // if THIS field is master it does NOT have reference to it's master_field
			$lang = $this->Application->GetVar('m_lang');
			$value = $object->GetDBField('l'.$lang.'_'.$field_name); //getting value of current language
			$master_field = $field_name; // THIS is master_field
		}
		$options = $object->GetFieldOptions($field_name);
		$format = isset($format) ? $format : ( isset($options['format']) ? $options['format'] : null);

		// use strpos, becase 2 comma-separated formats could be specified
		if ($value == '' && strpos($format, 'no_default') === false) { // try to get default language value
			$def_lang_value = $object->GetDBField('l'.$this->Application->GetDefaultLanguageId().'_'.$master_field);
			if ($def_lang_value == '') {
				return NULL;
			}

			return $this->_replaceFCKLinks($def_lang_value, $options, $format); //return value from default language
		}

		return $this->_replaceFCKLinks($value, $options, $format);
	}

	/**
	 * Performs required field check on primary language
	 *
	 * @param mixed $value
	 * @param string $field_name
	 * @param kDBItem $object
	 * @return mixed
	 * @access public
	 */
	public function Parse($value, $field_name, &$object)
	{
		if ($value == '') return NULL;

		return $value;
	}
}