<?

class main_app {

	private $sql;
	
	private $statement;

	private $dates;

	public $base_instance = NULL;

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

		$this->set_callbacks = [];

		/*$self_sql = $this->sql;
		$this->sql->last_id = function($v) {
			if($object->isset($v['id'])) {
				return $v['id'];
			}
			return $self_sql->last_insert_id();
		};*/

		$init_string = '
			CREATE TABLE IF NOT EXISTS settings (
			id TEXT primary key,
			property_name TEXT,
			property_value TEXT );
			CREATE TABLE IF NOT EXISTS locations (
				id text primary key,
				fullpath TEXT
			);
			CREATE TABLE IF NOT EXISTS library (
				id text primary key,
				fullpath text,
				relativepath text,
				parent_id text,
				title text,
				is_folder integer,
				is_active integer,
				is_template_item integer DEFAULT 0,
				created datetime,
				modified datetime,
				tags text,
				found_when_indexing integer,
				watch_count integer DEFAULT -1,
				child_ids text
			);
			CREATE TABLE IF NOT EXISTS playlists (
				id text primary key,
				title text,
				type integer,
				sorting text
			);
			CREATE TABLE IF NOT EXISTS watch_log (
				id text primary key,
				library_item_id text,
				created datetime
			);
			CREATE TABLE IF NOT EXISTS template_items (
				id text primary key,
				library_item_id text,
				playlist_template_id text,
				random integer
			);
			CREATE TABLE IF NOT EXISTS cachestore (
				name text,
				value text
			);
		';

		$init_tables = $object->strings->split($init_string, ';');

		foreach($init_tables as $init_table) {
			if($init_table != NULL && $object->strings->strlen($init_table) > 0) {
				$this->sql->execute($init_table, []);
			}
		}
		$table_update = new table_structure_update($init_string, $this->sql);

		$this->location = new location();
		$this->library = new library();
		$this->playlist = new playlist();
		$this->watch_log = new watch_log();
		$this->template_item = new template_item();

		$object->main_instance = $this;

		$object->log('run main');
		$this->run_main();

		$self = $this;

