<?php

Lib::loadClass('BaseModel');


class ProcesLogModel extends BaseModel {

	function __construct($dao) {
		parent::__construct($dao);
		$this->fields['ID'] = '';
		$this->fields['TYPE'] = '';
		$this->fields['ID_PROCES_INIT'] = '';
		$this->fields['ID_STEP'] = '';// ID procesu
		$this->fields['ID_STEP_WSKAZNIK'] = '';// ID wskaznika w danym procesie ID_STEP
		$this->fields['ID_STANOWISKA'] = '';// ID stanowisk kroku aktualnie do wykonania
		$this->fields['ID_USER'] = '';// 0 - nie przypisane - patrz ID_STANOWISKA, przypisane do konkretnego stanowiska
		$this->fields['ID_KEY'] = '';// ID from external table - defined in ID_STEP_WSKAZNIK (parent zasob table), TODO: clear after next step? Yes
		$this->fields['A_UPDATE_ZASOB_ID'] = '';
		$this->fields['A_UPDATE_HIST_ID'] = '';
		$this->fields['log'] = '';
		//$this->fields['TIMESTAMPP'] = '';// automatic field - not used
		$this->fields['A_RECORD_CREATE_DATE'] = '';
		$this->fields['A_RECORD_CREATE_AUTHOR'] = '';
		$this->fields['A_RECORD_UPDATE_DATE'] = '';
		$this->fields['A_RECORD_UPDATE_AUTHOR'] = '';
	}

	/**
	 * Get list of next step (Proces).
	 * @returns array [ID] = DESC
	 * TODO: use IF_GO_TO
	 */
	function get_next_step() {
		$ret = array();

		if (!$this->get('ID')) {
			return $ret;
		}

		$cur_step_id = $this->get('ID_STEP');
		if ($cur_step_id <= 0) {
			$cur_step_id = $this->get('ID_PROCES_INIT');
		}

		$ret = $this->dao->get_proces_next_steps($cur_step_id);
		return $ret;
	}

	/**
	 * Get list of next step wskaznik (Proces).
	 * @returns wskaznik
	 */
	function get_next_step_wskaznik() {
		$ret = null;

		if (!$this->get('ID')) {
			return $ret;
		}

		$cur_step_id = $this->get('ID_STEP');
		if ($cur_step_id <= 0) {
			$cur_step_id = $this->get('ID_PROCES_INIT');
		}

		$wsk_grouped = $this->get_wskazniki_grouped($cur_step_id);
		if (empty($wsk_grouped)) {
			return $ret;
		}
		$wsk_grouped_keys = array_keys($wsk_grouped);

		$cur_step_wsk_id = $this->get('ID_STEP_WSKAZNIK');
		// check if current id_step_wsk is set to last group
		if ($cur_step_wsk_id > 0) {
			if ($cur_step_wsk_id == end($wsk_grouped_keys) && $this->get('ID_KEY') > 0) {
				return $ret;// is finished
			}
		}
		// set default id_step_wsk if not set
		if (!in_array($cur_step_wsk_id, $wsk_grouped_keys)) {
			$cur_step_wsk_id = reset($wsk_grouped_keys);
		}

		// find current and return next
		$found_current = false;
		foreach ($wsk_grouped as $k_wsk_id => $v_edit) {
			if ($found_current) {
				return $v_edit;
			}
			if ($k_wsk_id == $cur_step_wsk_id) {
				$found_current = true;
			}
		}

		return $ret;
	}

