<?php

/**
 * table `_DB_TASKS`
 *   int ID
 *   str(30) A_RECORD_CREATE_DATE
 *   str(40) A_RECORD_CREATE_AUTHOR
 *   str(30) A_RECORD_UPDATE_DATE
 *   str(40) A_RECORD_UPDATE_AUTHOR
 *   str TRANSACTION_ID - uniq? task transaction id
 *   str DB_TABLE
 *   text DB_OBJ
 *   text PARAMS
 *   int RESULT_ID
 *   int TASK_DONE - default 0, if done 1
 * 
	CREATE TABLE IF NOT EXISTS `_DB_TASKS` (
		`ID` int(11) NOT NULL AUTO_INCREMENT,
		`A_RECORD_CREATE_DATE` varchar(30) NOT NULL,
		`A_RECORD_CREATE_AUTHOR` varchar(40) NOT NULL,
		`A_RECORD_UPDATE_DATE` varchar(30) NOT NULL,
		`A_RECORD_UPDATE_AUTHOR` varchar(40) NOT NULL,
		`TRANSACTION_ID` varchar(255) NOT NULL,
		`TASK` VARCHAR(32) NOT NULL,
		`DB_TABLE` varchar(255) NOT NULL,
		`DB_OBJ` text NOT NULL,
		`PARAMS` text NOT NULL,
		`RESULT_ID` int(11) NOT NULL DEFAULT '0',
		`TASK_DONE` int(11) NOT NULL DEFAULT '0',
		PRIMARY KEY (`ID`)
	) ENGINE=MyISAM DEFAULT CHARSET=latin2 AUTO_INCREMENT=1 ;
 */
class SimulateDBTask {

	var $_db = null;
	var $_tbl = '_DB_TASKS';
	var $_transaction_id = null;
	var $_create_date = null;
	var $_task_list = array();

	function __construct($db, $transaction_id) {
		$this->_db = $db;
		$this->_transaction_id = $transaction_id;
		$this->_create_date = date('Y-m-d-H:i:s');
	}

	/**
	 * Add database task.
	 * 
	 * @returns int - task id
	 */
	function add($task, $table, $obj, $params = array()) {
		$sql_data = array();
		$sql_data["`A_RECORD_CREATE_DATE`"] = "'{$this->_create_date}'";
		$sql_data["`A_RECORD_CREATE_AUTHOR`"] = "'" . User::getName() . "'";
		$sql_data["`TRANSACTION_ID`"] = "'{$this->_transaction_id}'";
		$sql_data["`TASK`"] = "'{$task}'";
		$sql_data["`DB_TABLE`"] = "'{$table}'";
		$sql_data["`DB_OBJ`"] = "'" . $this->_decode_obj($obj) . "'";
		$sql_data["`PARAMS`"] = "'" . $this->_decode_obj($params) . "'";
		$sql_data["`TASK_DONE`"] = "'0'";

		$sql = "insert into `{$this->_tbl}` (" . implode(", ", array_keys($sql_data)) . ") values (" . implode(", ", array_values($sql_data)) . ");";
		$this->_db->query($sql);
		return $this->_db->insert_id();
	}

	function has_todo() {
		$tasks = $this->_fetch_task_list();
		$undone = 0;
		foreach ($tasks as $key => $val) {
			if ($val->TASK_DONE == 0) {
				$undone++;
			}
		}
		return ($undone > 0);
	}

	function has_tasks() {
		$tasks = $this->_fetch_task_list();
		return !empty($tasks);
	}

	function _fetch_task_list($force = false) {
		$this->_task_list = array();
		if (!empty($this->_task_list) && $force == false) {
			return $this->_task_list;
		}
		$sql = "select t.*
			from `{$this->_tbl}` as t
			where
				t.`TRANSACTION_ID`='{$this->_transaction_id}'
			order by `ID` ASC
		";
		$res = $this->_db->query($sql);
		while ($r = $this->_db->fetch($res)) {
			$this->_task_list [$r->ID]= $r;
		}
		return $this->_task_list;
	}

