<?php

class AssociatedSetBehavior extends ModelBehavior {

	/**
	 * Prepare the model.
	 *
	 * @param Model $Model    Instance of the model.
	 * @param array $settings Additional settings for the behavior.
	 */
	public function setup(Model $Model, $settings = []) {
		$Model->hasSet = [];
	}

	/**
	 * Get additional view variables to be set in the CMS backend.
	 *
	 * @param Model $Model Instance of the model.
	 *
	 * @return array Associative list of set names and their valur.
	 */
	public function getAdditionalViewVars(Model &$Model) {
		$vars = [];

		// Get all set fields
		foreach ($Model->hasSet as $alias => $params) {
			$vars[Inflector::variable(Inflector::pluralize($alias))] = ClassRegistry::init($alias)->find('list', [ 'conditions' => $params['conditions'] ]);
		}

		return $vars;
	}

	/**
	 * Auto detect columns that are used for set associations.
	 *
	 * @param Model  $Model  Instance of model.
	 * @param string $column Name of the column.
	 *
	 * @return bool True if the supplied column is used to store set associations.
	 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
	public static function handleColumn(Model &$Model, $column) {
		if (substr($column, -4) == '_set') {

			$association = Module::getModelForSetField($column);
			if (!isset($Model->hasSet) || !key_exists($association, $Model->hasSet)) {

				// Add associated set behavior
				if (!$Model->Behaviors->loaded('AssociatedSet')) {
					$Model->Behaviors->load('AssociatedSet');
				}

				// Add parameters
				$Model->$association = ClassRegistry::init($association);
				@$Model->hasSet[$association] = [
					'field'      => $column,
					'className'  => $association,
					'conditions' => null
				];
			}

			return true;
		}

		return false;
	}

	/**
	 * Extract comma separated values into associations.
	 *
	 * @param Model $Model   Instance of model which is about to be saved.
	 * @param array $results Results from the database.
	 * @param bool  $primary True if using primary database index.
	 *
	 * @return array Modified results.
	 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
	function afterFind(Model $Model, $results, $primary = false) {

		// Extract values, only in CMS // TODO NOT WORKING
		if (CMS) {
			foreach ($Model->hasSet as $association => $params) {
				// TODO, never reaches
				foreach ($results as $i => $result) {
					$results[$i][$association] = [];
					if (!empty($result[$Model->alias][$params['field']])) {
						$result[$Model->alias][$params['field']] = preg_replace('/[^0-9,]/', '', $result[$Model->alias][$params['field']]);
						$display = [];
						$associatedIds = explode(',', $result[$Model->alias][$params['field']]);
						$associatedIds = array_filter($associatedIds);
						$associatedIds = implode(',', $associatedIds);
						$set = $Model->$association->find('all', [ 'conditions' => array_merge((array) $params['conditions'], [ "{$association}.id IN(0" . (!empty($associatedIds) ? ',' . $associatedIds : '') . ")" ]), 'recursive' => -1 ]);
						foreach ($set as $data) {
							$display[] = $data[$association][$Model->$association->displayField];
							$results[$i][$association][] = $data[$association];
						}
						$results[$i][$Model->alias][$params['field']] = implode(', ', $display);
					}
				}
			}
		}

		return $results;
	}

	/**
	 * Handle the incoming set data from the form.
	 *
	 * @param Model $Model   Instance of model which is about to be saved.
	 * @param array $options Additional options during save.
	 *
	 * @return bool On false saving will abort, on anything else it will proceed.
	 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
	function beforeSave(Model $Model, $options = []) {

		// Iterate over each set
		foreach ($Model->hasSet as $association => $params) {
			if (isset($Model->data[$association])) {
				$Model->data[$Model->alias][$params['field']] = trim(implode(',', array_unique($Model->data[$association])), ', ');
			}
		}
	}

}