	/**
	 * 
	 * @retruns array of wskazniki - grouped
	 *   [first wsk id] => ProcesLogEdit
	 * Cache in PROCES_LOG_WSK_GROUPED = array( log_id => array( step_id => array( wsk_id => array from ProcesLogEdit->to_array() ) ) )
	 */
	function get_wskazniki_grouped($step_id) {
		static $_wsk;// TODO: save to ses by $this->get('ID') and $step_id
		if (!is_array($_wsk)) $_wsk = array();

		Lib::loadClass('ProcesLogEdit');

		if (!empty($_wsk[$step_id])) {
			// update _last_id_key in ProcesLogEdit
			foreach ($_wsk[$step_id] as $k_wsk_id => $v_plog_edit) {
				$v_plog_edit->set_last_id_key($this->get('ID_KEY'));
				$_SESSION['PROCES_LOG_WSK_GROUPED'][$this->get('ID')][$step_id][$k_wsk_id] = $v_plog_edit->to_array();
			}
			return $_wsk[$step_id];
		}

		$cache_on = false;

		if (empty($_SESSION['PROCES_LOG_WSK_GROUPED'])) $_SESSION['PROCES_LOG_WSK_GROUPED'] = array();
		if ($cache_on && !empty($_SESSION['PROCES_LOG_WSK_GROUPED'][$this->get('ID')][$step_id])) {
			$_wsk[$step_id] = array();
			foreach ($_SESSION['PROCES_LOG_WSK_GROUPED'][$this->get('ID')][$step_id] as $k_wsk_id => $v_plog_edit_array) {
				$_wsk[$step_id][$k_wsk_id] = new ProcesLogEdit($this->get('ID'), $k_wsk_id);
				$_wsk[$step_id][$k_wsk_id]->from_array($v_plog_edit_array);
			}
			DEBUG_S(1, "wsk from ses:", $_SESSION['PROCES_LOG_WSK_GROUPED'][$this->get('ID')][$step_id], __FILE__, __FUNCTION__, __LINE__);
			DEBUG_S(1, "wsk from ses done:", $_wsk[$step_id], __FILE__, __FUNCTION__, __LINE__);
		}
		else {
			$_wsk[$step_id] = array();
			$wskazniki = $this->dao->get_wskazniki($step_id);
			$wskazniki_tables = $this->dao->get_wskazniki_parent_tables($wskazniki);
			DEBUG_S(1, "wskazniki:", $wskazniki, __FILE__, __FUNCTION__, __LINE__);
			DEBUG_S(1, "wskazniki_tables:", $wskazniki_tables, __FILE__, __FUNCTION__, __LINE__);
			// TYPE to search parents: KOMORKA, TODO: add DANE
			$children_types = array('KOMORKA');
			if (!empty($wskazniki_tables)) {
				// add _tbl_parent
				foreach ($wskazniki as $k_id => $v_wsk) {
					if (!in_array($v_wsk->TYPE, $children_types)) {
						continue;// eg. pomin TYPE='TABELA'
					}
					if (array_key_exists($v_wsk->ID, $wskazniki_tables)) {
						$v_wsk->_tbl_parent = $wskazniki_tables[$v_wsk->ID];
						// TODO: find parent zasob ID
						if (!is_object($v_wsk->_tbl_parent)) {
							$v_wsk->_tbl_parent = $wskazniki_tables[$v_wsk->_tbl_parent];
						}
						if (!is_object($wskazniki[$k_id]->_tbl_parent)) {
							$v_wsk->_tbl_parent = $wskazniki_tables[$v_wsk->_tbl_parent];
						}
					} else {
						// no zasob ID in tables tree
					}
				}
				DEBUG_S(1, "wskazniki 2:", $wskazniki, __FILE__, __FUNCTION__, __LINE__);

				$last_group_wsk_id = 0;

				foreach ($wskazniki as $k_id => $v_wsk) {
					if (isset($v_wsk->_tbl_parent)) {
						if ($last_group_wsk_id == 0) {
							$last_group_wsk_id = $k_id;
						}
						if (!array_key_exists($last_group_wsk_id, $_wsk[$step_id])) {
							$_wsk[$step_id][$last_group_wsk_id] = new ProcesLogEdit($this->get('ID'), $last_group_wsk_id);
							$_wsk[$step_id][$last_group_wsk_id]->set_tbl_zasob_id($v_wsk->_tbl_parent->ID);
							// set_last_id_key if action is done - ID_KEY is set
							if ($this->get('ID_KEY') > 0 && $last_group_wsk_id == $this->get('ID_STEP_WSKAZNIK')) {
								$_wsk[$step_id][$last_group_wsk_id]->set_last_id_key($this->get('ID_KEY'));
							}
						}
						$_wsk[$step_id][$last_group_wsk_id]->add_komorka($v_wsk);
					} else {
						$last_group_wsk_id = 0;
					}
				}
			}
			DEBUG_S(1, "wsk[" . $step_id . "]:", $_wsk[$step_id], __FILE__, __FUNCTION__, __LINE__);

			// save data into SES cache
			if (!empty($_wsk[$step_id])) {
				foreach ($_wsk[$step_id] as $k_wsk_id => $v_plog_edit) {
					$sql_types = $this->dao->get_sql_types($v_plog_edit->get_table_name());
					DEBUG_S(1, "sql_types:", $sql_types, __FILE__, __FUNCTION__, __LINE__);
					$v_plog_edit->set_komorki_sql_types($sql_types);

					$_SESSION['PROCES_LOG_WSK_GROUPED'][$this->get('ID')][$step_id][$k_wsk_id] = $v_plog_edit->to_array();
				}
				$this->_garbage_collection();
				DEBUG_S(1, "wsk[" . $step_id . "] save into SES:", $_SESSION['PROCES_LOG_WSK_GROUPED'][$this->get('ID')][$step_id], __FILE__, __FUNCTION__, __LINE__);
			}
		}

		return $_wsk[$step_id];
	}

