<?

class data_query {

	private $rows;

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

	public function where($callback) {
		$result = [];
		foreach($this->rows as $key => $row) {
			if($callback($row, $key)) {
				$result[] = $row;
			}
		}
		return $result;
	}

	public function first() {
		if($this->rows->length > 0) {
			return $this->rows[0];
		}
		return NULL;
	}

	public function last() {
		if($this->rows->length > 0) {
			return $this->rows[$this->rows->length-1];
		}
		return NULL;
	}	
}

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) {
						$object->log('ALTER TABLE '.$nametrimmed.' ADD COLUMN '.$sub_item);
						$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) { /*, $result_callback=false) {*/
		$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 = ?';
				}
			} 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.')';
			}

			if($object->isset($x['modified'])) {
				delete $x['modified'];
			}
			if($object->isset($x['created'])) {
				delete $x['created'];
			}
			/*if($result_callback) {
				$callback = function() {
					if($object->isset($x['id'])) {
						$query = 'SELECT * FROM '.$table.' WHERE id = ?';
						$row = $data->main_instance->get_row($query, [$x['id']]);
						if($row != NULL) {
							$data->data_base->build_row($row, $table);
						}
					}
				};
				return ['output' => $output, 'callback' => $callback];
			}*/
			return $output;
		}
		return NULL;
	}
}

class extension {

	protected $data;
	protected $base;
	protected $statement;

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

		$this->init();
	}

	public function base_init($init_string=NULL) {
		$self_sql = $this->data;

		if($init_string != NULL) {
			$init_tables = $object->strings->split($init_string, ';');
			foreach($init_tables as $init_table) {
				$this->data->execute($init_table, []);
			}
			$table_update = new table_structure_update($init_string, $this->data);
		}
	}
}

class base {
	
	public $apps=NULL;
	
	private $dict = NULL;

	public $indexing_in_progress = false;

	public function __construct() {
		$data->statement = new statement();
		$data->main_instance = $data->fetch('main');

		/*$data->main_instance->distinct_callbacks = $object->create();

		$data->main_instance->_ = function($insert, $v) {
			$data->main_instance->_insert($insert, $v);
			foreach($d
		};*/

		$data->main_instance->statement = $data->statement;

		$data->main_instance->last_id = function($v) {
			if($object->isset($v['id'])) {
				return $v['id'];
			}
			return NULL;
		};

		$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 -1;
		};

		$object->in_array = function($search_value, $input) {
			if($object->index_of($input, $search_value) != (-1)) {
				return true;
			}
			return false;
		};

