<?php namespace ModuleRelationships;

/**
 * Class Definition
 * A definition of a single relationship.
 *
 * @package ModuleRelationships
 */
class Definition {

	/** @const bool True value which indicates that the relationship is symmetric, so there is no master - slave hierarchy. */
	const TYPE_SYMMETRIC = true;

	/** @const bool False value which indicates  that the relationship is asymmetric, so there is distinctive master - slave hierarchy. */
	const TYPE_ASYMMETRIC = false;

	/** @var bool True for symmetrical relationship, false for asymmetrical one. */
	private $symmetric;

	/** @var string The name of the master module. */
	private $master;

	/** @var string The name of the slave module. */
	private $slave;

	/** @var string The name of this relationship. */
	private $name;

	/** @var array The list of additional options. */
	private $options;

	/**
	 * @param bool   $symmetric True for symmetrical relationship, false for asymmetrical one.
	 * @param string $master    The name of the master module.
	 * @param string $slave     The name of the slave module.
	 * @param string $name      The name of the relationship.
	 * @param array  $options   The additional options.
	 */
	public function __construct($symmetric, $master, $slave, $name, $options = []) {
		$this->symmetric = (bool) $symmetric;
		$this->master = $master;
		$this->slave = $slave;
		$this->name = $name;
		$this->options = $options;

		// Handle filters
		$filter = [];
		if (key_exists('filter', $this->options)) {
			foreach ($this->options['filter'] as $name => $params) {
				$filter[$name]['field'] = $params[0];

				// Handle options
				$filter[$name]['options'] = null;
				if (isset($params[1])) {
					switch ($params[1]) {
						case 'bool':
						case 'boolean':
							$filter[$name]['options'] = [ __('No'), __('Yes') ];
							break;

						default:
							$filter[$name]['options'] = $params[1];
					}
				}

			}
		}
		$this->options['filter'] = $filter;
	}

	/** @return bool True for symmetrical relationship, false for asymmetrical one. */
	public function isSymmetric() {
		return $this->symmetric;
	}

	/** @return string The name of the master module. */
	public function getMaster() {
		return $this->master;
	}

	/** @return string The name of the slave module. */
	public function getSlave() {
		return $this->slave;
	}

	/** @return string The name of this relationship. */
	public function getName() {
		return $this->name;
	}

	/** @return array The list of additional options. */
	public function getOptions() {
		return $this->options;
	}

	/**
	 * Get the available records for the this relationship.
	 *
	 * @param array $conditions The parameters for the search.
	 * @param int   $page       The parameters for the search.
	 *
	 * @return array[] The list of found records.
	 */
	public function find($conditions = [], $page = 1) {
		$query = [];

		// Get conditions
		$query['conditions'] = key_exists('conditions', $this->options) ? $this->options['conditions'] : [];
		if ($conditions) {

			// Make sure the conditions are save
			foreach ($conditions as $field => $value) {

				// Handle term
				if ($field === '_term') {
					$query['conditions'][] = \ClassRegistry::init($this->slave)->getSearchConditions($value);

				} else {
					$query['conditions']["{$this->slave}.{$field}"] = $value;
				}
			}
		}

		// Additional parameters
		foreach ([ 'order', 'limit' ] as $key) {
			if (key_exists($key, $this->options)) {
				$query[$key] = $this->options[$key];
			}
		}

		// Get the total count
		$count = \ClassRegistry::init($this->slave)->find('count', $query);

		// Pagination
		if (!isset($query['limit'])) {
			$query['limit'] = 20;
		}
		if (empty($page)) {
			$page = 1;
		}
		$query['offset'] = ($page - 1) * $query['limit'];

		// Get data and get the unique ID of the slave module on top
		$records = \ClassRegistry::init($this->slave)->find('all', $query);
		foreach ($records as $i => $record) {
			$records[$i]['slave_fk'] = $record[$this->slave]['id'];
		}

		// Return
		return [
			'page'    => [
				'current' => (int) $page,
				'total'   => ceil($count / $query['limit'])
			],
			'records' => $records
		];
	}

}