	/**
	 * Garbage collection (GC) is a form of automatic memory management.
	 */
	function _garbage_collection() {
		$max_cache_log_count = 10;// save 3 last log
		$max_cache_step_count = 10;// save 10 last steps
		if (empty($_SESSION['PROCES_LOG_WSK_GROUPED'])) $_SESSION['PROCES_LOG_WSK_GROUPED'] = array();
		if (count($_SESSION['PROCES_LOG_WSK_GROUPED']) > $max_cache_log_count) {
			// TODO: remove from the beginnig of array - without current log id $this->get('ID')
			DEBUG_S(1, "TODO: PROCES_LOG_WSK_GROUPED remove LOG $max_cache_log_count:", $_SESSION['PROCES_LOG_WSK_GROUPED'], __FILE__, __FUNCTION__, __LINE__);
		}
		if (count($_SESSION['PROCES_LOG_WSK_GROUPED'][$this->get('ID')]) > $max_cache_step_count) {
			// TODO: remove from the beginnig of array - without current step id
			DEBUG_S(1, "TODO: PROCES_LOG_WSK_GROUPED remove STEP $max_cache_step_count:", $_SESSION['PROCES_LOG_WSK_GROUPED'][$this->get('ID')], __FILE__, __FUNCTION__, __LINE__);
		}
	}

	/**
	 * 
	 * @returns ProcesLogEdit object or null
	 */
	function get_current_edit() {
		$ret = null;
		if ($this->get('TYPE') == 'END') {
			return $ret;
		}

		$wsk_group = $this->get_wskazniki_grouped($this->get('ID_STEP'));
		if (empty($wsk_group)) {
			return $ret;
		}

		$cur_wsk_id = null;
		if ($this->get('ID_STEP_WSKAZNIK') > 0) {
			if (array_key_exists($this->get('ID_STEP_WSKAZNIK'), $wsk_group)) {
				$cur_wsk_id = $this->get('ID_STEP_WSKAZNIK');
			} else {
				// TODO: Error w danych ID_STEP_WSKAZNIK!
			}
		}
		if (!$cur_wsk_id) {
			$cur_wsk_id = reset(array_keys($wsk_group));
		}

		if ($cur_wsk_id) {
			$ret = $wsk_group[$cur_wsk_id];
		}
		return $ret;
	}

	/**
	 * Check if current step is finished.
	 * @returns boolean.
	 */
	function is_step_finished() {
		// TODO: ID_STEP_WSKAZNIK is in the end of array of wskazniki grouped by TABELA and record ID is saved, found (ID_KEY)
		$wsk_grouped = $this->get_wskazniki_grouped($this->get('ID_STEP'));
		if (empty($wsk_grouped)) {
			return true;
		} else {
			if ($this->get('ID_STEP_WSKAZNIK') > 0) {
				if ($this->get('ID_STEP_WSKAZNIK') == end(array_keys($wsk_grouped)) && $this->get('ID_KEY') > 0) {
					return true;
				}
			} else {
				return false;
			}
		}
		return false;
	}

