<?
class live_indexing {

	public $interrupt_flag = false;

	public $was_interrupted = false;

	public $update_in_progress = false;

	public $should_proceed_update = false;

	public $statement;

	public $data;

	public $updated_results;

	public $base;

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

		$this->data = $data->fetch('tv');
	}

	public $locations;


	public $extensions = ['m4v', 'mp4', 'mkv', 'avi', 'wmv', 'mov', 'flv', '3gp', 'mpg', 'ts', 'rm', 'swf'];

	public $in_progress = false;

	public function init($locations, $first_run=true) {
		$self = $this;
		if($this->in_progress) {
			return false;
		}
		$this->in_progress = true;

		$object->log('init live indexing TV');

		if($locations->length == 0) {
			return NULL;
		}

		$this->locations = $locations;


		$content_type = 'public.movie';

		$query_string = 'kMDItemContentTypeTree CONTAINS[cd] "public.movie" OR kMDItemContentTypeTree CONTAINS[cd] "dyn.ah62d4rv4ge804450" OR kMDItemFSName LIKE[cd] "*.m4v" OR kMDItemFSName LIKE[cd] "*.mp4" OR kMDItemFSName LIKE[cd] "*.mkv" OR kMDItemFSName LIKE[cd] "*.avi" OR kMDItemFSName LIKE[cd] "*.wmv" OR kMDItemFSName LIKE[cd] "*.mov" OR kMDItemFSName LIKE[cd] "*.flv" OR kMDItemFSName LIKE[cd] "*.3gp" OR kMDItemFSName LIKE[cd] "*.mpg" OR kMDItemFSName LIKE[cd] "*.ts" OR kMDItemFSName LIKE[cd] "*.rm" OR kMDItemFSName LIKE[cd] "*.swf"';

		$variables = [];

		$files->search->stop_search();

		$set_locations = [...$locations];

		$this->make_accessible_multiple($set_locations, function() {
			$object->log('new search');
			$files->search->new_search($query_string, $variables, $locations, function($results) {
				$object->log('in callback1');
				if($results != NULL) {
					$self->run_update($results);
				}
			}, function($results) {
				/*$object->log('in callback2');
				$self->run_update($results);*/
			});
			/*if($first_run) {
				$self->base->apps['cinema']->init_live_indexing();
			}*/
		});
	}

	public function run_update($results) {
		$self = $this;
		$this->stored_results = $results;
		/*if(!$this->update_in_progress) {
			$self->update_in_progress = true;*/
			$wrap = async function() {
				$results = $self->parse_results($results);
				$self->initial_update($results);
			};
			$wrap();
		/*} else {
			$this->stored_results = true;
		}*/
	}

	public function run_stored_update() {
		$self = $this;
		/*if(!$this->update_in_progress && $this->stored_results != NULL) {
			$this->stored_results = NULL;
			
			$files->search->restart_search();
			
		}*/
	}

	public $stored_results = NULL;

	public function parse_results($results) {
		$parsed_results = [];

		$remove_string = '/System/Volumes/Data';
		$remove_string_length = $object->strings->strlen($remove_string);

		foreach($results as $item) {
			$parsed_item = $item->get_values(['FSSize', 'Path']);
			if($object->strings->strpos($parsed_item['kMDItemPath'], $remove_string) === 0) {
				$parsed_item['kMDItemPath'] = $object->strings->substr($parsed_item['kMDItemPath'], $remove_string_length); 
			}
			$parsed_results[] = $parsed_item;
		}

		return $parsed_results;
	}

	public function initial_update($results) {
		$object->send('app.main_settings.highlight_indexing_in_progress(data)', ['data' => true]);
		$object->set_app_property('indexing_in_progress', true);
		$this->base->indexing_dictionary['tv'] = true;
		$this->last_updated_results = $results;

		$performed_change = false;


		$episode_index_a = $object->create();
		$episode_index_b = $object->create();

		$without_filesize = $this->get_episodes_without_filesize();
		foreach($without_filesize as $episode) {
			$episode_index_a[$episode['path']] = $episode;
		}

		foreach($results as $episode) {
			if($object->isset($episode_index_a[$episode['kMDItemPath']])) {
				$episode_values = $episode_index_a[$episode['kMDItemPath']];
				$this->_episode([
					'id' => $episode_values['id'],
					'filesize' => $object->to_string($episode['kMDItemFSSize'])
				]);
			}
		}


		$all_episodes = $this->get_all_episodes();


		$set_episode_index = $object->create();

		foreach($all_episodes as $episode) {
			$components = $files->remove_path_component($episode['path']);
			$filename = $components['last_component'];
			$index_id = $filename.'-'.$episode['filesize'];

			if(!$object->isset($set_episode_index[$index_id])) {
				$set_episode_index[$index_id] = [];
			}

			$set_episode_index[$index_id][] = $episode;
		}


		$mark_exists = $object->create();

		foreach($results as $episode) {
			$components = $files->remove_path_component($episode['kMDItemPath']);

			$filename = $components['last_component'];

			$index_id = $filename.'-'.$episode['kMDItemFSSize'];

			
			$path = $episode['kMDItemPath'];
			/*$mark_exists[$index_id] = $path;*/
			if(!$object->isset($mark_exists[$index_id])) {
				$mark_exists[$index_id] = [];
			}
			$mark_exists_item = $mark_exists[$index_id];
			$mark_exists_item[] = $path;

			$to_set = false;
			if($object->isset($set_episode_index[$index_id])) {
				$to_set = true;
				foreach($set_episode_index[$index_id] as $item_values) {
					if($item_values['path'] == $path) {
						$to_set = false;
					}
				}
			} else {
				$to_set = true;
			}


			if($to_set) {
				$show_id = $this->get_show_id($path);

				if($show_id != NULL) {
					$episode_id = $this->_episode([
						'path' => $path,
						'filesize' => $episode['kMDItemFSSize'],
						'tv_show_id' => $show_id
					]);
					$performed_change = true;
				}
			} else {
				$same_paths = false;
				foreach($set_episode_index[$index_id] as $episode_set_values) {
					if($episode_set_values['path'] == $path) {
						$same_paths = true;
					}
				}
				if(!$same_paths) {
					foreach($set_episode_index[$index_id] as $episode_set_values) {
						if(!$files->exists($episode_set_values['path'])) {
							$show_id = $this->get_show_id($path);
							
							$update_values = [
								'id' => $episode_set_values['id'],
								'path' => $path,
								'tv_show_id' => $show_id
							];
							$this->_episode($update_values);
							$performed_change = true;
						}
					}

				}
			}
		}


		foreach($set_episode_index as $index_value => $episode_item) {
			
			foreach($episode_item as $item_values) {
				if(!$files->exists($item_values['path'])) {
					$this->delete_episode($item_values['id']);
					$performed_change = true;
				}
			}
			/*if(!$one_exists) {
				$this->delete_episode($item_values['id']);
				$performed_change = true;
			} else*/
			if(!$object->isset($mark_exists[$index_value])) {
				foreach($episode_item as $item_values) {
					$this->delete_episode($item_values['id']);
					$performed_change = true;
				}
			} else {
				foreach($episode_item as $item_values) {
					$found = false;
					/*if($item_values['path'] != $mark_exists[$index_value]) {
						$this->delete_episode($item_values['id']);
						$performed_change = true;
					}*/
					foreach($mark_exists[$index_value] as $path_item_value) {
						if($path_item_value == $item_values['path']) {
							$found = true;
						}
					}
					if(!$found) {
						$this->delete_episode($item_values['id']);
						$performed_change = true;
					}
				}
			}
		}

		/*foreach($mark_exists as $index_id => $episode_item) {

		}*/

		$this->update_in_progress = false;
		$this->base->indexing_dictionary['tv'] = false;
		if($performed_change) {
			$object->send('app.view_update(data)', ['data' => true]);
		}
		if(!$this->base->indexing_dictionary['cinema']) {
			$object->send('app.main_settings.highlight_indexing_in_progress(data)', ['data' => false]);
			$object->set_app_property('indexing_in_progress', false);
		}
		$this->in_progress = false;
		/*$this->run_stored_update();*/
	}

	public function get_show_id($path) {
		foreach($this->locations as $location) {
			if($object->strings->strpos($path, $location) !== (-1)) {
				$relative_path = $object->strings->split($path, $location)[1];
				$path_components = $files->path_components($relative_path);

				if($path_components->length > 0) {
					$show_name = $path_components[0];
					if($show_name == '/' && $path_components->length > 1) {
						$show_name = $path_components[1];
					}
					$query = 'SELECT * FROM tv_shows WHERE name = ?';
					$tv_show_rows = $this->data->get_rows($query, [$show_name]);
					$id = NULL;
					if($tv_show_rows->length == 0) {
						$id = $this->_tv_show([
							'name' => $show_name
						]);
					} else {
						$id = $tv_show_rows[0]['id'];
					}
					return $id;
				}
			}
		}
		return NULL;
	}

	public function clean_duplicates() {
		$query = 'SELECT * FROM episodes'; /* as a WHERE (SELECT COUNT(*) as count FROM episodes as e WHERE e.path = a.path) > 1*/
		$rows = $this->data->get_rows($query, []);
		foreach($rows as $row) {
			$query = 'SELECT * FROM episodes WHERE path = ?';
			$episodes = $this->data->get_rows($query, [$row['path']]);
			if($episodes->length > 1) {
				$max_size = (-1);
				$set_id = NULL;
				foreach($episodes as $episode) {
					if($episode['filesize'] > $max_size) {
						$max_size = $episode['filesize'];
						$set_id = $episode['id'];
					}
				}
				if($set_id != NULL) {
					foreach($episodes as $episode) {
						if($episode['id'] != $set_id) {
							$query = 'DELETE FROM episodes WHERE id = ?';
							$this->data->execute($query, [$episode['id']]);
						}
					}
				}
			}
		}
	}

	public function delete_episode($id) {
		$query = 'DELETE FROM episodes WHERE id = ?';
		$this->data->execute($query, [$id]);
	}

	public function _tv_show($v) {
		$insert = $this->data->statement->generate($v, 'tv_shows');
		$this->data->_($insert, $v);
		$id = $this->data->last_id($v);
		return $id;
	}

	public function _episode($v) {
		$insert = $this->data->statement->generate($v, 'episodes');
		$this->data->_($insert, $v);
		$id = $this->data->last_id($v);
		return $id;
	}

	public function get_episodes_without_filesize() {
		$query = 'SELECT * FROM episodes WHERE filesize IS NULL';
		$rows = $this->data->get_rows($query, []);
		$results = [];
		foreach($rows as $row) {
			if($row['tv_show_id'] > 0) {
				$query = 'SELECT COUNT(*) as count FROM tv_shows WHERE id = ?';
				$tv_show_count = $this->data->get_row($query, [$row['tv_show_id']])['count'];
				if($tv_show_count > 0) {
					$results[] = $row;
				}
			}
		}
		return $results;
	}

	public function get_all_episodes() {
		$query = 'SELECT * FROM episodes';
		$rows = $this->data->get_rows($query, []);
		$results = [];
		foreach($rows as $row) {
			if($row['tv_show_id'] > 0) {
				$query = 'SELECT COUNT(*) as count FROM tv_shows WHERE id = ?';
				$tv_show_count = $this->data->get_row($query, [$row['tv_show_id']])['count'];
				if($tv_show_count > 0) {
					$results[] = $row;
				}
			}
		}
		return $results;
	}

	public $last_updated_results = NULL;

	public function find_delta() {
		$last_results = $this->last_updated_results;
		$results = $this->updated_results;
		$this->last_updated_results = $results;


	}

	public $access_timeout_counter = 0;

	public function make_accessible($path, $callback=NULL) {
		$object->log('make accessible');
		$object->log($path);
		if($this->access_timeout_counter > 5) {
			if(false) {
				$object->send('app.main_settings.index_failed(data)', ['data' => 0]);
			}
			return false;
		}
		$self = $this;
		if(!$files->is_readable($path)) {
			$object->log('not readable');
			$callback_id = $this->base->push_callback(function() {
				$files->picker($path, true, false, function($url) {
					if($url != NULL) {
						if(!$files->is_readable($path)) {
							$self->access_timeout_counter++;
							$self->make_accessible($path, $callback);
						} else {
							if($callback != NULL) {
								$callback();
							}
						}
					} else {
						$object->send('app.main_settings.index_failed(data)', ['data' => 0]);
					}
				});
			});

			$object->send('app.main_settings.prompt_gain_access(data)', [
				'data' => [
					'location' => $path, 
					'callback_id' => $callback_id
				]
			]);
		} else {
			$object->log('readable');
			if($callback != NULL) {
				$callback();
			}
		}
	}

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

?>