	function get_result($task_id) {
		$this->_fetch_task_list();
		if (!array_key_exists($task_id, $this->_task_list)) {
			return null;
		}
		return $this->_task_list[$task_id]->RESULT_ID;
	}

	function set_result($task_id, $res_id) {
		$sql_data = array();
		$sql_data[] = "`A_RECORD_UPDATE_DATE`='" . date('Y-m-d-H:i:s') ."'";
		$sql_data[] = "`A_RECORD_UPDATE_AUTHOR`='" . User::getName() . "'";
		$sql_data[] = "`RESULT_ID`='{$res_id}'";
		$sql_data[] = "`TASK_DONE`='1'";
		$sql = "update `{$this->_tbl}` set " . implode("\n , ", $sql_data) . " where ID='{$task_id}';";
		$this->_db->query($sql);
		$this->_task_list[$task_id]->RESULT_ID = $res_id;
	}

	function force_run_task($task_id) {
		$tasks = $this->_fetch_task_list();
		if (empty($tasks)) {
			echo 'Brak tasków';
			return true;
		}

		if (empty($tasks[$task_id])) {
			echo 'Brak taska';
			return true;
		}

		$v_task = $tasks[$task_id];

		//   encode all obj and params
		//   run task, save result
		$v_task->DB_OBJ = $this->_encode_obj($v_task->DB_OBJ);
		$v_task->params_arr = $this->_encode_to_arr($v_task->PARAMS);

		if (!empty($v_task->params_arr)) {
			foreach ($v_task->params_arr as $k_field => $v_res_id) {
				$v_task->DB_OBJ->$k_field = $this->get_result($v_res_id);
			}
		}

		echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">tasks['.$task_id.'] (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($v_task);echo'</pre>';

		if ($v_task->RESULT_ID > 0) {
			echo 'Task został juz wykonany wcześniej - wynik ' . $v_task->RESULT_ID;
			return true;
		}

		echo 'running task';
		$k_task_id = $task_id;
		switch ($v_task->TASK) {
			case 'UPDATE_OBJ':
				echo '<p>' . "TODO: Run task ID {$k_task_id}: \$this->_db->UPDATE_OBJ('{$v_task->DB_TABLE}', DB_OBJ)" . '</p>';
				echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">DB_OBJ (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($v_task->DB_OBJ);echo'</pre>';
				$affected = $this->_db->UPDATE_OBJ($v_task->DB_TABLE, $v_task->DB_OBJ);
				echo '<p>'."result: $affected".'</p>';
				$this->set_result($k_task_id, $affected);
				break;
			case 'ADD_NEW_OBJ':
				echo '<p>' . "TODO: Run task ID {$k_task_id}: \$this->_db->ADD_NEW_OBJ('{$v_task->DB_TABLE}', DB_OBJ)" . '</p>';
				echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">DB_OBJ (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($v_task->DB_OBJ);echo'</pre>';
				$new_id = $this->_db->ADD_NEW_OBJ($v_task->DB_TABLE, $v_task->DB_OBJ);
				echo '<p>'."result: $new_id".'</p>';
				$this->set_result($k_task_id, $new_id);
				break;
			case 'INSERT':
				echo '<p>' . "TODO: Run task ID {$k_task_id}: insert ('{$v_task->DB_TABLE}', DB_OBJ)" . '</p>';
				echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">DB_OBJ (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($v_task->DB_OBJ);echo'</pre>';
				$task_arr = (array)$v_task->DB_OBJ;
				$sql_arr = array();
				foreach ($task_arr as $key => $val) {
					$sql_arr["`{$key}`"] = "'{$val}'";
				}
				$sql = "insert into `{$v_task->DB_TABLE}` (" . implode(',', array_keys($sql_arr)) . ") values (" . implode(',', array_values($sql_arr)) . ");";
				$this->_db->query($sql);
				$new_id = $this->_db->insert_id();
				echo '<p>'."result: $new_id".'</p>';
				$this->set_result($k_task_id, $new_id);
				break;
			default:
				echo '<p>'."Unknown task ({$v_task->TASK}) for ID = {$k_task_id}".'</p>';
		}

	}

