<?

class tv_app {
	private $data = NULL;

	public $base_instance = NULL;

	public $live_indexing;

	public function __construct($base_instance) {
		$this->data = $data->fetch('tv');
		$data->tv_main_instance = $this->data;
		$this->data->statement = $data->statement;
		$this->base_instance = $base_instance;


		$data->main_tv = $this->data;
		$this->data->last_id = function($v) {
			if($object->isset($v['id'])) {
				return $v['id'];
			}
			$res = $data->main_tv->last_insert_id();
			return $res;
		};

		$init_string = '
CREATE TABLE IF NOT EXISTS tv_shows (
id integer primary key autoincrement,
name text,
path text,
tags text,
decrease integer default 0
);
CREATE TABLE IF NOT EXISTS episodes (
id integer primary key autoincrement,
tv_show_id INTEGER,
path TEXT,
active INTEGER default 1,
audio_level TEXT,
max_audio_level TEXT,
adjustment_level TEXT,
filesize TEXT,
duration text,
lastplayed datetime
);
CREATE TABLE IF NOT EXISTS preferences (
id INTEGER primary key AUTOINCREMENT,
tv_shows_location TEXT,
tv_shows_location_2 TEXT,
tv_shows_location_3 TEXT,
movies_location TEXT
);
CREATE TABLE IF NOT EXISTS schedules (
id INTEGER primary key AUTOINCREMENT,
name TEXT,
playback_options integer default 0,
randomized_schedule integer default 0
);
CREATE TABLE IF NOT EXISTS schedule_items (
id INTEGER primary key AUTOINCREMENT,
show_id INTEGER,
schedule_id INTEGER,
in_sequence BOOLEAN DEFAULT 0,
order_value INTEGER DEFAULT -1
);
CREATE TABLE IF NOT EXISTS watch_log (
id INTEGER primary key AUTOINCREMENT,
episode_id INTEGER
);
CREATE TABLE IF NOT EXISTS locations (
id INTEGER primary key AUTOINCREMENT,
location TEXT
);
CREATE TABLE IF NOT EXISTS smart_templates (
id INTEGER primary key autoincrement,
name TEXT,
sources TEXT,
sources_ids TEXT
);
CREATE TABLE IF NOT EXISTS smart_template_color_schemes (
id INTEGER primary key autoincrement,
tag_a TEXT,
tag_b TEXT,
smart_template_id integer,
frequency double
)';


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

		$this->live_indexing = new live_indexing($base_instance);
	}

	public function grant_accesss_to_all_locations($v=NULL) {
		$sources = $object->map($this->get_sources(), function($e) {
			$location = $e['location'];
			if($object->strings->strpos($object->strings->strrev($location), '/') != 0) {
				$location = $location.'/';
			}
			return $location;
		});

		$sources = $object->concat($sources, $this->base_instance->apps['cinema']->get_indexing_sources());

		$this->live_indexing->make_accessible_multiple($sources, function() {
			return true;
		});

		return true;
	}

	public function clear_library($v=NULL) {
		$query = 'SELECT * FROM tv_shows';
		$shows = $this->data->get_rows($query, []);
		foreach($shows as $show) {
			$query = 'SELECT COUNT(*) as count FROM episodes WHERE tv_show_id = ?';
			$count = $this->data->get_row($query, [$show['id']])['count'];
			if($count == 0) {
				$query = 'DELETE FROM tv_shows WHERE id = ?';
				$this->data->execute($query, [$show['id']]);
				$query = 'DELETE FROM schedule_items WHERE show_id = ?';
				$this->data->execute($query, [$show['id']]);
			}
		}
		return true;
	}

	public function init_live_indexing($v=NULL, $first_run=true) {
		$tv_locations = $object->map($this->get_sources(), function($e) {
			$location = $e['location'];
			if($object->strings->strpos($object->strings->strrev($location), '/') != 0) {
				$location = $location.'/';
			}
			return $location;
		});

		$this->live_indexing->init($tv_locations, $first_run);

		return ['result' => true];
	}

	public function reset_audio_normalization($v=NULL) {
		$query = 'UPDATE episodes SET adjustment_level = NULL';
		$this->data->exeute($query, []);

		return NULL;
	}

	private function get_all_episodes_without_audio_adjustment() {
		$query = 'SELECT * FROM episodes WHERE (adjustment_level IS NULL OR LENGTH(adjustment_level) = 0) AND (audio_level IS NULL OR LENGTH(audio_level) = 0)';
		return $this->data->get_rows($query, []);
	}

	public function get_show_audio_level($v) {
		$query = 'SELECT MAX(adjustment_level) as adjustment_level FROM episodes WHERE tv_show_id = ?';
		$adjustment_level = $this->data->get_row($query, [$v['tv_show_id']]);
		if($adjustment_level != NULL) {
			return ['adjustment_level' => $adjustment_level['adjustment_level']];
		}
		return ['adjustment_level' => 0];
	}

