<?php
/**
 * Полуфабрикаты для форм
 * 
 * Сборка полуфабрикатов для построения контактных форм.
 * 
 * @author veselka.ua
 * @version 0.37
 *
 * @package veselka_ua/themes
 */

class FormsTools extends FormsKernel {

	/**
	 * Типы тега input.
	 */
	protected $input = [];
	/**
	 * Запчасти для сборки полей.
	 */
	protected $view = [];
	/**
	 * Html обертки для форм.
	 */
	protected $fields_html = [];


//////////////////// Обязательные ////////////////////

	/**
	 * Обработка входной информации.
	 * 
	 * Обязательный метод, объявленный в родительском классе.
	 */ 
	protected function input_data_processing() {

		// Запись типов тега input
		$this->input['type'] = array('button', 'checkbox', 'file', 'image', 'radio', 'reset', 'submit', 'text' );
		// Запись расширенных типов тега input
		$this->input['add_type'] = array('password', 'date', 'datetime', 'email', 'number', 'range', 'search', 'tel', 'time', 'url', 'month', 'week', 'hidden');

		// Получение префикса имен полей
		$form_name_prefix = $this->options['form_name'] . '-';
		// Обработка POST данных и запись в локальный массив
		$this->post_data_handling($form_name_prefix);
	}

	/**
	 * Обработка информации и построение результата.
	 * 
	 * Обязательный метод, объявленный в родительском классе.
	 */ 
	protected function result_construct() {
		// Плучение нужных шаблонов полей
		$this->get_fields_templates();
		// Запись html кода вспомогательных элементов
		$this->get_fields_wrappers();
		// Сборка html кода полей
		$this->fields_assembly();
		// Тело формы
		$this->html_construct($this->fields);
	}

	/**
	 * Построение разметки заголовка блока полей.
	 * 
	 * Обязательный метод, объявленный в родительском классе.
	 */ 
	protected function block_header_construct($block_title) {
		// Проверка установлена ли в параметрах запись загловков блоков и есть ли она в наличии
		if( $this->options['block_title'] && isset($block_title) && $block_title != ''  ) {
			// Подготовка разметки загловка из файла field_block_title.php для добавление к результату
			$incubator = $this->fields_html['block_title'];
			$incubator = str_replace('[BLOCK_TITLE]', $block_title, $incubator);
			return $incubator;
		} else {
			return '';
		}
	}

	/**
	 * Построение разметки для текущего одиночного поля (поля формы или строки письма).
	 * 
	 * Обязательный метод, объявленный в родительском классе.
	 */ 
	protected function single_line_construct($incoming_value, $label, $label_name, $block_name) {
		// Стек для временных данных
		// Записываются поля для двойного размещения
		static $tmp_stack = '';
		/**
		 * Замена маркеров на значения.
		 */
		$incubator = $this->field_personification($label_name, $label, $this->placeholders[$block_name][$label_name]);
		// Резервирование результата
		if( isset($incoming_value['row']) && $incoming_value['row'] == true ) {
			if( $tmp_stack == '' ) {
				$tmp_stack .= $incubator;
				$incubator = '';
			} else {
				$tmp_stack .= $incubator;
				/**
				 * Добавление слоя обертки из файла part_form_group.php.
				 * Замена маркера [FIELD_CONTENT] на полученную ранее разметку.
				 */
				$tmp_stack = str_replace('[FIELD_CONTENT]', $tmp_stack, $this->fields_html['form_group']);
				// Добавление к блоку результата
				$incubator = $tmp_stack;
				// Обнуление временной переменной
				$tmp_stack = '';
			}
		} else {
			/**
			 * Добавление слоя обертки из файла part_form_group.php.
			 * Замена маркера [FIELD_CONTENT] на полученную ранее разметку.
			 */
			if( !strpos($incubator, 'hidden') ) {
				$incubator = str_replace('[FIELD_CONTENT]', $incubator, $this->fields_html['form_group']);
			}
		}

		// Добавление к блоку результата
		return $incubator;
	}

	/**
	 * Построение обертки для сформированного результата.
	 * 
	 * Обязательный метод, объявленный в родительском классе.
	 */ 
	protected function html_wrapper_construct($result_set) {
		// Запись результата
		if( !empty($result_set) ) {
			$this->result_set = '';
			// Все блоки последовательно записываются в результирующую переменную
			foreach( $result_set as $block_name => $data ) {
				$this->result_set .= $data;
			}
		}

		// Разметка модального окна
		$incubator = $this->get_form_wrapper();
		// Массив замен для маркеров
		$replacement = $this->get_replacement();
		// Текущий результат - блок полей формы
		$replacement['fields'] = $this->result_set;

		/**
		 * Запись html разметки в результирующую переменную.
		 * Замену маркеров осуществляет метод $this->markers_replacement.
		 */
		$this->result_set = $this->markers_replacement($incubator, $replacement);

	}

//////////////////// Получение оберток полей ////////////////////