	function run() {
		$tasks = $this->_fetch_task_list();
		if (empty($tasks)) {
			return true;
		}
		foreach ($tasks as $k_task_id => $v_task) {
			if ($v_task->TASK_DONE) {
				continue;
			}

			//   encode all obj and params
			//   run task, save result
			$v_task->DB_OBJ = $this->_encode_obj($v_task->DB_OBJ);
			$v_task->params_arr = $this->_encode_to_arr($v_task->PARAMS);

			if (!empty($v_task->params_arr)) {
				foreach ($v_task->params_arr as $k_field => $v_res_id) {
					$v_task->DB_OBJ->$k_field = $this->get_result($v_res_id);
				}
			}

			switch ($v_task->TASK) {
				case 'UPDATE_OBJ':
					echo '<p>' . "TODO: Run task ID {$k_task_id}: \$this->_db->UPDATE_OBJ('{$v_task->DB_TABLE}', DB_OBJ)" . '</p>';
					echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">DB_OBJ (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($v_task->DB_OBJ);echo'</pre>';
					$affected = $this->_db->UPDATE_OBJ($v_task->DB_TABLE, $v_task->DB_OBJ);
					echo '<p>'."result: $affected".'</p>';
					$this->set_result($k_task_id, $affected);
					break;
				case 'ADD_NEW_OBJ':
					echo '<p>' . "TODO: Run task ID {$k_task_id}: \$this->_db->ADD_NEW_OBJ('{$v_task->DB_TABLE}', DB_OBJ)" . '</p>';
					echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">DB_OBJ (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($v_task->DB_OBJ);echo'</pre>';
					$new_id = $this->_db->ADD_NEW_OBJ($v_task->DB_TABLE, $v_task->DB_OBJ);
					echo '<p>'."result: $new_id".'</p>';
					$this->set_result($k_task_id, $new_id);
					break;
				case 'INSERT':
					echo '<p>' . "TODO: Run task ID {$k_task_id}: insert ('{$v_task->DB_TABLE}', DB_OBJ)" . '</p>';
					echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">DB_OBJ (F.' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($v_task->DB_OBJ);echo'</pre>';
					$task_arr = (array)$v_task->DB_OBJ;
					$sql_arr = array();
					foreach ($task_arr as $key => $val) {
						$sql_arr["`{$key}`"] = "'{$val}'";
					}
					$sql = "insert into `{$v_task->DB_TABLE}` (" . implode(',', array_keys($sql_arr)) . ") values (" . implode(',', array_values($sql_arr)) . ");";
					$this->_db->query($sql);
					$new_id = $this->_db->insert_id();
					echo '<p>'."result: $new_id".'</p>';
					$this->set_result($k_task_id, $new_id);
					break;
				default:
					echo '<p>'."Unknown task ({$v_task->TASK}) for ID = {$k_task_id}".'</p>';
			}
		}
	}

	function _decode_obj($obj) {
		$lines = array();
		foreach ($obj as $k_field => $v_value) {
			$lines[] = "{$k_field}: {$v_value}";
		}
		return implode("\n", $lines);
	}

	function _encode_to_arr($str) {
		$ret = array();
		if (empty($str)) {
			return null;
		}
		$lines = explode("\n", $str);
		foreach ($lines as $v_line) {
			$v_args = explode(': ', $v_line, 2);
// TODO: BUG A_PROBLEM_DESC: "ANEKS - Stare dane: ..." i w nowej linii "ANEKS - Stare dane: ..." z popdzedniego wpisu
//			if (false != strpos(' ', $v_args[0])) {
//				continue;
//			}
			$ret[ $v_args[0] ] = $v_args[1];
		}
		return $ret;
	}

	function _encode_obj($str) {
		if (empty($str)) {
			return null;
		}
		$ret = $this->_encode_to_arr($str);
		return (object)$ret;
	}

	function get_tasks() {
		$tasks = $this->_fetch_task_list();
		return $tasks;
	}

}