		$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;
		};

		$object->where = function($rows, $callback) {
			$result = [];
			foreach($rows as $row) {
				if($callback($row)) {
					$result[] = $row;
				}
			}
			return $result;
		};

		$object->concat = function($a, $b) {
			$result = [...$a];
			foreach($b as $b_value) {
				$result[] = $b_value;
			}
			return $result;
		};

		$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);
		};

    	$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-1);
    		}
    		if($object->strings->strpos($file, '/') != 0) {
    			$file = '/'.$file;
    		}
    		return $path.$file;
    	};

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

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

    	$this->callbacks = [];

    	$data->data_base = new data_base([
			'tables' => [
				'medias' => [
					'id' => 'mediaitems'
				],
				'versions_images' => [
					'versions_id' => 'media_versions'
				],
				'media_versions' => [
					'medias_id' => 'mediaitems'
				],
				'movies' => [
					'mediaitems_id' => 'mediaitems'
				],
				'mediaimages' => [
					'mediaitems_id' => 'mediaitems'
				],
				'personimages' => [
					'person_id' => 'people'
				],
				'directors' => [
					'peoples_id' => 'people',
					'mediaitems_id' => 'mediaitems'
				],
				'writers' => [
					'peoples_id' => 'people',
					'mediaitems_id' => 'mediaitems'
				],
				'stars' => [
					'peoples_id' => 'people',
					'mediaitems_id' => 'mediaitems'
				],
				'crews' => [
					'peoples_id' => 'people',
					'mediaitems_id' => 'mediaitems'
				],
				'producers' => [
					'peoples_id' => 'people',
					'mediaitems_id' => 'mediaitems'
				],
				'mediaitemsgenres' => [
					'genres_id' => 'genres',
					'mediaitems_id' => 'mediaitems'
				],
				'mediaitemscompanies' => [
					'companies_id' => 'companies',
					'mediaitems_id' => 'mediaitems'
				],
				'mediaitemstropes' => [
					'tropes_id' => 'tropes',
					'mediaitems_id' => 'mediaitems'
				],
				'mediaitemspopculture' => [
					'popculture_id' => 'popculture',
					'mediaitems_id' => 'mediaitems'
				],
				'mediaitemsthemes' => [
					'themes_id' => 'themes',
					'mediaitems_id' => 'mediaitems'
				],
				'mediaitems' => [
					'media_type_id' => 'mediatypes'
				],
				'mediatypes' => []
			]
		]);

    	$this->action_handler = new action_handler();

    	$this->action_handler_alt = new action_handler_alt($this->action_handler->get_app());
    	/*$this->action_handler_native = $object->get_action_handler();

    	$app = $this->action_handler->get_app();

    	$this->action_handler_native->initialize($app);*/

    	$self = $this;

    	/*$this->indexing_dictionary = [
    		'cinema' => false,
    		'tv' => false
    	];*/


				/*'app_users' => [
					'user_group_id' => 'app_user_groups'
				],
				'app_user_groups' => [
					'user_group_id' => 'app_user_groups'
				],*/

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

    	/*if(false) {
			$this->apps = [
				'cinema' => new cinema_app($self),
	    		'player' => new player_app($self),
	    		'tv' => new tv_app($self)
	    	];
	    }*/

	    $object->main_base = $this;
	}

	public $action_handler;

	public $action_handler_native;

	public $indexing_dictioanry;

	private $callbacks;

	public function push_callback($callback) {
		$index = $this->callbacks->length;
		$callback_obj = [
			'id' => $index,
			'callback' => $callback
		];
		$this->callbacks[] = $callback_obj;
		return $index;
	}

	public function call_callback($callback_id) {
		$set_index = (-1);
		foreach($this->callbacks as $index => $callback_obj) {
			if($callback_obj['id'] == $callback_id) {
				$callback_obj['callback']();
				$callback_obj['id'] = NULL;
				$set_index = $index;
			}
		}
		if($set_index != (-1)) {
			$object->splice($this->callbacks, $set_index, 1);
		}
		return ['result' => true];
	}

	public $ws_connections = [];

	public function add_ws_connection($ws_item) {
		$this->ws_connections[] = $ws_item;

		$self = $this;

		$ws_item->add_remove_callback(function() {
			$object->remove_item($self->ws_connections, $ws_item);
			if($object->isset($ws_item->user_object)) {
				$object->remove_item($ws_item->user_object['user_instance']->instances, $ws_item);
			}
		});

		$ws_item->main_properties = [
			'current_titlemedia_id' => NULL
		];

		$ws_item->add_response_callback(function($message) {
			/*if($message['action'] == 'login') {
				$self->
			} else */
			/*if($message['action'] == 'login') {
		    	$message_counter = $message['message_counter'];
		    	delete $message['message_counter'];
	    		$self->action_handler->handle_action($message, function($response) {
	    			$response['message_counter'] = $message_counter;
	    			$ws_connection->send($response);
	    		});
			} else */
			if($message['action'] == 'to_user') {
				foreach($ws_item->user_object['user_instance']->instances as $instance) {
					$instance->send([
						'action' => $message['to_action']
					]);
				}
			} else if($message['action'] == 'propagate_tags_update') {
				$object->log('propagate');
				$self->update_tags();
			} else if($message['action'] == 'register_collections_id') {
				$ws_item->main_properties['current_titlemedia_id'] = $message['collections_id'];
			} else if($message['action'] == 'update_collections') {
				$id = $message['collections_id'];
				foreach($self->ws_connections as $ws_connection) {
					if(!$object->equals($ws_connection, $ws_item)) {
						/*$object->log($object->toJSON([$ws_connection->main_properties['current_titlemedia_id'], $id]));*/
						if($ws_connection->main_properties['current_titlemedia_id'] == $id) { /* && !$object->equals($ws_connection, $ws_item)*/
							$ws_connection->send(['action' => 'view_update']);
						}
					}
				}
				/*$self->action_handler->get_app()->public_modules['items']['all_movies']->reset_cache();*/
			} else if($message['action'] == 'login') {
		    	$message_counter = $message['message_counter'];
		    	delete $message['message_counter'];
	    		/*$self->action_handler->handle_action($message, function($response) {
	    			$response['message_counter'] = $message_counter;
	    			$ws_connection->send($response);
	    		});*/
	    		$user_object = NULL;
	    		if($object->isset($ws_item->user_object)) {
	    			$user_object = $ws_item->user_object;
	    		}
	    		if($object->isset($ws_item->login_attempts)) {
	    			if($ws_item->login_attempts > 4) {
	    				return false;
	    			}
	    		}
	    		$response = $self->action_handler->handle_action($message, $user_object);
	    		/*$object->log($object->toJSON(['login response' => $response['user_id']]));*/
	    		if($response != false) {
	    			$response['message_counter'] = $message_counter;
	    			$ws_item->send([
	    				'user_id' => $response['user_id']
	    			]);
	    			$ws_item->user_object = $response;
	    			$instances = $response['user_instance']->instances;
	    			$instances[] = $ws_item;
	    		} else {
	    			if($object->isset($ws_item->login_attempts)) {
		    			$ws_item->login_attempts++;
		    		} else {
		    			$ws_item->login_attempts = 0;
		    		}
	    		}
			} else {
		    	$message_counter = $message['message_counter'];
		    	delete $message['message_counter'];

	    		$user_object = NULL;
	    		if($object->isset($ws_item->user_object)) {
	    			$user_object = $ws_item->user_object;
	    		}
	    		$response = $self->action_handler->handle_action($message, $user_object);

    			$response['message_counter'] = $message_counter;
    			$ws_item->send($response);
			}
		});
	}

	public function update_tags() {
		foreach($this->ws_connections as $ws_connection) {
			$ws_connection->send(['action' => 'tags_update']);
		}
	}

	public function update_titlemedia_view($id) {
		foreach($this->ws_connections as $ws_connection) {
			if($ws_connection->main_properties['current_titlemedia_id'] == $id) {
				$ws_connection->send(['action' => 'view_update']);
			}
		}
	}

    public function receive_messages($message) {
    	$message_counter = $message['message_counter'];
    	delete $message['message_counter'];
    	/*$app_id = $message['app_id'];
    	delete $message['app_id'];*/
    	$app_id = 'main';
    	$action = $message['action'];
    	delete $message['action'];
    	$result = NULL;

    	/*$object->log($object->toJSON($message));*/

		if($this->indexing_in_progress) {
			return [
	        	'message_counter' => $message_counter,
	        	'message' => $result,
	        	'stall' => true
	        ];
		}
		if($action == 'call_callback') {
			$result = $this->call_callback($message['callback_id']);
    	} else if($object->isset($message['callback_result'])) {
    		delete $message['callback_result'];
    		$result = $this->apps[$app_id][$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[$app_id][$action]($message);
	    }    
        return [
        	'message_counter' => $message_counter,
        	'message' => $result
        ];
    }

    public function receive_request($input) {
    	$message = $input['message'];
    	/*$object->log($object->toJSON(['req' => $message]));*/
    	/*$object->log($message['action']);
    	if($message['action'] == 'test1') {
			$response = $this->test1();
			$object->log($object->toJSON($response));
			return false;
		} else {

			$response = $this->test2();
			$object->log($object->toJSON($response));
			return false;
		}*/
    	$callback = $input['callback'];


    	if(!$object->isset($message['action'])) {
    		$callback(['response' => 0]);
    	} else {

	    	if($object->isset($message['callback_result'])) {
	    		$this->action_handler->handle_action($message, function($results) {
    				$return_result = [
						'has_access' => true,
						'result' => $results
					];
	    			$callback($return_result);
	    		});
	    	} else {
	    		$response = $this->action_handler_alt->handle_action($message);
	    		$callback($response);
	    	}
	    }
    }

    public function test2() {
    	$v = $object->create();
    	$v['companies_id'] = '7F94703D-77A0-47DB-B8A5-8C9741919918-companies';
		$query = 'SELECT *, mediaitems.id as id FROM mediaitems, movies, mediaitemscompanies WHERE movies.mediaitems_id = mediaitems.id AND mediaitemscompanies.mediaitems_id = mediaitems.id AND companies_id = ? AND (mediaitems.parent_id IS NULL OR mediaitems.title LIKE ?)  ORDER BY year ASC';
		$rows = $data->main_instance->get_rows($query, [$v['companies_id'], '%season%']);
		return $rows;
    }

    public function test1() {
    	$v = $object->create();
    	$v['companies_id'] = '7F94703D-77A0-47DB-B8A5-8C9741919918-companies';

		/*$rows = $data->data_base->select_rows($data->data_base->values['mediaitems'], [
			['*'],
			['movies', '>', '*']
		], function($row) {
			$has_company_id = false;
			if($object->isset($row['mediaitemscompanies'])) {
				foreach($row['mediaitemscompanies'] as $mediaitemcompanies_item) {
					if($object->isset($mediaitemcompanies_item['companies'])) {
						if($mediaitemcompanies_item['companies']['id'] == $v['companies_id']) {
							$has_company_id = true;
						}
					}
				}
				if($has_company_id && ($row['parent_id'] == NULL || $object->strings->strpos($row['title'], 'season') != (-1))) {
					return true;
				}
			}
			return false;
		});*/

		$rows = $data->data_base->select_rows($data->data_base->values['companies'][$v['companies_id']]['mediaitemscompanies'], [
			['mediaitems', '*'],
			['mediaitems', 'movies', '*']
			/*['movies', '>', '*']*/
		], NULL, function($e) {
			if($e['parent_id'] == NULL || $object->strings->strpos($e['title'], 'season') != (-1)) {
				return true;
			}
			return false;
		});

		return $rows;
    }

    public function receive_request_depr($input) {
    	$message = $input['message'];
    	$callback = $input['callback'];

    	$counter = 0;
    	$values = [];
    	while($counter < $message['action']) {
    		$values[] = $counter;
    		$counter++;
    	}

    	$permutations = new permutations($values);
    	$res = $permutations->generate();

    	$callback($res);
    }
}

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;
	}
}