		$object->get_locations = function() {
			$locations = $self->load_locations();

			return $object->map($locations, function($e) {
				return $e['fullpath'];
			});
		};
	}

	public function get_library() {
		return $this->library;
	}

	public function invalidate_cache($v) {
		$query = 'DELETE FROM cachestore WHERE name = ?';
		$this->sql->execute($query, [$v['name']]);

		return true;
	}

	public function store_cache($v) {
		$this->invalidate_cache($v['name']);

		$v['value'] = $object->toJSON($v['value']);

		$insert = $this->statement->generate($v, 'cachestore');
		$this->sql->_($insert, $v);

		return true;
	}

	public function get_cache($name) {
		$query = 'SELECT * FROM cachestore WHERE name = ?';
		$row = $this->sql->get_row($query, [$name]);

		if($row != NULL) {
			if($row['value'] != NULL && $object->strings->strlen($row['value']) > 0) {
				return $object->fromJSON($row['value']);
			}
		}

		return NULL;
	}

	public function generate_playlist($v, $callback) {
		$generating_instance = new generating();

		$locations = $object->get_locations();

		$this->make_accessible_multiple($locations, function() {
			$playlist = $generating_instance->generate_playlist($v['id'], $v['iterations']);

			$playlist_name = $playlist['name'].'.m3u';

			$files->save(['m3u'], $playlist_name, function($path) {
				$files->write($playlist['content'], $path);
				$callback(['location' => $path, 'library_items' => $playlist['library_items']]);
			});
		});
	}

	/*public function save_picker($v, $callback) {
		$files->save(['m3u'], $v['playlist_name'], function($path) {
			$files->write($v['content'], $path);
			$callback($path);
		});
	}*/

	public function delete_log_item($v) {
		$this->watch_log->delete($v['id']);
		return true;
	}

	public function reset_library($v=NULL) {
		$query = 'DELETE FROM watch_log';
		$this->sql->execute($query, []);
		$query = 'DELETE FROM locations';
		$this->sql->execute($query, []);
		$query = 'DELETE FROM library';
		$this->sql->execute($query, []);
		$query = 'DELETE FROM playlists';
		$this->sql->execute($query, []);
		$query = 'DELETE FROM template_items';
		$this->sql->execute($query, []);

		return true;
	}

	public function reset_playback_history($v=NULL) {
		$query = 'DELETE FROM watch_log';
		$this->sql->execute($query, []);

		$query = 'UPDATE library SET watch_count = 0';
		$this->sql->execute($query, []);

		return true;
	}

	public function decrement_play_count($v) {
		$query = 'DELETE FROM watch_log WHERE library_item_id = ? ORDER BY rowid DESC LIMIT 1';
		$this->sql->execute($query, [$v['id']]);

		return true;
	}

	public function reset_play_count($v) {
		/*$query = 'SELECT * FROM library WHERE id = ?';
		$library_item = $this->sql->get_row($query, [$v['id']]);

		if($library_item['is_folder'] == 0) {*/
			$query = 'DELETE FROM watch_log WHERE library_item_id = ?';
			$this->sql->execute($query, [$v['id']]);

			$query = 'UPDATE library SET watch_count = 0 WHERE id = ?';
			$this->sql->execute($query, [$v['id']]);
		/*}*/

		return true;
	}

	public function delete_playlist_template($v) {
		$this->playlist->delete($v['id']);
		return true;
	}

	public function set_at_random($v) {
		$query = 'UPDATE template_items SET random = ? WHERE id = ?';
		$this->sql->execute($query, [$v['random'], $v['id']]);
		return true;
	}

	public function delete_template_item($v) {
		$this->template_item->delete($v['id']);
		return true;
	}

	public function _template_item($v) {
		return $this->template_item->_($v);
	}

	public function get_template_item_parent($id) {
		$query = 'SELECT * FROM library WHERE id = ?';
		$row = $this->sql->get_row($query, [$id]);


		if($row == NULL) {
			return $id;
		}

		if($row['is_template_item'] == 1) {
			return $row['id'];
		} else {
			return $this->get_template_item_parent($row['parent_id']);
		}
	}

	public function set_last_played($v) {
		$res = [];
		$set_count = $v['set_count'];
		if($v['update_previous']) {
			$generating_instance = new generating();
			$set_parent_id = $this->get_template_item_parent($v['id']);
			$media_items = $generating_instance->get_media_from_item($set_parent_id);
			$object->sort($media_items, function($a, $b) {
				return $object->strings->compare($a['relativepath'], $b['relativepath']);
			});


			$found = false;

			foreach($media_items as $media_item) {
				if(!$found) {
					if($media_item['id'] == $v['id']) {
						$found = true;
					} else {
						$query = 'SELECT COUNT(*) as count FROM watch_log WHERE library_item_id = ?';
						$count = $this->sql->get_row($query, [$media_item['id']])['count'];

						if($count < $set_count) {
							$res[] = $media_item['id'];
						}

						$set_count_value = $count;

						while($set_count_value < $set_count) {
							/*$this->watch_log->_([
								'library_item_id' => $media_item['id']
							]);*/

							$object->add_to_watch_log($media_item['id'], NULL);
							$set_count_value = $set_count_value + 1;
						}
					}
				}
			}
		}
		$res[] = $v['id'];
		/*$this->watch_log->_([
			'library_item_id' => $v['id']
		]);*/
		$object->add_to_watch_log($v['id'], NULL);
		return $res;
	}

	public function _playlist($v) {
		return $this->playlist->_($v);
	}

	public function get_playlist($v) {
		return $this->playlist->get_playlist($v['id']);
	}

	public function load_playlists($v=NULL) {
		$query_template = 'SELECT * FROM playlists WHERE type = 1';

		$query_smart_templates = 'SELECT * FROM playlists WHERE type = 2';

		$results = [
			'playlist_templates' => $this->sql->get_rows($query_template, []),
			'smart_playlist_templates' => $this->sql->get_rows($query_smart_templates, [])/*,
			'advanced_playlist_templates' => []*/
		];

		foreach($results['playlist_templates'] as $playlist_template) {
			$query = 'SELECT * FROM template_items WHERE playlist_template_id = ?';
			$template_items = $this->sql->get_rows($query, [$playlist_template['id']]);

			foreach($template_items as $template_item) {
				$query = 'SELECT * FROM library WHERE id = ?';
				if($template_item['library_item_id'] != NULL && $template_item['library_item_id'] != (-1)) {
					$template_item['library_item'] = $this->sql->get_row($query, [$template_item['library_item_id']]);
				} else {
					$template_item['library_item'] = ['title' => '', 'id' => -1];
				}
			}

			$playlist_template['template_items'] = $template_items;
		}

		return $results;
	}

	public function _library_item($v) {
		return $this->library->_($v);
	}

	public function update_library($data, $locations) {
		$this->library->update($data, $locations);
	}

	public function delete_library_item($v) {
		$this->library->delete($v['id']);
		return true;
	}

	public function delete_not_found($v=NULL) {
		$query = 'SELECT * FROM library WHERE found_when_indexing = 0';
		$rows = $this->sql->get_rows($query, []);
		foreach($rows as $row) {
			$query = 'DELETE FROM watch_log WHERE library_item_id = ?';
			$this->sql->execute($query, [$row['id']]);			
		}
		$query = 'DELETE FROM library WHERE found_when_indexing = 0';
		$this->sql->execute($query, []);
		return true;
	}

	public function load_watch_log($v) {
		return $this->watch_log->load();
	}

	public function load_library($v) {
		/*$cache = $this->get_cache('load_library');
		if($cache != NULL) {
			return $cache;
		}*/
		$res = $this->library->load();
		/*$this->store_cache(['value' => $res, 'name' => 'load_library']);*/
		return $res;
	}

	public function init_indexing($v, $callback) {
		$self = $this;
		$this->invalidate_cache('load_library');
		$locations = $this->load_locations();
		if($locations->length == 0) {
			$callback(NULL);
		} else {
			$locations = $object->map($locations, function($e) {
				return $e['fullpath'];
			});

			$set_locations = [...$locations];

			$this->make_accessible_multiple($set_locations, function() {
				$search_instance = new search($locations);
				$search_instance->initial_search(function($data) {
					$self->update_library($data, $locations);
					$object->log('call callback');
					$object->log($callback);
					$callback($data);
				});
			});
		}
	}

	private $location;

	private $library;

	private $playlist;

	private $watch_log;

	private $template_item;

	public function load_locations($v=NULL) {
		return $this->location->load();
	}

	public function choose_location($v, $callback) {
		$location = $this->location;
		$files->picker($v['fullpath'], true, false, function($url) {
			if($url != NULL) {
				$v['fullpath'] = $url;
				$location->_($v);
				$callback($v);
			} else {
				$callback(NULL);
			}
		});
	}

	public function delete_location($v) {
		$this->location->delete($v['id']);
	}

	public $set_callbacks;

	public function make_accessible($path, $callback=NULL) {
		$self = $this;

		$callback_main = function() {
			if(!$files->is_readable($path)) {
				$files->picker($path, true, false, function($url) {
					if(!$files->is_readable($path)) {
						$self->make_accessible($callback);
					} else {
						if($callback != NULL) {
							$callback();
						}
					}
				});
			} else {
				if($callback != NULL) {
					$callback();
				}
			}
		};


		if(!$files->is_readable($path)) {
			$this->set_callbacks[] = $callback_main;
			$object->send('app.dialog.show(data)', [
				'data' => [
					'data' => 'You will now be prompted to access this location: '.$path.'"',
					'callback_index' => $self->set_callbacks->length-1
				]
			]);
		} else {
			$callback_main();
		}
	}

	public function call_callback($v) {
		$callback = $object->splice($this->set_callbacks, $v['index'], 1)[0];
		$callback();
		return true;
	}

	public function make_accessible_multiple($paths, $callback=NULL) {
		$self = $this;

		$object->log($object->toJSON($paths));

		if($paths->length > 0) {
			$path = $object->array_pop($paths);

			$this->make_accessible($path, function() {
				if($paths->length > 0) {
					$this->make_accessible_multiple($paths, $callback);
				} else {
					$callback();
				}
			});
		}
	}

	public function run_main() {
		/*$preg_split = new preg_split('(<|>|\")', '<value prop="test"></value>');
		$res = $preg_split->get();
		$object->log($object->toJSON($res));*/

		$object->log('run 1');
		$source = $files->read_text('streamline2/main', 'html');
		$object->log('run 2');
		/*
				<div class="c_container">
					<video class="preview"></video>
				</div>*/
		/*
				<div class="web_container">
					<web></web>
				</div>*/


		$html_parser_instance = new html_parser($source);
		$res = $html_parser_instance->parse();
		$object->log('run 3');

		$object->log('run main1');
		$object->log($res);

		$web_main_item = $res->get_window()->get_document()->query_selector('web.mainweb')[0];


		$object->log('run main1');

		$object->web_main_item = $web_main_item->get_webview();

		$object->send = function($eval_string, $arguments) {
			$object->web_main_item->evaluate($eval_string, NULL, $arguments);
		};


		$object->log('run main1');

		$self = $this;

		$object->web_main_item->init_messages(function($message_value) {
			$data_res = $object->base_instance->receive_messages($message_value);
			if($object->isset($data_res) && $data_res != NULL && $data_res['message_counter'] != (-1)) {
	    		$object->send('app.receive_messages(data)', ['data' => $data_res]);
	    	}
		});

	}

	public function path_input($v=NULL) {
		$path_input_instance = new path_input($v['input_value']);
		return $path_input_instance->get_results();
	}

	public function register_location_usage($v) {
		$query = 'SELECT * FROM locations WHERE fullpath = ?';
		$row = $this->sql->get_row($query, [$v['fullpath']]);
		$id = NULL;
		$usage_count = 1;
		if($row != NULL) {
			$id = $row['id'];
			$usage_count = $row['usage_count']+1;
		}
		$insert_values = [
			'fullpath' => $v['fullpath'],
			'usage_count' => $usage_count
		];
		if($id != NULL) {
			$insert_values['id'] = $id;
		}

		$insert = $this->statement->generate($insert_values, 'locations');
		$this->sql->_($insert, $insert_values);
		return ['result' => true];
	}

	public function open_folder($v) {
		$wrap = async function($v) {
			$exists = $files->exists($v['fullpath']);
			if($exists) {
				$files->open_folder($v['fullpath']);
			}
		};
		$wrap($v);
		return ['result' => false];
	}

	public $searcH_instance;

	public function start_search($v) {
		$search = new search($v['search_object'], $v['locations']);
		$this->search_instance = $search;
		$this->search_instance->initial_search();
		return ['result' => true];
	}

	public function sub_search($v) {
		$search = new search($v['search_object'], NULL, $v['key']);

		$this->search_instance->sub_searches[$v['key']] = $search;

		$intermediate_results = [];

		if($v['key'] == 1) {
			$intermediate_results = $this->search_instance->search_results;
		} else {
			$previous_key = $v['key']-1;
			$intermediate_results = $this->search_instance->sub_searches[$previous_key]->search_results;
		}
		
		$search->sub_search($intermediate_results);
		
		return ['result' => true];
	}

	public function test($v=NULL) {
		$list = [];
		$index = 0;
		while($index < 100) {
			$index++;
			$list[] = $index;
		}
		$test_b_instance = new test_b();
		$test_b = $test_b_instance->get('parent');
		return ['inheritance' => $test_b, 'results' => [1, 2, 3], 'value' => 1, 'list' => $list];
	}

	public function get_settings($v=NULL, $continue=true) {
		$query = 'SELECT * FROM settings';
		$results = $object->create();
		$rows = $this->sql->get_rows($query, []);
		foreach($rows as $row) {
			$results[$row['property_name']] = $row['property_value'];
		}
		if(false && $results['nc_instance_id'] == NULL && $continue) {
			
			$nc_instance_id = $this->generate_nc_instance_id();
			$this->set_setting([
				'property_name' => 'nc_instance_id',
				'property_value' => $nc_instance_id
			]);
			return $this->get_settings(NULL, false);
		}
		$results['testdata'] = [1, 2, 3];
		return $results;
	}

	private function generate_nc_instance_id() {
		$counter = 0;
		$characters = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
		$letters_uppercase = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'X', 'Y', 'Z'];
		foreach($letters_uppercase as $character) {
			$characters[] = $character;
			$characters[] = $object->strings->lower($character);
		}
		$unique_id = [];
		while($counter < 16) {
			$index = $math->random_int($characters->length);
			$unique_id[] = $characters[$index];
			$counter = $counter+1;
		}
		return $object->strings->join($unique_id, '');
	}

	public function set_setting($v) {
		$query = 'DELETE FROM settings WHERE property_name = ?';
		$this->sql->execute($query, [$v['property_name']]);

		$insert = $this->statement->generate($v, 'settings');
		$this->sql->_($insert, $v);
		return ['results' => true];
	}

}


?>
