<?php

App::uses('ModelBehavior', 'Model');
App::uses('AppModel', 'Model');

/**
 * BemmelhorTranslate Behavior
 *
 * Modified version of cake's core TranslateBehavior.
 * If no translated record is found for the locale, the main record will be returned.
 * TranslateBehavior used to return nothing in that case.
 *
 * @category Behavior
 * @package  Bemmelhor
 * @version  1.0
 * @author   Fabricio S Costa <fabriciojf@gmail.com>
 * 
 * @link     http://www.bemmelhor.org
 */
class BemmelhorTranslateBehavior extends ModelBehavior {

/**
 * Used for runtime configuration of model
 */
	public $runtime = array();

/**
 * Field names
 *
 * @var array
 */
	public $translationFields = array();

/**
 * Callback
 *
 * $config for BemmelhorTranslateBehavior should be
 * array( 'fields' => array('field_one',
 * 'field_two' => 'FieldAssoc', 'field_three'))
 *
 * With above example only one permanent hasMany will be joined (for field_two
 * as FieldAssoc)
 *
 * $config could be empty - and translations configured dynamically by
 * bindTranslation() method
 *
 * @param Model $model
 * @param array $config
 * @return mixed
 * @access public
 */
	public function setup(Model $model, $config = array()) {
		$db = ConnectionManager::getDataSource($model->useDbConfig);
		if (!$db->connected) {
			trigger_error(
				__('Datasource %s for BemmelhorTranslateBehavior of model %s is not connected', $model->useDbConfig, $model->alias),
				E_USER_ERROR
			);
			return false;
		}

		$this->settings[$model->alias] = array();
		$this->runtime[$model->alias] = array('fields' => array());
		$this->translateModel($model);
		$this->translationFields[$model->alias] = $config;
		//return $this->bindTranslation($model, $config, false);
	}

/**
 * Callback
 *
 * @return void
 * @access public
 */
	public function cleanup(Model $model) {
		//$this->unbindTranslation($model);
		unset($this->settings[$model->alias]);
		unset($this->runtime[$model->alias]);
	}

/**
 * Get field names for Translation
 *
 * @param object $model
 * @return array
 * @access public
 */
	public function getTranslationFields(Model $model) {
		if (Set::numeric(array_keys($this->translationFields[$model->alias]))) {
			return $this->translationFields[$model->alias];
		} else {
			return array_keys($this->translationFields[$model->alias]);
		}
	}

/**
 * afterFind Callback
 *
 * @param array $results
 * @param boolean $primary
 * @return array Modified results
 * @access public
 */
	public function afterFind(Model $model, $results, $primary) {
		$locale = $this->_getLocale($model);

		if (empty($locale) || empty($results)) {
			return $results;
		}

		$fields = $this->getTranslationFields($model);
		$RuntimeModel = $this->translateModel($model);

		if ($primary && isset($results[0][$model->alias])) {
			$i = 0;
			foreach ($results as $result) {
				if (!isset($result[$model->alias][$model->primaryKey])) {
					continue;
				}

				$translations = $RuntimeModel->find('all', array(
					'conditions' => array(
						$RuntimeModel->alias . '.model' => $model->alias,
						$RuntimeModel->alias . '.foreign_key' => $result[$model->alias][$model->primaryKey],
						$RuntimeModel->alias . '.field' => $fields,
					),
				));

				foreach ($translations as $translation) {
					$field = $translation[$RuntimeModel->alias]['field'];

					// Original row
					/*if (isset($results[$i][$model->alias][$field])) {
						$results[$i][$field.'Original'] = $results[$i][$model->alias][$field];
					}*/

					// Translated row
					if ($translation[$RuntimeModel->alias]['locale'] == $locale &&
						isset($results[$i][$model->alias][$field])) {
						$results[$i][$model->alias][$field] = $translation[$RuntimeModel->alias]['content'];
					}

					// Other translations
					if (!Set::numeric(array_keys($this->translationFields[$model->alias])) &&
						isset($results[$i][$model->alias][$field])) {
						if (!isset($results[$i][$field . 'Translation'])) {
							$results[$i][$field . 'Translation'] = array();
						}
						$results[$i][$field . 'Translation'][] = $translation[$RuntimeModel->alias];
					}
				}

				$i++;
			}
		}

		return $results;
	}

/**
 * Save translation only (in i18n table)
 *
 * @param object $model
 * @param array $data
 * @param boolean $validate
 */
	public function saveTranslation(Model $model, $data = null, $validate = true) {
		$model->data = $data;
		if (!isset($model->data[$model->alias])) {
			return false;
		}

		$locale = $this->_getLocale($model);
		if (empty($locale)) {
			return false;
		}

		$RuntimeModel = $this->translateModel($model);
		$conditions = array('model' => $model->alias, 'foreign_key' => $model->id);

		foreach ($model->data[$model->alias] as $field => $value) {
			unset($conditions['content']);
			$conditions['field'] = $field;
			if (is_array($value)) {
				$conditions['locale'] = array_keys($value);
			} else {
				$conditions['locale'] = $locale;
				if (is_array($locale)) {
					$value = array($locale[0] => $value);
				} else {
					$value = array($locale => $value);
				}
			}
			$translations = $RuntimeModel->find('list', array('conditions' => $conditions, 'fields' => array($RuntimeModel->alias . '.locale', $RuntimeModel->alias . '.id')));
			foreach ($value as $_locale => $_value) {
				$RuntimeModel->create();
				$conditions['locale'] = $_locale;
				$conditions['content'] = $_value;
				if (array_key_exists($_locale, $translations)) {
					if (!$RuntimeModel->save(array($RuntimeModel->alias => array_merge($conditions, array('id' => $translations[$_locale]))))) {
						return false;
					}
				} else {
					if (!$RuntimeModel->save(array($RuntimeModel->alias => $conditions))) {
						return false;
					}
				}
			}
		}

		return true;
	}

/**
 * afterDelete Callback
 *
 * @return void
 * @access public
 */
	public function afterDelete(Model $model) {
		$RuntimeModel = $this->translateModel($model);
		$conditions = array('model' => $model->alias, 'foreign_key' => $model->id);
		$RuntimeModel->deleteAll($conditions);
	}

/**
 * Get selected locale for model
 *
 * @return mixed string or false
 * @access protected
 */
	protected function _getLocale(Model $model) {
		if (!isset($model->locale) || is_null($model->locale)) {
			/*
			if (!class_exists('I18n')) {
				App::import('Core', 'i18n');
			}
			$I18n = I18n::getInstance();
			$I18n->l10n->get(Configure::read('Config.language'));
			$model->locale = $I18n->l10n->locale;
			*/
			$model->locale = Configure::read('Config.language');
		}

		return $model->locale;
	}

/**
 * Get instance of model for translations
 *
 * @return object
 * @access public
 */
	public function &translateModel(Model $model) {
		if (!isset($this->runtime[$model->alias]['model'])) {
			if (!isset($model->translateModel) || empty($model->translateModel)) {
				$className = 'I18nModel';
			} else {
				$className = $model->translateModel;
			}

			$this->runtime[$model->alias]['model'] = ClassRegistry::init($className, 'Model');
		}
		if (!empty($model->translateTable) && $model->translateTable !== $this->runtime[$model->alias]['model']->useTable) {
			$this->runtime[$model->alias]['model']->setSource($model->translateTable);
		} elseif (empty($model->translateTable) && empty($model->translateModel)) {
			$this->runtime[$model->alias]['model']->setSource('i18n');
		}
		return $this->runtime[$model->alias]['model'];
	}

}

if (!defined('CAKEPHP_UNIT_TEST_EXECUTION')) {
/**
 * @package	 cake
 * @subpackage  cake.cake.libs.model.behaviors
 */
	class I18nModel extends AppModel {

		public $name = 'I18nModel';

		public $useTable = 'i18n';

		public $displayField = 'field';

		public $actsAs = array(
			'Cached' => array(
				'prefix' => array(
					'',
				),
			),
		);
	}
}