	public function set_show_audio_level($v) {
		$query = 'UPDATE episodes SET adjustment_level = ? WHERE tv_show_id = ?';
		$this->data->execute($query, [$v['adjustment_level'], $v['tv_show_id']]);

		return true;
	}

	public function perform_audio_normalization() {
		$files_groupped = [];

		$episodes = $this->get_all_episodes_without_audio_adjustment();

		if($episodes->length == 0) {

			return ['result' => false];
		}

		$episodes_partitioned = $files->partition_by_parent_folder($episodes, 'path');

		$episodes = [];

		foreach($episodes_partitioned as $path => $episodes_items) {
			$episodes[] = $episodes_items[0];
			if($episodes_items->length > 3) {
				$mid_range = $math->floor($episodes_items->length / 3);
				$episodes[] = $episodes_items[$mid_range];
			}
		}

		$files_groupped = $object->partition($episodes, 2);

		$audio_normalization = new audio_normalization($this->data, $files_groupped, $episodes);

		$paths = [];

		$sources = $this->get_sources();
		foreach($sources as $source) {
			$paths[] = $source['location'];
		}
		$object->log('called initial_check');
		$audio_normalization->initial_check($paths);

		return ['result' => true];
	}

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

	public function index_show($show_id, $path) {
		$files_list = $files->list_files($path);
		$counter = 0;
		$total_length = $files_list->length;
		foreach($files_list as $file) {
			$full_path = $files->append_path($path, $file);
			if($files->is_dir($full_path)) {
				$this->index_show($show_id, $full_path);
			} else if($object->index_of($this->extensions, $files->get_extension($file)) != (-1) && $object->strings->strpos($file, '.') != 0) {
				$query = 'SELECT * FROM episodes WHERE path = ?';
				$rows = $this->data->get_rows($query, [$full_path]);
				$episode_id = NULL;
				if($rows->length == 0) {
					$episode_id = $this->_episode([
						'tv_show_id' => $show_id,
						'path' => $full_path
					]);
				} else {
					$episode_id = $rows[0]['id'];
				}
				if($episode_id != NULL) {
					$this->set_episode_index['ep_'.$episode_id] = true;
				}
			}

			$progress = $math->mult(($counter / $total_length), 100);
			$object->send('app.set_progress(data)', ['data' => $progress]);		
			$counter = $counter + 1;
		}
	}

	public $set_episode_index = NULL;

	public function index_library_sub($v=NULL) {
		$files_index = [];
		$this->set_episode_index = $object->create();
		$sources = $this->get_sources();
		foreach($sources as $source) {
			$location = $source['location'];
			if(!$files->is_readable($location)) {
				$this->base_instance->indexing_dictionary['tv'] = false;
				return ['result' => -1];
			}
		}
		foreach($sources as $source) {
			$location = $source['location'];
			if($files->exists($location) && $files->is_dir($location)) {
				$list = $files->list_files($location);
				foreach($list as $directory_item) {
					if($object->strings->strpos($directory_item, '.') != 0) {
						$full_path = $files->append_path($location, $directory_item);
						$query = 'SELECT * FROM tv_shows WHERE name = ?';
						$rows = $this->data->get_rows($query, [$directory_item]);
						$show_id = NULL;
						if($rows->length == 0) {
							$show_id = $this->_show([
								'name' => $directory_item
							]);
						} else {
							$show_id = $rows[0]['id'];
						}
						if($show_id != NULL) {
							$this->index_show($show_id, $full_path);
						}
					}
				}
			}
		}
		if($sources->length == 0) {
			return ['result' => 0];
		}

		if($this->set_episode_index != NULL && $object->values($this->set_episode_index)->length > 0) {
			$query = 'SELECT * FROM episodes';
			$episodes = $this->data->get_rows($query, []);
			foreach($episodes as $episode) {
				if($episode['id'] != NULL) {
					if(!$object->isset($this->set_episode_index['ep_'.$episode['id']])) {
						$query = 'DELETE FROM episodes WHERE id = ?';
						$this->data->execute($query, [$episode['id']]);
					}
				}
			}
		}	
		$this->base_instance->indexing_dictionary['tv'] = false;
		return ['result' => 1];
	}

	public function library_picker($v, $result_callback) {
		$object->log('in picker');
		$object->log($object->toJSON($v));
		$set_callback = function($result) {
			$object->log('in picker res');
			$object->log($result);
			if($result != NULL) {
				$result_callback($result);
			}
		};
		$files->picker($v['location'], true, false, $set_callback);
	}

	public function index_library($v=NULL) {
		$this->init_live_indexing(NULL, false);
	}