class data_base {

	private $sql;

	private $statement;

	private $relational_map;

	public function __construct($relational_map) {
		$this->sql = $data->main_instance;
		$this->statement = $data->main_instance->statement;
		$this->values = $object->create();
		$this->relational_map = $relational_map;

		$this->build();
	}

	public function select_rows($rows, /*$columns,*/ $where=NULL, $filter=NULL, $select_callback=NULL, $limit=NULL) {
		$results = [];

		$counter = 0;


		foreach($rows as $row) {
			if($where == NULL || $where($row)) {
				$result_row = NULL;
				/*if($select_callback == NULL) {
					foreach($columns as $column_selector) {
						$value = $row;
						$last_selector_item = NULL;
						$select_star = false;
						$add = true;
						foreach($column_selector as $selector_item) {
							if($add) {
								if($selector_item == '>') {
									if($object->item_is_array($value, true)) {
										$value_item_arr = $object->values($value);
										if($value_item_arr->length > 0) {
											$value = $value_item_arr[0];
										}
									}
								} else if($selector_item == '*') {
									$select_star = true;
									foreach($value as $selector_item => $value_item_value) {
										if(!$object->item_is_array($value_item_value, true)) {
											if(!$object->isset($result_row[$selector_item])) {
												$result_row[$selector_item] = $value_item_value;
											}
										}
									}
								} else {
									if($object->isset($value[$selector_item])) {
										$value = $value[$selector_item];
										$last_selector_item = $selector_item;
									} else {
										$add = false;
									}
								}
							}
						}
						if($add) {
							if(!$select_star) {
								if($object->item_is_array($value, true)) {
									$value = [...$value];
									foreach($value as $key => $value_sub_item) {
										if($object->item_is_array($value_sub_item, true)) {
											delete $value[$key];
										}
									}
								}
								if(!$object->isset($result_row[$last_selector_item])) {
									$result_row[$last_selector_item] = $value;
								}
							}
						}
					}
				} else {*/
				if($select_callback != NULL) {
					$result_row = $object->create();
					$select_callback($result_row, $row);
				} else {
					$result_row = $row;
				}
				if($filter == NULL || $filter($result_row)) {
					$results[] = $result_row;
					if($limit !== NULL) {
						$counter++;
						if($counter >= $limit) {
							return $results;
						}
					}
				}
			}
		}

		return $results;
	}

