<?
class table_structure_update {
	public function __construct($init_command, $data_instance) {
		$create_commands = $object->strings->split($init_command, 'CREATE TABLE IF NOT EXISTS');
		foreach($create_commands as $item) {
			$table_parts = $object->strings->split($item, '(');
			if($table_parts->length > 1) {
				$nametrimmed = $object->strings->trim($table_parts[0]);
				$sub_items = $object->strings->split($table_parts[1], ')')[0];
				$sub_items = $object->strings->split($sub_items, ',');
				$index = 0;
				$columns = $data_instance->table_columns($nametrimmed);
				foreach($sub_items as $sub_item) {
					$sub_item_value = $object->strings->split($object->strings->trim($sub_item), ' ')[0];
					$flag = false;
					foreach($columns as $column) {
						if($column == $sub_item_value) {
							$flag = true;
						}
					}
					if(!$flag) {
						$data_instance->execute('ALTER TABLE '.$nametrimmed.' ADD COLUMN '.$sub_item, []);
					} else {
					}
				}
			}
		}
	}
}

class statement {
	public function generate($x, $table, $prevent_id_generating=false, $user_id=NULL) {
		$output = NULL;
		$keys = [];
		$type = 0;
		if($object->isset($x['modified']) && $x['modified'] == (-1)) {
			delete $x['modified'];
		}
		if($object->isset($v['id']) && $object->strings->strlen($v['id']) == 0) {
			delete $v['id'];
		}
		$table_columns = $data->main_instance->table_columns($table);
		/*$x_unaltered = $x;
		$x = [...$x];*/
		/*$x_unaltered = [...$x];*/
		if($object->index_of($table_columns, 'created') != (-1)) {
			/*if(!$object->isset($x_unaltered['created']) || $x_unaltered['created'] == NULL || $object->strings->strlen($x_unaltered['created']) == 0) {*/
				$x['created'] = 'current_timestamp';
			/*}*/
		}
		if($object->index_of($table_columns, 'modified') != (-1)) {
			/*if(!$object->isset($x_unaltered['modified']) || $x_unaltered['modified'] == NULL || $object->strings->strlen($x_unaltered['modified']) == 0) {*/
				$x['modified'] = 'current_timestamp';
			/*}*/
		}
		if($object->index_of($table_columns, 'user_id') != (-1) && $user_id != NULL) {
			$x['user_id'] = $user_id;
		}
		if($object->index_of($table_columns, 'id') == (-1)) {
			$prevent_id_generating = true;
		}
		/*if($object->index_of($table_columns, 'user_id') != (-1)) {

		}*/
		if($x->length > 0) {
			if($object->isset($x['id'])) {
				if($x['id'] == '-1') {
					$type = 1;	
				} else {
					$type = 0;	
				}
			} else {
				$type = 1;	
			}
			if($type == 0) {
				$output = 'UPDATE '.$table.' SET ';
				if($object->isset($x['id'])) {
					$counter = 0;
					if($object->isset($x['created'])) {
						delete $x['created'];
					}
					foreach($x as $key => $x_value) {
						$keys[] = $key;
						if($key != 'id') {
							if($counter > 0) {
								$output = $output.', ';
							}
							if(($key == 'created' || $key == 'modified') && $object->strings->lower($x_value) == 'current_timestamp') {
								if($key != 'created') {
									$output = $output.$key.' = current_timestamp';
								}
							} else {
								$output = $output.$key.' = ?';
							}
							$counter = $counter+1;
						}
					}
					$output = $output.' WHERE id = ?';
				}
				/*($row, $table_name, $relations, $set_values=NULL, $create=false)*/
				/*$data->data_base->build_row(NULL, $table, NULL, $x, false);*/
			} else {
				if(!$prevent_id_generating) {
					$x['id'] = $data->main_instance->generate_uuid().'-'.$table;
				}
				$output = 'INSERT INTO '.$table.' (';
				$counter = 0;
				foreach($x as $key => $x_value) {
					$keys[] = $key;
					if($counter > 0) {
						$output = $output.', ';
					}
					$output = $output.$key;
					$counter = $counter+1;
				}
				$counter = 0;
				$output = $output.') VALUES (';
				foreach($x as $key => $x_value) {
					if($counter > 0) {
						$output = $output.', ';
					}
					if(($key == 'created' || $key == 'modified') && $object->strings->lower($x_value) == 'current_timestamp') {
						$output = $output.'current_timestamp ';
					} else {
						$output = $output.'? ';
					}
					$counter = $counter+1;
				}
				$output = $output.')';
				/*$data->data_base->build_row(NULL, $table, NULL, $x, true);*/
			}

			if($object->isset($x['modified'])) {
				delete $x['modified'];
			}
			if($object->isset($x['created'])) {
				delete $x['created'];
			}
			/*$x_unaltered['id'] = $x['id'];*/
			return $output;
		}
		return NULL;
	}
}