	public function index_library_manually($v=NULL) {
		$self = $this;
		if($this->base_instance->indexing_dictionary['tv']) {
			return ['result' => 3];
		}
		$this->base_instance->indexing_dictionary['tv'] = true;
		$this->base_instance->indexing_in_progress = true;
		$wrap = async function() {
			$result = $self->index_library_sub();

			$object->send('app.tv.settings.indexing_completed(data)', ['data' => $result]);
			$self->base_instance->indexing_in_progress = false;
		};
		$wrap();
		return ['result' => 1];
	}

	public function get_sources($v=NULL) {
		$query = 'SELECT tv_shows_location, movies_location FROM preferences';
		$preferences = $this->data->get_rows($query, []);

		if($preferences->length > 0) {
			if($preferences[0]['tv_shows_location'] != '' && $preferences[0]['tv_shows_location'] != NULL) {
				$query = 'DELETE FROM preferences';
				$this->data->execute($query, []);


				$location_id = $this->_location([
					'location' => $preferences[0]['tv_shows_location']
				]);
			}
		}

		$query = 'SELECT * FROM locations';
		$locations = $this->data->get_rows($query, []);
		/*if($preferences->length > 0) {
			$locations = $object->concat([[
				'id' => 0,
				'location' => $preferences[0]['tv_shows_location']
			]], $locations);
		}*/
		return $locations;
	}

	public function set_sources($v) {
		$locations = $v['locations'];
		$location_ids = [];
		foreach($locations as $key => $location) {
			/*if($object->isset($location['id']) && $location['id'] == 0) {
				$this->_pref([
					'tv_shows_location' => $location['location']
				]);
			} else {*/
				$location_id = $this->_location($location);
				$location_ids[] = $location_id;
			/*}*/
		}
		foreach($locations as $location) {
			if($object->isset($location['id']) && $object->index_of($location_ids, $location['id']) == (-1)) {
				$location_ids[] = $location['id'];
			}
		}
		$sources = $this->get_sources();
		foreach($sources as $source) {
			if($object->index_of($location_ids, $source['id']) == (-1)) {
				$query = 'DELETE FROM locations WHERE id = ?';
				$this->data->execute($query, [$source['id']]);
			}
		}
		/*$this->init_live_indexing(NULL, false);*/
		return ['result' => 1];
	}

	public function _pref($v) {
		$query = 'DELETE FROM preferences';
		$this->data->execute($query, []);
		$insert = $this->data->statement->generate($v, 'preferences');
		$this->data->_($insert, $v);
		$id = $this->data->last_id($v);
		return $id;
	}

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

	public function reset_playback_history($v) {
		$episodes = $this->get_episodes($v);
		foreach($episodes as $episode) {
			$query = 'DELETE FROM watch_log WHERE episode_id = ?';
			$this->data->execute($query, [$episode['id']]);
		}
		return ['result' => 1];
	}

	public function reset_all_playback_history($v=NULL) {
		$query = 'DELETE FROM watch_log';
		$this->data->execute($query, []);
		return ['result' => 1];
	}

	public function generate_smart_template($v) {
		$schedule_id = $v['schedule_id'];
		$source_index = NULL;
		$schedules = $this->get_schedules();
		foreach($schedules as $key => $schedule) {
			if($schedule['id'] == $schedule_id) {
				$source_index = $key+1;
			}
		}
		$sources_ids = [];
		$sources = [];
		if($source_index != NULL) {
			$sources[] = $source_index;
		}
		$sources_ids[] = $schedule_id;
		$frequency_count = $object->create();
		$schedule_name = $this->get_schedule_name($schedule_id);
		$smart_template_id = $this->add_smart_template('Generated from '.$schedule_name, false, $sources, $sources_ids);
		$schedule_items = $this->get_schedule_items(['schedule_id' => $schedule_id], false);
		
		$last_tags = [];
		foreach($schedule_items as $schedule_item) {
			if($schedule_item['show_id'] != NULL) {
				$show_tags = $this->get_show_tags($schedule_item['show_id']);
				foreach($show_tags as $tag_a) {
					foreach($last_tags as $tag_b) {
						$tag_id_a = $object->strings->split($tag_a, ' ')[1];
						$tag_id_b = $object->strings->split($tag_b, ' ')[1];

						$tag_id_a_value = 'tag_'.$tag_id_a;
						$tag_id_b_value = 'tag_'.$tag_id_b;

						$key_1 = $tag_id_a_value.'-'.$tag_id_b_value;
						$key_2 = $tag_id_b_value.'-'.$tag_id_a_value;
						if($object->isset($frequency_count[$key_1])) {
							$frequency_count[$key_1] = $frequency_count[$key_1]+1;
						} else if($object->isset($frequency_count[$key_2])) {
							$frequency_count[$key_2] = $frequency_count[$key_2]+1;
						} else {
							$frequency_count[$key_1] = 1;
						}
					}
				}
				$last_tags = $show_tags;
			}
		}
		foreach($frequency_count as $key => $frequency_value) {
			$split = $object->strings->split($key, '-');
			$tag_a = $split[0];
			$tag_b = $split[1];
			$this->_smart_template_color_scheme([
				'tag_a' => $tag_a,
				'tag_b' => $tag_b,
				'smart_template_id' => $smart_template_id,
				'frequency' => $frequency_value
			]);
		}
		return ['smart_template_id' => $smart_template_id];
	}