	public function delete($id, $table) {
		if(!$object->isset($this->values[$table])) {
			return false;
		}
		$relations = $this->relational_map->tables[$table_name];
		if(!$object->isset($this->values[$table][$id])) {
			return false;
		}
		$last_values = $this->values[$table][$id];

		foreach($relations as $foreign_key => $foreign_table) {
			if($last_values != NULL) {
				if($object->isset($this->values[$foreign_table][$last_values[$foreign_key]])) {
					$last_foreign_item = $this->values[$foreign_table][$last_values[$foreign_key]];

					if($object->isset($last_foreign_item[$table_name])) {
						$delete_item = $last_foreign_item[$table_name];
						$delete_index = $last_values['id'];
						delete $delete_item[$delete_index];
					}
				}
			}
		}

		delete $this->values[$table][$id];

		return true;
	}

	/*public function delete_and_update($id, $item_table) {
		$query = 'DELETE FROM '.$item_table.' WHERE id = ?';
		$this->sql->execute($query, [$id]);
		$this->delete($id, $table);
	}

	public function insert_and_update($v, $item_table) {
		$insert = $this->sql->statement->generate($v, $item_table);
		$this->sql->_($insert, $v);
		$this->rebuild($v, $table_name);
	}*/	

	/*public function select_row($row, $columns, $select_callback, $where) {
		$rows = $this->select_rows([$row], $columns, $select_callback, $where, 1);
		if($rows->length == 0) {
			return NULL;
		}
		return $rows[0];
	}*/