	/**
	 * Плучение нужных шаблонов полей.
	 * 
	 * Получает html код поля если еще не получен.
	 * Шаблон загружается из соответствующего файла.
	 */
	private function get_fields_templates() {

		// Проход цикла по массиву полей, для поиска уникальных значений
		foreach( $this->fields as $options ) {

			/**
			 * Проверка наличия html обертки.
			 * Если элемент в массиве оберток с таким именем существует - дублировать нет смысла.
			 */
			if( !isset( $this->fields_html[$options['type']] ) ) {
				/**
				 * Получение имени файла.
				 * Имя необходимого файла образуется из обозначения типа поля.
				 * Возможные типы полей хранятся в $this->input.
				 */
				if( in_array($options['type'], $this->input['type']) ) {
					$field_template = 'field_input_' . $options['type'];
				} elseif( in_array($options['type'], $this->input['add_type']) ) {
					$field_template = 'field_input_text';
				} elseif( isset($options['custom_view']) && $options['custom_view'] ) {
					$options['type'] = $options['custom_view'];
					$field_template = 'field_' . $options['type'];
				} else {
					$field_template = 'field_' . $options['type'];
				}
				// Проверка наличия файла с шаблоном
				$this->check_file_path('/view/forms/', $field_template . '.php');
				// Запись html кода поля
				$this->fields_html[$options['type']] = file_get_contents($this->files_path[$field_template]);
			}
		}
	}


	/**
	 * Запись html кода вспомогательных элементов.
	 */
	private function get_fields_wrappers() {

		// Список оберток для сборки полей
		$this->view[] = 'col_sm';
		$this->view[] = 'form_group';
		$this->view[] = 'control_label';
		$this->view[] = 'block_title';
		$this->view[] = 'help_block';
		$this->view[] = 'required';
		$this->view[] = 'select_option';
		$this->view[] = 'radio_button';
		$this->view[] = 'products_container';

		// Получение html кода оберток для полей
		foreach( $this->view as $name ) {
			// Проверка наличия файла со вспомогательными обертками
			$this->check_file_path('/view/forms/', 'part_' . $name . '.php');
			// Запись html кода поля
			$this->fields_html[$name] = file_get_contents($this->files_path['part_' . $name]);
		}
	}


	/**
	 * Сборка html кода полей.
	 * Добавление оберток к коду полей.
	 */
	private function fields_assembly() {

		foreach( $this->fields_html as $field_type => $html ) {
			// Тлько для разметки полей, вспомогательные запчасти не интересуют
			if( !in_array($field_type, $this->view) ) {
				/**
				 * Запись типа поля.
				 * Замена маркера [FIELD_TYPE] на переданное значение.
				 */
				if( $field_type != 'textarea' && $field_type != 'select' ) {
					$this->fields_html[$field_type] = str_replace('[FIELD_TYPE]', $field_type, $this->fields_html[$field_type]);
				}
				// Скрытые поля
				if( $field_type == 'hidden' ) {
					continue;
				}

				if( $this->options['purpose'] == 'modal' ) {
					/**
					 * Добавление слоя обертки из файла part_col_sm.php.
					 * Замена маркера [FIELD_CONTENT] на полученную ранее разметку.
					 */
					$this->fields_html[$field_type] = str_replace('[FIELD_CONTENT]', $this->fields_html[$field_type], $this->fields_html['col_sm']);
				}
				/**
				 * Добавление названия поля из файла part_control_label.php к существующему коду.
				 */
				$this->fields_html[$field_type] = $this->fields_html['control_label'] . $this->fields_html[$field_type];
			}
		}
	}


//////////////////// Вспомогательные ////////////////////