	private function get_show_tags($show_id) {
		$query = 'SELECT tags FROM tv_shows WHERE id = ?';
		$rows = $this->data->get_rows($query, [$show_id]);
		if($rows->length == 0) {
			return [];
		}
		return $object->fromJSON($rows[0]['tags']);
	}

	private function add_smart_template($name, $default_values=true, $sources=NULL, $sources_ids=NULL) {
		$values = [
			'name' => $name
		];
		if($sources == NULL) {
			$values['sources'] = '[]';
		} else {
			$values['sources'] = $object->toJSON($sources);
		}
		if($sources_ids != NULL) {
			$values['sources_ids'] = $object->toJSON($sources_ids);
		} else {
			$values['sources_ids'] = '[]';
		}
		$id = $this->_smart_template($values);
		if($default_values) {
			$index = 0;
			while($index < 10) {
				$tag_a = 'tag_'.$index;
				$num = $index+1;
				if($num == 10) {
					$num = 0;
				}
				$tag_b = 'tag_'.$num;
				$this->_smart_template_color_scheme([
					'smart_template_id' => $id,
					'tag_a' => $tag_a,
					'tag_b' => $tag_b,
					'frequency' => 1
				]);
				$index = $index+1;
			}
		}
		return $id;
	}

	public function toggle_episode_by_path($path) {
		$episode = $this->get_episode_by_path($path);
		if($episode != NULL) {
			$active_value = 1;
			if($episode['active'] == 1) {
				$active_value = 0;
			}
			$this->_episode([
				'id' => $episode['id'],
				'active' => $active_value
			]);
		}
	}

	public function get_episode_by_path($path) {
		$query = 'SELECT * FROM episodes WHERE path = ?';
		return $this->data->get_row($query, [$path]);
	}

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