	public function $set_tables;

	public function build() {
		$relational_map = $this->relational_map;

		$additional_tables = [];

		$tables = $object->keys($relational_map->tables);

		$this->set_tables = $tables;

		foreach($relational_map->tables as $table_name => $relations) {
			foreach($relations as $table_name) {
				if($object->index_of($tables, $table_name) === (-1)) {
					$tables[] = $table_name;
				}
			}
		}

		/*foreach($relational_map->tables as $table_name => $relations) {*/
		foreach($tables as $table_name) {
			$this->values[$table_name] = $object->create();


			/*$object->log($table_name);*/

			$query = 'SELECT * FROM '.$table_name;
			$rows = $this->sql->get_rows($query, []);

			foreach($rows as $row) {
				$this->values[$table_name][$row['id']] = $row;
			}

			/*$object->log($this->values->length);*/
			/*
				Reyna ad automata eins og eg get virknina i samhengi vid nuverandi sql struktur t.d. ad geta generatad selector fyrir skrif utfra gognum i skrifinu toflu nafni og id-i
			*/
		}
		/*
		'producers' => [
			'peoples_id' => 'people', people hefur stars=[{ movie: ..., character_name: ...}]
			'mediaitems_id' => 'mediaitems' movie hefur stars[{ person: ... character_name: ... 
		],*/

		foreach($relational_map->tables as $table_name => $relations) {
			$object->log($table_name);
			foreach($this->values[$table_name] as $row) {
				/*foreach($relations as $foreign_key => $foreign_table) {
					if($object->isset($this->values[$foreign_table][$row[$foreign_key]])) {
						$foreign_item = $this->values[$foreign_table][$row[$foreign_key]];
						$row[$foreign_table] = $foreign_item;
						if(!$object->isset($foreign_item[$table_name])) {
							$foreign_item[$table_name] = $object->create();
						}
						$foreign_item[$table_name][$row['id']] = $row;
					}
				}*/
				$this->build_row($row, $table_name, $relations);
			}
		}

		/*$test_select = $this->values['mediaitems']['B1EC43A7-429F-42C5-9507-2D0880803648-mediaitems']['movies'];
		$object->log('test select length: '.($object->keys($test_select)->length));
		foreach($test_select as $key => $row) {
			$object->log($key);
		}

		$first = $object->values($test_select)[0];

		foreach($first as $key => $value) {
			$object->log($key);
			$object->log($value);
		}*/
	}

	/*public function update($last_values, $new_values, $table_name) {
		$relations = $this->relational_map->tables[$table_name];

		foreach($relations as $foreign_key => $foreign_table) {
			if($object->isset($this->values[$foreign_table][$row[$foreign_key]])) {

			}
		}
	}*/

	public function build_row($row, $table_name, $relations=NULL, $last_values=NULL) {
		if(!$object->isset($this->values[$table_name])) {
			return false;
		}
		if($relations == NULL) {
			$relations = $this->relational_map->tables[$table_name];
		}
		foreach($relations as $foreign_key => $foreign_table) {
			if($last_values != NULL) {
				if($object->isset($this->values[$foreign_table][$last_values[$foreign_key]])) {
					$last_foreign_item = $this->values[$foreign_table][$last_values[$foreign_key]];

					if($object->isset($last_foreign_item[$table_name])) {
						$delete_item = $last_foreign_item[$table_name];
						$delete_index = $last_values['id'];
						delete $delete_item[$delete_index];
					}
				}
			}
			if($object->isset($this->values[$foreign_table][$row[$foreign_key]])) {
				$foreign_item = $this->values[$foreign_table][$row[$foreign_key]];
				$row[$foreign_table] = $foreign_item;
				if(!$object->isset($foreign_item[$table_name])) {
					$foreign_item[$table_name] = $object->create();
				}
				$foreign_item[$table_name][$row['id']] = $row;
			}
		}
	}

	public function rebuild($row, $table_name, $last_values=NULL) {
		if($last_values === NULL && $object->isset($row['id'])) {
			if($object->isset($this->values[$table_name][$row['id']])) {
				$last_values = $this->values[$table_name][$row['id']];
			} else {
				$last_values = $object->create();
			}
		}
		$relations = $this->relational_map->tables[$table_name];
		$this->build_row($row, $table_name, $relations, $last_values);
	}

	public $values;
}

$base_instance = new base();

?>