	/**
	 * Замена маркеров на значения.
	 * 
	 * Маркеры для замены:
	 * 
	 * В файлах группы field_*.php 
	 * [FIELD_TYPE] - тип для <input type="text">
	 * [FIELD_ID] - id тега input или textarea
	 * [FIELD_NAME] - name
	 * [FIELD_VALUE] - value
	 * [FIELD_VALUE_NAME] - value для поля selected
	 * [PLACEHOLDER] - Подсказка
	 * [DATA] - Дата атрибуты
	 * [REQUIRED] - Обязательно для заполнения
	 * [CHECKED] - Чекбокс выбран
	 * [SELECTED] - select выбран
	 * [DISABLED] - Запрещен
	 * 
	 * В файле part_col_sm.php
	 * [COL_SPAN] - Номер грид сетки
	 * [HELP_BLOCK] - Блок ремарки поля
	 * 
	 * В файле part_help_block.php
	 * [HELP_TEXT] - Ремарка поля
	 * 
	 * В файле part_control_label.php
	 * [LABEL_ID] - id тега label
	 * [FIELD_ID] - id тега input
	 * [LABEL] - Название поля
	 * [LABEL_HIDE] - Скрыть лейбл
	 * [LABEL_SPAN] - Отступ
	 * [DEPENDENCE] - Селектор зависимости
	 * [SLAVE] - Зависимый блок
	 */
	private function field_personification($field_name, $label, $placeholder) {

		/**
		 * Массив с информацией для замены.
		 * Индексы массива совпадают с маркерами в файлах с элементами разметки.
		 */
		$replacement = [];
		// Определение стандартных значений
		$replacement['field_name'] = $this->options['form_name'] . '-' . $field_name;
		$replacement['field_id'] = 'input-' . $replacement['field_name'];
		$replacement['field_value'] = '';
		$replacement['placeholder'] = $placeholder;
		$replacement['data'] = '';
		$replacement['required'] = '';
		$replacement['checked'] = '';
		$replacement['col_span'] = '9';
		$replacement['help_block'] = '';
		$replacement['help_text'] = '';
		$replacement['label_id'] = 'label-' . $replacement['field_name'];
		$replacement['label'] = $label;
		$replacement['label_hide'] = '';
		$replacement['label_span'] = ' col-sm-3';
		$replacement['dependence'] = '';
		$replacement['slave'] = '';

		// Скрыть конкретный лейбл чекбокса (указано в конфиге формы)
		if( isset($this->fields[$field_name]['hide_label']) && $this->fields[$field_name]['hide_label'] === true ) {
			$replacement['label'] = '';
		}

		// Если без лейблов, поле во всю ширину
		if( isset($this->options['label_hide']) && $this->options['label_hide'] ) {
			$replacement['col_span'] = '12';
		}
		// Если существует метод для дополнительных приготовлений
		if( method_exists( $this, $this->fields[$field_name]['type'] . '_pre_personification' ) ){
			// Построение списка option
			$replacement['field_value'] = $this->{$this->fields[$field_name]['type'] . '_pre_personification'}($field_name, $placeholder);
		// Для остальных запись значения если установлено
		} elseif( isset($this->fields[$field_name]['value']) ) {
			$replacement['field_value'] = $this->fields[$field_name]['value'];
		}

		// Исключение для подсказок (placeholder) поля для ввода input
		if( in_array( $this->fields[$field_name]['type'], $this->input['type'] ) || in_array( $this->fields[$field_name]['type'], $this->input['add_type'] ) ) {
			// По спецификации только для text, search, url, tel, email, password, или number
			if( in_array( $this->fields[$field_name]['type'], ['textarea', 'text', 'search', 'url', 'tel', 'email', 'password', 'number']) ) {
				if( $replacement['placeholder'] != '' ) {
					$replacement['placeholder'] = '  placeholder="' . $replacement['placeholder'] . '"';
				}
			} elseif( $this->fields[$field_name]['type'] != 'checkbox' ) {
				$replacement['placeholder'] = '';
			}
		}

		// Поиск зависимостей
		foreach( $this->fields as $name => $options) {
			if( isset($options['dependence']) && $options['dependence'] == $field_name ) {
				$replacement['slave'] = ' slave-field';
			}
		}

		// Если без лейблов, поле во всю ширину
		if( isset($this->fields[$field_name]['data']) && is_array($this->fields[$field_name]['data']) && !empty($this->fields[$field_name]['data']) ) {
			foreach( $this->fields[$field_name]['data'] as $key => $value ) {
				$key = str_replace('_','-',$key);
				$replacement['data'] .= ' data-' . $key . '="' . $value . '"';
			}
		}

		/**
		 * Определение значений полей.
		 * Заполнение происходит на основании параметров формы.
		 */
		// Обязательно для заполнения
		if( isset($this->fields[$field_name]['required']) && $this->fields[$field_name]['required'] == true ) {
			// Атрибута тега - сигнализирующий об обязательном заполнении поля
			$replacement['required'] = ' required ';
			// Звездочка в названии поля
			$replacement['label'] .= $this->fields_html['required'];
		}
		// Подпись
		if( isset($this->fields[$field_name]['help_block']) && $this->fields[$field_name]['help_block'] ) {
			// В содержимом файл part_help_block.php заменяется маркер [HELP_TEXT] на подпись указанную в параметрах текущего поля
			$replacement['help_block'] = str_replace('[HELP_TEXT]', $this->fields[$field_name]['help_block'], $this->fields_html['help_block']); 
		}
		// Вывод в две колонки
		if( isset($this->fields[$field_name]['row']) && $this->fields[$field_name]['row'] == true ) {
			$replacement['col_span'] = '3';
		}
		// Зависимость от другого поля
		if( isset($this->fields[$field_name]['dependence']) && $this->fields[$field_name]['dependence'] ) {
			$replacement['dependence'] = ' depend' . '-' . $this->fields[$field_name]['dependence'];
		}
		// Скрытие лейблов для статических форм
		if( isset($this->options['label_hide']) && $this->options['label_hide'] ) {
			$replacement['label_hide'] = ' label-hide';
			$replacement['label_span'] = '';
			//$replacement['label'] = '';
		}
		/**
		 * Получение обертки для поля.
		 * В зависимости от параметра custom_view текущего поля может быть получена нестандартная обертка.
		 */
		if( isset($this->fields[$field_name]['custom_view']) && $this->fields[$field_name]['custom_view'] ) {
			// Получение html разметки поля
			$incubator = $this->fields_html[$this->fields[$field_name]['custom_view']];
		} else {
			// Получение html разметки поля
			$incubator = $this->fields_html[$this->fields[$field_name]['type']];
		}

		/**
		 * Возвращает html разметку.
		 * Замену маркеров осуществляет метод $this->markers_replacement.
		 */
		return $this->markers_replacement($incubator, $replacement);
	}