	public function _smart_template_color_scheme($v) {
		$insert = $this->data->statement->generate($v, 'smart_template_color_schemes');
		$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 coordinate_template_sources($id) {
		$query = 'SELECT * FROM smart_templates WHERE id = ?';
		$smart_template = $this->data->get_row($query, [$id]);
		if($smart_template != NULL && $smart_template->length > 0) {
			$sources = $smart_template['sources'];
			$sources_ids = $smart_template['sources_ids'];
			if($sources != NULL && $object->strings->strlen($sources) > 0 && $sources != '[]') {
				$sources = $object->fromJSON($sources);
				$sources_ids = [];
				foreach($sources as $source) {
					$schedule = $this->get_schedule_by_index($source);
					$sources_ids[] = $schedule['id'];
				}
				$sources_ids = $object->toJSON($sources_ids);
				$this->_smart_template([
					'id' => $id,
					'sources_ids' => $sources_ids
				], false);
			} else if($sources_ids != NULL && $object->strings->strlen($sources_ids) > 0 && $sources_ids != '[]') {
				$sources_ids = $object->fromJSON($sources_ids);
				$sources = [];
				foreach($sources_ids as $source_id) {
					$sources[] = $this->get_schedule_index($source_id);
				}
				$sources = $object->toJSON($sources);
				$this->_smart_template([
					'id' => $id,
					'sources' => $sources
				], false);
			}
		} else {
			$this->_smart_template([
				'id' => $id,
				'sources' => '[ ]',
				'sources_ids' => '[ ]'
			], false);
		}
	}

	public function _smart_template($v, $update=true) {
		$insert = $this->data->statement->generate($v, 'smart_templates');
		$this->data->_($insert, $v);
		$id = $this->data->last_id($v);
		if($update) {
			$this->coordinate_template_sources($id);
		}
		return $id;
	}

	public function delete_smart_template($v) {
		$query = 'DELETE FROM smart_templates WHERE id = ?';
		$this->data->execute($query, [$v['id']]);
		return ['result' => 1];
	}

	public function delete_schedule($v) {
		$query = 'DELETE FROM schedules WHERE id = ?';
		$this->data->execute($query, [$v['id']]);
		return ['result' => 1];
	}

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

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

	public function set_schedule_order($v) {
		foreach($v['items'] as $schedule_item) {
			$this->_schedule_item($schedule_item);
		}
		return ['result' => 1];
	}

	public function shows_not_in_schedule($v) {
		$shows = $this->get_shows();
		$schedule_items = $this->get_schedule_items($v, false);
		$shows_not_in = [];
		$schedule_items = $object->map($schedule_items, function($e) {
			return $e['show_id'];
		});
		foreach($shows as $show) {
			if($object->index_of($schedule_items, $show['id']) == (-1)) {
				$shows_not_in[] = $show;
			}
		}
		return $shows_not_in;
	}

	public function get_schedule_name($schedule_id) {
		$query = 'SELECT name FROM schedules WHERE id = ?';
		$rows = $this->data->get_rows($query, [$schedule_id]);
		if($rows->length == 0) {
			return NULL;
		}
		return $rows[0]['name'];
	}

	public function save_schedule($v) {
		foreach($v['schedule_items'] as $schedule_item) {
			$this->_schedule_item($schedule_item);
		}
		return ['result' => 1];
	}

	public function get_shows($v=NULL) {
		$query = 'SELECT * FROM tv_shows ORDER BY tv_shows.name ASC';
		return $this->data->get_rows($query, []);
	}

	public function remove_schedule_item($v) {
		$query = 'DELETE FROM schedule_items WHERE id = ?';
		$this->data->execute($query, [$v['id']]);
		return ['result' => 1];
	}

	public function get_schedule_by_index($index) {
		$index = $index-1;
		$schedules = $this->get_schedules();
		$set_index = (-1);
		foreach($schedules as $schedule) {
			$set_index = $set_index+1;
			if($index == $set_index) {
				return $schedule;
			}
		}
		return NULL;
	}

	public function get_schedule_index($id) {
		$schedules = $this->get_schedules();
		$index = -1;
		foreach($schedules as $schedule) {
			$index = $index+1;
			if($schedule['id'] == $id) {
				return $index;
			}
		}
		return -1;
	}

	public function get_schedule_items($v, $perform_count=true) {
		$query = 'SELECT * FROM schedule_items WHERE schedule_id = ? ORDER BY order_value ASC';
		$rows = $this->data->get_rows($query, [$v['schedule_id']]);
		$results = [];
		if($object->isset($v['playback_options'])) {
			if($v['playback_options'] == 0) {
				$perform_count = false;
			}
		}

		if($perform_count) {
			$min_play_count = $this->min_play_count($v['schedule_id'], true);

			$show_counts = $min_play_count['shows'];
			$min_play_count = $min_play_count['count'];

			foreach($rows as $row) {
				$count = $shows_counts[$row['id']];
				if($count <= $min_play_count) {
					$results[] = $row;
				}
			}
		} else {
			return $rows;
		}

		return $results;
	}

	public function get_schedule_items_names($v) {
		$query = 'SELECT schedule_items.*, tv_shows.name, tv_shows.tags FROM schedule_items, tv_shows WHERE schedule_items.show_id = tv_shows.id AND schedule_id = ? ORDER BY order_value ASC';
		return $this->data->get_rows($query, [$v['schedule_id']]);
	}

	public function add_new_color_connection($v=NULL) {
		$id = $this->_smart_template_color_scheme($v);
		return ['id' => $id];
	}

	public function set_color_connection($v) {
		$tag_name = 'tag_'.$object->strings->split($v['which_color'], 'color_')[1];
		$send_data = [
			'id' => $v['id']
		];
		$send_data[$tag_name] = 'tag_'.$v['set_tag'];
		$this->_smart_template_color_scheme($send_data);
		return ['result' => 1];
	}

	public function set_color_frequency($v) {
		return $this->_smart_template_color_scheme([
			'id' => $v['id'],
			'frequency' => $v['frequency']
		]);
	}

	public function delete_color_connection($v) {
		$query = 'DELETE FROM smart_template_color_schemes WHERE id = ?';
		$this->data->execute($query, [$v['id']]);
		return ['result' => 1];
	}

	public function episodes_from_show($v) {
		$min_count = (-1);
		if($object->isset($v['schedule_id'])) {
			$min_count = $this->min_play_count($v['schedule_id']);	
		} else if($object->isset($v['show_id']) && $object->isset($v['by_count'])) {
			$min_count = $this->min_play_count_shows($v['show_id']);
		}
		$query = NULL;
		if($min_count == (-1)) {
			$query = 'SELECT * FROM episodes WHERE tv_show_id = ? AND active = 1 ORDER BY path ASC';
			return $this->data->get_rows($query, [$v['show_id']]);
		} else {
			$query = 'SELECT episodes.* FROM episodes WHERE active = 1 AND tv_show_id = ? AND (SELECT COUNT(*) FROM watch_log WHERE episode_id = episodes.id) <= ?  ORDER BY path ASC';
			return $this->data->get_rows($query, [$v['show_id'], $min_count]);
		}
		return [];
	}

	public function test1($v=NULL) {
		return ['result' => 1];
	}

	public function generate_tags_shows($v_generate_tags) {
		$query = 'SELECT * FROM tv_shows WHERE tags IS NULL OR tags = ? OR tags LIKE ? OR LENGTH(tags) = 0';
		$rows = $this->data->get_rows($query, ['', '%[]%']);
		$character_color_map = $v_generate_tags['map'];
		$tags = $v_generate_tags['tags'];
		foreach($rows as $row) {
			$characters = $object->strings->str_split($row['name']);
			$num1 = 0;
			$num2 = 0;
			foreach($characters as $ch) {
				$lower = $object->strings->lower($ch);
				if($object->isset($character_color_map[$lower])) {
					$character_color = $character_color_map[$lower];
					$num1 = $num1 + $object->index_of($tags, $character_color);
					$num2 = $num2+1;
				}
			}
			$index = 0;
			if($num2 != 0) {
				$index = $math->round($num1 / $num2);
			}
			if($index > $tags->length || $index < 0) {
				$index = 0;
			}
			$tag_index_value_item = 'tag '.$index;
			$tags_set_value = $object->toJSON([$tag_index_value_item]);
			$values = [
				'id' => $row['id'],
				'tags' => $tags_set_value
			];
			$this->_show($values);
		}
		return ['result' => 1];
	}

	public function set_smart_template_title($v) {
		return $this->_smart_template($v);
	}

	public function generate_from_smart_template($v) {
		$smart_template_id = $v['id'];
		return $this->get_smart_template($smart_template_id);
	}

	public function get_edit_smart_template($v) {
		$result = $this->get_smart_template($v['id'], true);
		$result['source_values'] = $this->get_schedules();
		return $result;
	}

	public function get_smart_template($id, $disable_gather_shows=false) {
		$query = 'SELECT * FROM smart_templates WHERE id = ?';
		$smart_template = $this->data->get_row($query, [$id]);
		$query = 'SELECT * FROM smart_template_color_schemes WHERE smart_template_id = ? ORDER BY id DESC';
		$color_schemes = $this->data->get_rows($query, [$id]);
		if($smart_template['sources'] == NULL) {
			$smart_template['sources'] = [];
		} else {
			$smart_template['sources'] = $object->fromJSON($smart_template['sources']);
			$smart_template['sources_ids'] = $object->fromJSON($smart_template['sources_ids']);
		}
		$smart_template['color_schemes'] = $color_schemes;


		$schedule_ids = [];
		$schedules = $this->get_schedules(NULL);



		$schedules_arr = [];
		foreach($schedules as $schedule) {
			$schedules_arr[] = $schedule['id'];
		}
		if($smart_template['sources']->length == 0 || $smart_template['sources_ids']->length == 0) {
			$disable_gather_shows = true;
		} else {
			$schedule_ids = $smart_template['sources_ids'];
		}
		
		$query = 'SELECT tv_shows.id, tv_shows.tags FROM tv_shows'; /*, tv_shows.decrease*/
		$tvshows = $this->data->get_rows($query, []);
		$shows = NULL;
		$shows_dictionary = ['test' => NULL];
		delete $shows_dictionary['test'];
		if(!$disable_gather_shows) {
			if($object->index_of($schedule_ids, (-1)) != (-1) || $schedule_ids->length == 0) {
				$shows = $tvshows;
			} else {
				foreach($schedule_ids as $schedule_id) {
					$query = 'SELECT tv_shows.id, tv_shows.tags, schedule_items.in_sequence FROM tv_shows, schedule_items WHERE schedule_items.show_id = tv_shows.id AND schedule_items.schedule_id = ?';
					$shows_result = $this->data->get_rows($query, [$schedule_id]);
					foreach($shows_result as $show_item) {
						$shows_dictionary['show_'.$show_item['id']] = $show_item;
					}
				}
				$shows = $object->values($shows_dictionary);
			}
		}
		if($shows == NULL) {
			$shows = $tvshows;
		}
		$color_scheme_marker = $object->create();
		foreach($shows as $show) {
			$tags = $object->fromJSON($show['tags']);
			foreach($tags as $tag) {
				$tag = $object->strings->join($object->strings->split($tag, ' '), '_');
				$color_scheme_marker[$tag] = true;
			}
		}
		
		$verified_tags = $object->create();
		foreach($color_schemes as $color_scheme) {
			$tag_a = $color_scheme['tag_a'];
			$tag_b = $color_scheme['tag_b'];
			if($object->isset($color_scheme_marker[$tag_a])) {
				$verified_tags[$tag_a] = true;
			}
			if($object->isset($color_scheme_marker[$tag_b])) {
				$verified_tags[$tag_b] = true;
			}
		}

		$smart_template['verified_tags'] = $verified_tags;
		$smart_template['sources_indicies'] = $smart_template['sources'];
		$smart_template['sources'] = $shows;

		/*foreach($shows as $show_item) {

		}*/

		return $smart_template;
	}

	public function clear_smart_templates($v=NULL) {
		$values = [
			'id' => $v['id'],
			'sources' => '[  ]',
			'sources_ids' => '[ ]'
		];
		$this->_smart_template($values, false);
		return ['result' => 1];
	}

	public function set_smart_template_source_index($v) {
		$query = 'SELECT * FROM smart_templates WHERE id = ?';
		$smart_template = $this->data->get_row($query, [$v['smart_template_id']]);
		if($smart_template['sources'] != NULL && $object->strings->strlen($smart_template['sources']) > 0) { 	
			$smart_template['sources'] = $object->fromJSON($smart_template['sources']);
		} else {
			$smart_template['sources'] = [];
		}
		if($smart_template['sources']->length > $v['set_index_value']) {
			$smart_template['sources'][$v['set_index_value']] = $v['set_id'];
		} else {
			$smart_template['sources'][] = $v['set_id'];
		}
		$v = [
			'id' => $smart_template['id'],
			'sources' => $object->toJSON($smart_template['sources'])
		];
		$this->_smart_template($v);
		return ['result' => 1];
	}

	public function get_schedules($v=NULL) {
		$query = 'SELECT * FROM schedules ORDER BY id ASC';
		return $this->data->get_rows($query, []);
	}

	public function get_smart_templates($v) {
		$query = 'SELECT * FROM smart_templates ORDER BY id ASC';
		return $this->data->get_rows($query, []);
	}

	public function min_show_count($v) {
		$count = 0;
		foreach($this->get_episodes($v) as $episode) {
			$query = 'SELECT COUNT(*) as watch_count FROM watch_log WHERE episode_id = ?';
			$watch_count = $this->data->get_rows($query, [$episode['id']])[0]['watch_count'];
			if($watch_count < $count || $count == 0) {
				$count = $watch_count;
			}
		}
		return $count;
	}

	public function get_episodes($v) {
		$query = 'SELECT * FROM episodes WHERE tv_show_id = ? ORDER BY path ASC';
		return $this->data->get_rows($query, [$v['show_id']]);
	}

	public function get_episodes_with_play_counts($v) {
		$query = 'SELECT * FROM episodes WHERE tv_show_id = ? ORDER BY path ASC';
		$rows = $this->data->get_rows($query, [$v['show_id']]);

		foreach($rows as $row) {
			$query = 'SELECT COUNT(*) as watch_count FROM watch_log WHERE episode_id = ?';
			$watch_count = $this->data->get_row($query, [$row['id']])['watch_count'];

			$row['watch_count'] = $watch_count;
		}

		return $rows;
	}

	public function get_all_episodes() {
		$query = 'SELECT * FROM episodes';
		return $this->data->get_rows($query, []);
	}

	public $stored_min_play_count = NULL;

	public function get_next_episode($v) {
		$show_id = $v['show_id'];
		$schedule = NULL;
		$schedule_id = NULL;
		if($object->isset($v['template_id'])) {
			$schedule_id = $v['template_id'];

			$query = 'SELECT * FROM schedules WHERE id = ?';
			$schedule = $object->get_first_row($this->data->get_rows($query, [$schedule_id]));
		}
		$playback_options = 0;
		if($schedule != NULL) {
			$playback_options = $schedule['playback_options'];
		}
		$min_play_count = -1;
		if($playback_options == 1) {
			$min_play_count = $this->min_play_count();
		} else if($playback_options == 2) {
			/*if(false && $object->isset($this->stored_min_play_count[$schedule_id])) {
				$min_play_count = $this->stored_min_play_count[$schedule_id];
			} else {*/
				$min_play_count = $this->min_play_count($schedule_id);
			/*}*/
		} else if($playback_options == 3) {
			$min_play_count = 0;
		}

		
		$last_played_episode_rows = $this->last_played_episode(['id' => $show_id]);
		$episodes = [];
		if($min_play_count > (-1)) {
			$episodes = $this->filter_episodes_by_play_count($show_id, $min_play_count);
		} else {
			$episodes = $this->episodes_from_show($v);
		}
		if($episodes->length == 0) {
			return ['__skip_to_next' => true];
		}
		if($last_played_episode_rows->length == 0) {
			if($episodes->length > 0) {
				return $episodes[0];
			}
			return ['__skip_to_next' => true];
		}
		$next_index = $object->index_of($object->map($episodes, function($row) {
			return $row['id'];
		}), $last_played_episode_rows[0]['episode_id']);
		$next_index = $next_index+1;
		if($next_index >= $episodes->length) {
			$next_index = 0;
		}
		return $episodes[$next_index];
	}

	public function filter_episodes_by_play_count($show_id, $play_count) {
		$query = 'SELECT episodes.* FROM episodes WHERE tv_show_id = ? AND (SELECT COUNT(*) FROM watch_log WHERE episode_id = episodes.id) <= ? ORDER BY path ASC';
		return $this->data->get_rows($query, [$show_id, $play_count]);
	}

	/*private $store_show_play_count;*/

	private function min_play_count_shows($show_id) {
		$episodes = $this->get_episodes(['show_id' => $show_id]);
		$count = (-1);
		foreach($episodes as $episode) {
			$query = 'SELECT COUNT(*) as watch_count FROM watch_log WHERE episode_id = ?';
			$watch_count = $this->data->get_row($query, [$episode['id']])['watch_count'];
			if($watch_count < $count || $count == (-1)) {
				$count = $watch_count;
			}
		}
		/*$object->log($object->toJSON(['show_id' => $show_id, 'min_count' => $count]));*/
		return $count;
	}

	public function min_play_count($schedule_id=NULL, $return_shows=false) {
		$count = (-1);
		/*if($this->stored_min_play_count == NULL) {
			$this->stored_min_play_count = $object->create();
			$this->store_show_play_count = $object->create();
		}*/
		if($schedule_id == NULL) {
			foreach($this->get_all_episodes() as $episode) {
				$query = 'SELECT COUNT(*) as watch_count FROM watch_log WHERE episode_id = ?';
				$watch_count = $this->data->get_rows($query, [$episode['id']])[0]['watch_count'];
				if($watch_count < $count || $count == (-1)) {
					$count = $watch_count;
				}
			}
			if($count == (-1)) {
				return 0;
			}
			return $count;
		} else {
			$shows = $object->create();
			$schedule_items = $this->get_schedule_items(['schedule_id' => $schedule_id], false);
			foreach($schedule_items as $schedule_item) {
				$show_id = $schedule_item['show_id'];
				/*if(false && $object->isset($this->store_show_play_count[$show_id])) {
					$shows[$show_id] = $this->store_show_play_count[$show_id];
				} else {*/
					$episodes = $this->get_episodes(['show_id' => $show_id]);
					$shows_count_value = NULL;
					foreach($episodes as $episode) {
						$query = 'SELECT COUNT(*) as watch_count FROM watch_log WHERE episode_id = ?';
						$watch_count = $this->data->get_rows($query, [$episode['id']])[0]['watch_count'];
						if($watch_count < $count || $count == (-1)) {
							$count = $watch_count;
							$shows_count_value = $count;
						}
					}
					$shows[$show_id] = $shows_count_value;
					/*$this->store_show_play_count[$show_id] = $shows_count_value;*/
				/*}*/
			}
			/*$this->stored_min_play_count[$schedule_id] = $count;*/
			if($return_shows) {
				return ['shows' => $shows, 'count' => $count];
			}
			if($count == (-1)) {
				return 0;
			}
			return $count;
		}
		return 0;
	}

	public function last_played_episode($v) {
		$query = 'SELECT watch_log.episode_id as episode_id FROM watch_log, episodes WHERE watch_log.episode_id = episodes.id AND episodes.tv_show_id = ? ORDER BY watch_log.id DESC LIMIT 1';
		return $this->data->get_rows($query, [$v['id']]);
	}

	public function add_path_to_log($v) {
		$query = 'SELECT * FROM episodes WHERE path = ?';
		$rows = $this->data->get_rows($query, [$v['path']]);
		if($rows->length > 0) {
			$id = $rows[0]['id'];
			$this->add_to_watch_log(['episode_id' => $id]);
			return ['result' => true, 'row' => $rows[0]];
		}
		return ['result' => false];
	}

	public function invalidate_play_count($show_id) {
		if($object->isset($this->store_show_play_count[$show_id])) {
			delete $this->store_show_play_count[$show_id];
		}
	}

	public function add_to_watch_log($v) {
		/*if($object->isset($v['episode_id']) && $object->isset($this->store_show_play_count)) {
			$query = 'SELECT * FROM episodes WHERE id = ?';
			$episode = $object->get_first_row($this->data->get_rows($query, [$v['episode_id']]));
			if($episode != NULL) {
				$show_id = $episode['tv_show_id'];
				$this->invalidate_play_count($show_id);
			}
		}*/
		$insert = $this->data->statement->generate($v, 'watch_log');
		$this->data->_($insert, $v);
		return ['result' => 1];
	}

	public function display_episode_preview($v) {
		$query = 'SELECT * FROM episodes WHERE id = ?';
		$row = $this->data->get_row($query, [$v['episode_id']]);
		if($row != NULL) {
			$this->base_instance->display_preview($v['coordinates'], $row['path'], NULL);
		}/* else {

		}*/
		return ['result' => 1];
	}

	public function hide_preview($v) {
		$this->base_instance->hide_preview();
		return ['result' => 1];
	}

	public function reset($v) {
		$this->data->execute('DELETE FROM episodes', []);
		$this->data->execute('DELETE FROM schedule_items', []);
		$this->data->execute('DELETE FROM schedules', []);
		$this->data->execute('DELETE FROM tv_shows', []);
		$this->data->execute('DELETE FROM watch_log', []);
		$this->data->execute('DELETE FROM locations', []);
		$this->data->execute('DELETE FROM smart_template_color_schemes', []);
		$this->data->execute('DELETE FROM smart_templates', []); 
	}
}

?>