/*class statement {
	public function generate($x, $table) {
		$output = NULL;
		$keys = [];
		$type = 0;
		if($x->length > 0) {
			if($object->isset($x['id'])) {
				if($x['id'] == '-1') {
					$type = 1;	
				} else {
					$type = 0;	
				}
			} else {
				$type = 1;	
			}
			if($type == 0) {
				$output = 'UPDATE '.$table.' SET ';
				if($object->isset($x['id'])) {
					$counter = 0;
					foreach($x as $key => $x_value) {
						$keys[] = $key;
						if($key != 'id') {
							if($counter > 0) {
								$output = $output.', ';
							}
							$output = $output.$key.' = ?';
							$counter = $counter+1;
						}
					}
					$output = $output.' WHERE id = ?';
				}
			} else {
				$output = 'INSERT INTO '.$table.' (';
				$counter = 0;
				foreach($x as $key => $x_value) {
					$keys[] = $key;
					if($counter > 0) {
						$output = $output.', ';
					}
					$output = $output.$key;
					$counter = $counter+1;
				}
				$counter = 0;
				$output = $output.') VALUES (';
				foreach($x as $key => $x_value) {
					if($counter > 0) {
						$output = $output.', ';
					}
					$output = $output.'? ';
					$counter = $counter+1;
				}
				$output = $output.')';
			}
			$result_a = ['insert_query' => $output, 'table_name' => $table, 'type' => $type];
			return $output;
		}
		return NULL;
	}
}*/

class base {
	public $apps = [];

	public function __construct() {
		$object->log('in construct');
		$data->statement = new statement();
		$object->deep_copy = function($input) {
			return $object->fromJSON($object->toJSON($input));
		};
		$object->index_of = function($input, $search_value) {
			foreach($input as $indexofkey => $value) {
				if($search_value == $value) {
					return $indexofkey;
				}
			}
			return 0-1;
		};
		$object->union = function($a, $b, $comparator) {
			foreach($b as $b_value) {
				$exists = false;
				foreach($a as $a_value) {
					$comparator_result = $comparator($a_value, $b_value);
					if($comparator_result) {
						$exists = true;
					}
				}
				if(!$exists) {
					$a[] = $b_value;
				}
			}
			return NULL;
		};
		$object->map = function($arr, $func) {
			$result = [];
			foreach($arr as $row) {
				$result[] = $func($row);
			}
			return $result;
		};
    	$files->append_path_depr = function($path, $file) {
    		$path_strlen = $object->strings->strlen($path);
    		$strrev = $object->strings->strrev($path);
    		if($object->strings->strpos($strrev, '/') == 0) {
    			$path = $object->strings->substr($path, 0, $path_strlen-2);
    		}
    		if($object->strings->strpos($file, '/') != 0) {
    			$file = '/'.$file;
    		}
    		return $path.$file;
    	};
    	/*$object->create = function($input) {
			$created_object = ['test' => 'test'];
			delete $created_object['test'];
			return $created_object;
		};*/

		$object->count = function($arr) {
			return $arr->length;
		};

		$object->get_first_row = function($rows) {
			if($rows->length > 0) {
				return $rows[0];
			}
			return NULL;
		};

		$object->array_keys = function($value) {
			return $object->keys($value);
		};
		
    	$object->strings->explode = function($delimiter, $value) {
    		return $object->strings->split($value, $delimiter);
    	};

    	$object->strings->implode = function($delimiter, $values) {
    		return $object->strings->join($values, $delimiter);
    	};

    	$object->regex->preg_split = function($regex_value, $text, $mark_delimiters) {
			$preg_split_instance = new preg_split($regex_value, $text, $mark_delimiters);
			return $preg_split_instance->get();
		};

		$object->regex->preg_replace = function($regex_value, $replace_value, $text, $prefix) {
			$split = $object->regex->preg_split($regex_value, $text, true);
			/*if($object->isset($prefix) && $prefix) {
				if($split->length == 1 && $split[0] != $text) {
					return $replace_value.$object->strings->join($split, $replace_value);
				}
			}*/
			return $object->strings->join($split, $replace_value);
		};

		$this->apps = [
			'main' => new main_app($this)
    	];

    	$object->base_instance = $this;
	}