	/**
	 * Дополнительные приготовления для select.
	 */
	private function select_pre_personification($field_name, $placeholder) {

		// Массив с информацией для замены
		$replacement = [];
		// Определение стандартных значений
		$replacement['selected'] = 'selected ';
		$replacement['disabled'] = 'disabled ';
		$replacement['field_value'] = '--' . $placeholder . '--';
		$replacement['field_value_name'] = 'disabled';
		// Запись первого значения (подсказки)
		$incubator = $this->markers_replacement($this->fields_html['select_option'], $replacement);

		// Проход цикла по массиву значений
		foreach( $this->fields[$field_name]['value'] as $value ) {
			// Обнуление массива с информацией для замены
			$replacement = [];
			// Определение стандартных значений
			$replacement['selected'] = '';
			$replacement['disabled'] = '';
			$replacement['field_value'] = $value;
			$replacement['field_value_name'] = $value;

			$incubator .= $this->markers_replacement($this->fields_html['select_option'], $replacement);
		}
		return $incubator;
	}


	/**
	 * Дополнительные приготовления для radio.
	 */
	private function radio_pre_personification($field_name, $placeholder) {
		$incubator = '';
		$counter = 1;
		$checked_marker = 'checked ';
		$field_id_marker = 'input-' . $this->options['form_name'] . '-' . $field_name;
		$field_name_marker = $this->options['form_name'] . '-' . $field_name;
		// Проход цикла по массиву значений
		foreach( $this->fields[$field_name]['value'] as $value ) {
			// Обнуление массива с информацией для замены
			$replacement = [];
			// Определение стандартных значений
			$replacement['checked'] = $checked_marker;
			$replacement['field_id'] = $field_id_marker . $counter;
			$replacement['field_name'] = $field_name_marker;
			$replacement['field_value'] = $value;
			$replacement['field_value_name'] = $value;
			// Замена
			$incubator .= $this->markers_replacement($this->fields_html['radio_button'], $replacement);

			$counter++;
			$checked_marker = '';
		}
		return $incubator;
	}


	/**
	 * Замена маркеров.
	 * 
	 * Аргумент $incubator - html разметка включающая маркеры для замены.
	 * Аргумент $replacement - массив замен.
	 */
	protected function markers_replacement($incubator, $replacement) {
		// Замена маркеров значениями
		foreach( $replacement as $key => $value ) {
			// Маркер
			$marker = '[' . strtoupper($key) . ']';
			// Замена текущего маркера
			$incubator = str_replace($marker, $value, $incubator);
		}

		return $incubator;
	}


	/**
	 * Получение разметки экстренных уведомлений.
	 * 
	 * Аргумент - массив имен уведомлений.
	 * Возвращает html разметку уведомлений, имена которых были переданы как аргумент.
	 */
	protected function emergency_notifications($notifications) {
		$notification_set = '';
		foreach( $notifications as $key => $name ) {
			
			// Проверка наличия файла с шаблоном
			$this->check_file_path('/view/forms/', 'part_notification_' . $name . '.php');
			// Получение html разметки уведомления из файла
			$notifications[$key] = file_get_contents($this->files_path['part_notification_' . $name]);
			
			$alert_id = $this->options['form_name'] . '-' . $name . '-output';
			$notifications[$key] = str_replace( '[ALERT_ID]', $alert_id, $notifications[$key] );
			$notification_set .= $notifications[$key];
		}
		return $notification_set;
	}

} // end FormsTools