	/**
	 * Check if allow to move to next step.
	 * @returns boolean.
	 */
	function allow_next_step($next_id) {
		if (!$this->is_step_finished()) {
			return false;
		}
		$next_processes = $this->get_next_step();
		return array_key_exists($next_id, $next_processes);
	}

	/**
	 * Check if allow to move to next step.
	 * @returns boolean.
	 */
	function allow_next_step_wskaznik($next_wsk_id) {
		if ($this->is_step_finished()) {
			return false;
		}
		$next_step_wsk = $this->get_next_step_wskaznik();
		if ($next_step_wsk != null && $next_step_wsk->get_log_wsk_id() == $next_wsk_id) {
			return true;
		}
		return false;
	}

	/**
	 * Check if allow to move to end.
	 * @returns boolean.
	 */
	function allow_end() {
		$next_step_list = $this->get_next_step();
		if (empty($next_step_list)) {
			if ($this->is_step_finished()) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Change ProcesLog state to next step.
	 * @returns true / false
	 */
	function go_to_next_step($next_id) {
		// get proces
		// get wskazniki for this proces
		$wskazniki = ProcesHelper::get_wskazniki($next_id);

		$wsk_stanowiska = array();// [ID wskaznika] = ID zasobu (stanowiska)
		foreach ($wskazniki as $k => $v_wsk) {
			if ($v_wsk->TYPE == 'STANOWISKO') {
				$wsk_stanowiska [$v_wsk->CW_ID] = $v_wsk->ID;
			}
		}

		if (!empty($wsk_stanowiska)) {
			$this->set('ID_USER', 0);
			$this->set('ID_STANOWISKA', implode(",", array_values($wsk_stanowiska)));
		}

		$this->set('TYPE', 'STEP');// always set to STEP after update
		$this->set('ID_STEP', $next_id);
		$this->set('ID_STEP_WSKAZNIK', '');
		$this->set('ID_KEY', 0);// clear key ID - used only in _HIST
		$this->set('A_UPDATE_ZASOB_ID', 0);// clear key A_UPDATE_ZASOB_ID - used only in _HIST
		$this->set('A_UPDATE_HIST_ID', 0);// clear key A_UPDATE_HIST_ID - used only in _HIST

		if ($this->dao->save($this)) {
			return true;
		}
		return false;
	}

	/**
	 * Change ProcesLog state to next step wskaznik.
	 * @returns true / false
	 */
	function go_to_next_step_wskaznik($next_wsk_id) {
		$wskazniki_grouped = $this->get_wskazniki_grouped($this->get('ID_STEP'));
		if (!array_key_exists($next_wsk_id, $wskazniki_grouped)) {
			return false;
		}

		// TODO: verify if $next_wsk_id is after current wskaznik

		$this->set('TYPE', 'STEP');// always set to STEP after update
		//$this->set('ID_STEP', );// dont change
		$this->set('ID_STEP_WSKAZNIK', $next_wsk_id);
		$this->set('ID_KEY', 0);// clear key ID - used only in _HIST
		$this->set('A_UPDATE_ZASOB_ID', 0);// clear key A_UPDATE_ZASOB_ID - used only in _HIST
		$this->set('A_UPDATE_HIST_ID', 0);// clear key A_UPDATE_HIST_ID - used only in _HIST

		if ($this->dao->save($this)) {
			return true;
		}
		return false;
	}

	/**
	 * Change ProcesLog state quit.
	 * @returns true / false
	 */
	function go_to_end() {
		$this->set('TYPE', 'END');
		$this->set('ID_STEP', 0);
		$this->set('ID_STEP_WSKAZNIK', 0);
		$this->set('ID_STANOWISKA', '');
		$this->set('ID_KEY', 0);
		$this->set('A_UPDATE_ZASOB_ID', 0);
		$this->set('A_UPDATE_HIST_ID', 0);

		if ($this->dao->save($this)) {
			return true;
		}
		return false;
	}

}