	public $indexing_in_progress = false;

	public function receive_request($request) {
		$action = NULL;
		if($request['action'] != NULL) {
			$action = $request['action'];
		} else {
			return ['message' => 'error'];
		}
		if($this->apps['main'][$action] == NULL) {
			return ['message' => 'error'];
		}


		return [
			'message' => $this->apps['main'][$action]()
		];
	}

    public function receive_messages($message) {
    	$message_counter = $message['message_counter'];
    	delete $message['message_counter'];
    	$action = $message['action'];
    	delete $message['action'];
    	$result = NULL;
    	if($object->isset($message['callback_result'])) {
    		delete $message['callback_result'];
    		$result = $this->apps['main'][$action]($message, function($result_data) {
    			$object->send('app.receive_messages(data);', [
    				'data' => [
	    				'message_counter' => $message_counter, 
	    				'message' => $result_data
    				]
    			]);
    		});
    		return NULL;
    	} else {
	    	$result = $this->apps['main'][$action]($message);
	    }
        return [
			'message_counter' => $message_counter, 
			'message' => $result
		];
    }
}

class data_query {

	public function query($items, $where) {
		$results = [];
		foreach($items as $item) {
			if($where($item)) {
				$results[] = $item;
			}
		}

		return $results;
	}

	public function map($items, $map_to) {
		$results = [];
		foreach($items as $item) {
			$results[] = $map_to($item);
		}
		return $results;
	}
}

class data_query_concurrent {

	public function query($items, $where, $callback) {
		$results = [];
		$counter = [];
		$callback_wrap = function() {
			$callback($results);
		};
		foreach($items as $item) {
			$wrap = async function($item) {
				if($where($item)) {
					$results[] = $item;
				}
				$counter[] = true;
				if($counter->length == $items->length) {
					$object->once($callback_wrap);
				}
			};
			$wrap($item);
		}
	}

	public function map($items, $map_to, $callback) {
		$results = [];

		$callback_wrap = function() {
			$intermediate_results = $object->create();
			foreach($results as $item) {
				$intermediate_results[$item['key']] = $item['item'];
			}
			$end_results = [];
			$counter = 0;
			while($counter < $results->length) {
				$end_results[] = $intermediate_results[$counter];
				$counter = $counter + 1;
			}
			$callback($end_results);
		};

		foreach($items as $key => $item) {
			$wrap = async function($item, $key) {
				$results[] = [
					'key' => $key,
					'item' => $map_to($item)
				];
				if($results->length == $items->length) {
					$object->once($callback_wrap);
				}
			};
			$wrap($item, $key);
		}
	}
}

class combinations {
	
	private $values;

	public function __construct($values) {
		$this->values = $values;
	}

	public function generate() {
		return $this->generate__cached($this->values);
	}

	public function generate__cached($values=NULL) {
		if($values->length == 0) {
			$result = [];
			return $result;
		}
		$result = [];
		foreach($values as $key => $value) {
			$subset = [...$values];
			$object->splice($subset, $key, 1);
			$result[] = $subset;
			$generated = $this->generate__cached($subset);
			foreach($generated as $subset_value) {
				$index_of = $object->index_of($result, $subset_value);
				if($index_of == (-1)) {
					$result[] = $subset_value;
				}
			}
		}
		return $result;
	}
}


class permutations {

	private $values;

	public function __construct($values) {
		$this->values = $values;
	}

	public function generate() {
		return $this->generate__cached($this->values);
	}

	public function generate__cached($values=NULL) {
		if($values->length == 1) {
			return [$values];
		}
		$values = [...$values];
		$result = [];
		foreach($values as $key => $value) {
			$arrangement = [$value];
			$subset = [...$values];
			$object->splice($subset, $key, 1);
			$generated = $this->generate__cached($subset);
			foreach($generated as $sub_arrangement) {
				$result[] = $object->concat($arrangement, $sub_arrangement);
			}
		}
		return $result;
	}
}


$base_instance = new base();

?>
