<?

class store_words {
	private $data;

	private $statement;

	public function __construct() {

		$this->data = $data->main_instance;/*$data->fetch('main');*/

		$this->statement =  $data->statement;/*new statement();*/
	}

	public function store($tags) {
		foreach($tags as $tag_value => $vector) {
			/*$object->log('store');
			$object->log($tag_value);
			$object->log($object->toJSON($vector));*/
			$query = 'UPDATE tag_vectors SET vector_value = ?, rd7 = 150 WHERE tag_value = ?';
			$this->data->execute($query, [$object->toJSON($vector), $tag_value]);
		}
	}
}

class wordnet {

	private $vectors_by_type;

	private $data;

	private $evaluation;

	private $tags_vectors_index;

	private $statement;

	public $ignore_vector_columns;

	private $errors;

	public function __construct($skip=false) {
		$this->ignore_vector_columns = $object->create();
		$this->errors = $object->create();
		/*$evaluation = new evaluation();
		$evaluation->__set_configuration(16, NULL, ['value' => '0', 'remainder' => '1/10000'], false, 4, 4, true);

		$this->evaluation = $evaluation;*/

		$this->vector = new m_vector();

		$this->data = $data->main_instance;/*$data->fetch('main');*/

		$this->statement =  $data->statement;/*new statement();*/

		$this->vectors_by_type = [
			'genres' => $object->create(),
			'companies' => $object->create(),
			'tropes' => $object->create(), 
			'popculture' => $object->create(),
			'themes' => $object->create(),
			'lists' => $object->create(),
			'movies' => $object->create(),
			'persons' => $object->create()
		];

		$this->tags_vectors_index = $object->create();

		/*$query = 'SELECT COUNT(*) as count FROM tag_vectors';
		$object->log('get count');

		$count = $this->data_instance->get_row($query, [])['count'];

		$object->log($count);*/
		$query = 'SELECT * FROM medias';
		$rows = $this->data->get_rows($query, []);

		$acceptible_tags = $object->create();

		foreach($rows as $row) {
			$all_tags = [];
			if($row['all_cache_field_search'] != NULL && $object->strings->strlen($row['all_cache_field_search']) > 0) {
				$all_tags = $object->fromJSON($row['all_cache_field_search']);
			}
			if(!$object->isset($all_tags) || $all_tags == NULL) {
				$all_tags = [];
			}
			if($all_tags->length > 2) {
				$item = [
					'vector_value' => NULL,
					'all_tags' => $all_tags,
					'tag_value' => $row['title']
				];

				foreach($all_tags as $acceptible_tag) {
					$acceptible_tags[$acceptible_tag] = true;
				}

				$this->vectors_by_type['movies'][$row['title']] = $item;
			}
		}

		$query = 'SELECT * FROM tag_vectors';
		$rows = $this->data->get_rows($query, []);



		$this->tag_type_index = $object->create();

		foreach($rows as $row) {

			/*$object->log($object->toJSON($row));
			$object->log($object->toJSON(['title' => $row['tag_value'], 'type' => $row['type']]));*/
			if($object->isset($row['tag_value']) && $row['tag_value'] != NULL) {
				if($object->isset($acceptible_tags[$row['tag_value']]) || $row['type'] == 'movies') {
					$this->tag_type_index[$row['tag_value']] = $row['type'];
					if($row['type'] != 'format') {


	/*id|tag_value|scalar_value|tag_vectors_id|locked|complexity_simplicity|intensity|seriousness|comedicity|absurdity|physicality|violence|romance|surprisinginess_predictability|scale|locality_globality|structure_randomness|intellectuality_mindlessness|rd1|rd2|rd3|rd4|rd5|rd6|rd7|complexity_simplicity_locked|intensity_locked|seriouesness_locked|comedicity_locked|absurdity_locked|physicality_locked|violence_locked|action_locked|romance_locked|surprisingness_predictability_locked|scale_locked|locality_globality_locked|stucture_randomness_locked|intellectuality_mindlessness_locked|action_value|type*/

						/*$vector_value = [
							$row['intensity'],
							$row['seriousness'],
							$row['comedicity'],
							$row['absurdity'],
							$row['physicality'],
							$row['violence'],
							$row['action_value'],
							$row['romance'],
							$row['surprisinginess_predictability'],
							$row['scale'],
							$row['locality_globality'],
							$row['structure_randomness'],
							$row['intellectuality_mindlessness'],
							$row['rd1'],
							$row['rd2'],
							$row['rd3'],
							$row['rd4'],
							$row['rd5'],
							$row['rd6'],
							$row['rd7']
						];*/
						/*$object->log($row['tag_value']);
						$object->log($row['vector_value']);*/
						$vector_value = $object->fromJSON($row['vector_value']);




						$this->tags_vectors_index[$row['tag_value']] = $vector_value;
						/*foreach($vector_value as $index => $value_vector) {
							$vector_value[$index] = $evaluation->whole_common($value_vector);
						}*/
						/*$object->log('set vector '.$row['tag_value']);
						$object->log($object->toJSON($row));
						$object->log($object->toJSON($vector_value));*/
						if($row['type'] == 'movies') {
							if($object->isset($this->vectors_by_type['movies'][$row['tag_value']])) {
								$this->vectors_by_type['movies'][$row['tag_value']]['vector_value'] = $vector_value;
							}
						} else if($row['type'] != 'movies') {

							$item = [
								'vector_value' => $vector_value,
								'tag_value' => $row['tag_value']
							];


							$this->vectors_by_type[$row['type']][$row['tag_value']] = $item;
						}
					}
				}
			}
		}

		$object->log('ended: ');

		foreach($this->vectors_by_type as $type => $values) {
			$object->log($type);
			$object->log($object->keys($values)->length);
			$object->log($object->values($values)->length);
			if($type == 'movies') {
				/*$object->log('movies');
				foreach($values as $tag => $vector) {
					$object->log($tag);
					$object->log($object->toJSON($vector));
				}
				$object->log('movies-end');*/
				$delete_index = [];
				foreach($values as $movie => $item) {
					if($item['vector_value'] === NULL) {
						$delete_index[] = $movie;
						/*$object->log($item['vector_value']);
						$object->log('delete: '.$movie);*/
					}
				}

				foreach($delete_index as $index_value) {
					delete $values[$index_value];
				}
			}

			$object->log($object->keys($values)->length);
			$object->log($object->values($values)->length);
		}

		foreach($this->vectors_by_type['movies'] as $movie_title => $item) {
			/*$object->log($movie_title);*/
			/*$object->log($object->toJSON($item));*/
			$tags = $item['all_tags'];
			/*$object->log($tags);
			$object->log($object->toJSON($tags));*/
			foreach($tags as $tag_value) {
				if($tag_value != NULL && $object->strings->strlen($tag_value) > 0) {

					$tag_value = $object->strings->trim($tag_value);
					/*$object->log($tag_value.'-'.$object->strings->strlen($tag_value));*/
					if($object->isset($this->tag_type_index[$tag_value])) {
						/*$object->log('get tag type index');*/
						$type = $this->tag_type_index[$tag_value];
						/*$object->log($type);*/
						if($object->isset($type)) { /* && $type != 'persons'*/
							$associated_tag_item = $this->vectors_by_type[$type][$tag_value];
							/*$object->log($associated_tag_item);*/
							if($object->isset($associated_tag_item)) {
								if(!$object->isset($item[$type])) {
									$item[$type] = $object->create();
								}
								if(!$object->isset($item['tags_vectors'])) {
									$item['tags_vectors'] = $object->create();
								}

								$item[$type][$tag_value] = $associated_tag_item;
								$item['tags_vectors'][$tag_value] = $associated_tag_item;

								if(!$object->isset($associated_tag_item['movies'])) {
									$associated_tag_item['movies'] = $object->create();
								}
								$associated_tag_item['movies'][$movie_title] = $item;
							}
						}
					}
				}
			}
		}

		


		$object->log('before train');

		$object->log('after train');


		/*$counter_training = 0;
		while($counter_training < 40) {*/
			/*1000*/
			/*$counter_training++;
		}*/
		/*$this->column_errors();*/
	}

	public function run_test() {
		$test = $this->tags_vectors_index['The Toxic Avenger'];

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


		$test = $this->tags_vectors_index['Scream'];

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


		$test = $this->vector->add_vector($this->tags_vectors_index['Scream'], $this->tags_vectors_index['Horror']);

		/*$test = $this->vector->add_vector($this->tags_vectors_index['Scream'], $this->tags_vectors_index['Comedy']);*/

		$test = $this->vector->normalize_vector($test);

		$min_value = -1;
		$min_tag = NULL;

		/*foreach($this->tags_vectors_index as $tag => $vector) {*/
		foreach($this->vectors_by_type['movies'] as $tag => $vector) {
			$distance = $this->vector->length_value($test, $vector['vector_value']);
			/*$object->log($tag);
			$object->log($distance);*/
			if($min_value == (-1) || $distance < $min_value) {
				$min_value = $distance;
				$min_tag = $tag;

				$object->log('set min: '.$min_tag);
			}
		}

		$object->log('min tag: '.$min_tag);

		$object->log($object->toJSON($test));
	}

	public function run() {


		$counter_iteration = 0;
		while($counter_iteration < 500) {
			$this->train();
			$counter_iteration++;
		}

		/*return $this->train();*/

		/*$this->run_test();*/

		/*$last_vector = NULL;

		$vectors = [];

		foreach($this->tags_vectors_index as $v) {
			if($vectors->length < 100) {
				$vectors[] = $v;
			}
		}

		foreach($vectors as $tag => $vector) {
			if($last_vector != NULL) {
				$res = $this->vector->length_value($vector, $last_vector);
				$object->log($res);
			}
			$last_vector = $tag;
		}*/
	}

	private $learning_rate = 15;/*15;*//**500;*/ /*0.005;*/

	public $vector;

	public $current_index = 0;

	private function random_index($count) {
		/*$set_index = $this->current_index;
		$this->current_index += 1;
		if($this->current_index >= $count) {
			$this->current_index = 0;
		}
		return $set_index;*/
		return $math->random_int($count);
	}
	/*
						$row['intensity'],
						$row['seriousness'],
						$row['comedicity'],
						$row['absurdity'],
						$row['physicality'],
						$row['violence'],
						$row['action_value'],
						$row['romance'],
						$row['surprisinginess_predictability'],
						$row['scale'],
						$row['locality_globality'],
						$row['structure_randomness'],
						$row['intellectuality_mindlessness'],
						$row['rd1'],
						$row['rd2'],
						$row['rd3'],
						$row['rd4'],
						$row['rd5'],
						$row['rd6'],
						$row['rd7']*/

	private $set_columns = [
		'intensity',
		'seriousness',
		'comedicity',
		'absurdity',
		'physicality',
		'violence',
		'action_value',
		'romance',
		'surprisinginess_predictability',
		'scale',
		'locality_globality',
		'structure_randomness',
		'intellectuality_mindlessness',
		'rd1',
		'rd2',
		'rd3',
		'rd4',
		'rd5',
		'rd6',
		'rd7'
	];

	public function train_sub_item($item, $index, $exclude_extras=false) {
		$normalized = $this->vector->normalize_vector($item['vector_value']);

		if($object->isset($item['movies'])) {
			$total_error = NULL;

			foreach($item['movies'] as $movie) {
				if($total_error === NULL) {
					if($object->isset($movie['vector_value'])) {
						/*$total_error = $movie['vector_value'];
						$total_error = [...$total_error];*/
						$total_error = [];

						foreach($movie['vector_value'] as $vector_item_value) {
							$total_error[] = $vector_item_value;
						}
					}
				} else {
					if($object->isset($movie['vector_value'])) {
						$total_error = $this->vector->add_vector($total_error, $movie['vector_value']);
					}
				}
				if($object->isset($movie['tags_vectors']) && $exclude_extras && $total_error != NULL) {
					$tag_total_vector = NULL;

					foreach($movie['tags_vectors'] as $tag_value => $tag_item) {

						if($tag_value != $item['tag_value']) {
							if($object->isset($tag_item['vector_value'])) {
								if($tag_total_vector === NULL) {
									/*$tag_total_vector = $tag_item['vector_value'];
									$tag_total_vector = [...$tag_total_vector];*/
									$tag_total_vector = [];
									foreach($tag_item['vector_value'] as $vector_item_value) {
										$tag_total_vector[] = $vector_item_value;
									}
								} else {
									$tag_total_vector = $this->vector->add_vector($tag_total_vector, $tag_item['vector_value']);
								}
							}
						}

						if($tag_total_vector != NULL) {
							$tag_total_vector = $this->vector->normalize_vector($tag_total_vector);
							$total_error = $this->vector->subtract_vector($total_error, $tag_total_vector);
							/*$total_error = $this->vector->subtract_vector($tag_total_vector, $total_error);*/
						}
					}
				}
			}

			if($total_error != NULL && $item['vector_value']->length > 0) {
				$total_error = $this->vector->normalize_vector($total_error);

				$error_value = $this->vector->length_value($normalized, $total_error);

				$index = $this->random_index($item['vector_value']->length);

				/*$addition = $math->pow($error_value, 2) * ($item['vector_value'][$index]/($math->pow($math->abs($item['vector_value'][$index]), 1/2)));*/

				$addition = $this->get_error_addition($error_value, $item['vector_value'][$index]);


				/*$addition = $item['vector_value'][$index] * ($error_value / ($math->pow($math->abs($error_value), 1/2)));*/
			
				if($object->isset($addition) && $addition != 'nan' && $addition > 0) {
					$addition = $addition / $this->learning_rate;
				}

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

				if($addition != 'nan') {
					$item['vector_value'][$index] += $addition;
				}

				$this->errors[$item['tag_value']] = $addition;
				return $error_value;
			}
		}
	}

	private function get_error_addition($item_value, $error_value) {
		$addition = $math->pow($item_value, 2) * ($error_value / $math->pow($math->abs($error_value), 1/2));

		return $addition;
	}

	/*private function get_error_addition($error_value, $item_value) {
		$addition = $math->pow($item_value, 2) * ($error_value / $math->pow($math->abs($error_value), 1/2));

		return $addition;
	}*/

	/*public function train_sub_set($ids) {
		foreach($ids as $id) {
			$object->log('train sub set '.$id);
			foreach($this->vectors_by_type[$id] as $genre_title => $genre_item) {
				$this->train_sub_item($genre_item, true);
			}
		}
	}*/

	public function column_errors() {
		/*$index = $this->random_index($this->set_columns->length);*/

		$ignore_index = 0;

		$set_total_error_value = 0;

		$items_count = 0;

		$error_values = $object->create();

		while($ignore_index < 20) {
			$error_values[$ignore_index] = 0;

			foreach($this->vectors_by_type['movies'] as $title => $movie) {
				/*$object->log($title);
				$object->log($object->toJSON($movie['vector_value']));*/

				$movie_error = 0;

				/*$vector_value = $movie['vector_value'];

				$vector_value = [...$vector_value];*/

				$vector_value = [];

				foreach($movie['vector_value'] as $vector_item_value) {
					$vector_value[] = $vector_item_value;
				}

				if($vector_value->length > 0) {

					$object->splice($vector_value, $ignore_index, 1);

					$normalized_movie = $this->vector->normalize_vector($vector_value);

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

					$tag_total_vector = NULL;

					if($object->isset($movie['tags_vectors'])) {



						foreach($movie['tags_vectors'] as $tag_value => $tag_item) {
							if($object->isset($tag_item['vector_value'])) {
								if($tag_total_vector === NULL && $tag_item['vector_value']->length > 0) {
									/*$tag_total_vector = $tag_item['vector_value'];
									$tag_total_vector = [...$tag_total_vector];*/
									$tag_total_vector = [];
									foreach($tag_item['vector_value'] as $tag_item_value) {
										$tag_total_vector[] = $tag_item_value;
									}

									$object->splice($tag_total_vector, $ignore_index, 1);
								} else if($tag_item['vector_value']->length > 0) {
									/*$tag_item_vector = $tag_item['vector_value'];
									$tag_item_vector = [...$tag_item_vector];*/
									$tag_total_vector = [];
									foreach($tag_item['vector_value'] as $tag_item_value) {
										$tag_total_vector[] = $tag_item_value;
									}

									$object->splice($tag_item_vector, $ignore_index, 1);

									$tag_total_vector = $this->vector->add_vector($tag_total_vector, $tag_item_vector);
								}
							}
						}

					}

					if($tag_total_vector != NULL && $movie['vector_value']->length > 0) {

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

						$tag_total_vector = $this->vector->normalize_vector($tag_total_vector);

						$movie_error = $this->vector->length_value($normalized_movie, $tag_total_vector);



						$error_values[$ignore_index] += $movie_error;
					}

				}
				/*x_value += error_value * x_value/√(abs(x_value)) * learning_rate*/

				/*return false;*/
			}
			$ignore_index++;
		}

		$object->log($object->toJSON($error_values));
		return $error_values;
	}

	public function train() {
		/*$counter_iteration = 0;*/


		/*$column_errors = $this->column_errors();

		$min_index = -1;

		$min_value_columns = -1;

		foreach($column_errors as $column_error_index => $column_error_value) {
			if($column_error_value > $min_value_columns || $min_value_columns == (-1)) {
				$min_index = $object->to_number($column_error_index);
				$min_value_columns = $column_error_value;
			}
		}

		$object->log('max index: '.$min_index.' '.$min_value_columns);*/

		/*while($counter_iteration < $iterations) {*/

			$index = $this->random_index($this->set_columns->length);

			/*$index = $min_index;*/

			$set_total_error_value = 0;

			$items_count = 0;

			foreach($this->vectors_by_type['movies'] as $title => $movie) {

				$movie_error = 0;

				$normalized_movie = $this->vector->normalize_vector($movie['vector_value']);


				$tag_total_vector = NULL;

				if($object->isset($movie['tags_vectors'])) {



					foreach($movie['tags_vectors'] as $tag_value => $tag_item) {
						if($object->isset($tag_item['vector_value'])) {
							if($tag_total_vector === NULL) {
								/*$tag_total_vector = $tag_item['vector_value'];
								$tag_total_vector = [...$tag_total_vector];*/
								$tag_total_vector = [];
								foreach($tag_item['vector_value'] as $tag_item_value) {
									$tag_total_vector[] = $tag_item_value;
								}
							} else {
								$tag_total_vector = $this->vector->add_vector($tag_total_vector, $tag_item['vector_value']);
							}
						}
					}

				}

				if($tag_total_vector != NULL && $movie['vector_value']->length > 0) {


					$tag_total_vector = $this->vector->normalize_vector($tag_total_vector);

					$movie_error = $this->vector->length_value($normalized_movie, $tag_total_vector);

					/*$index = $this->random_index($this->set_columns->length);*/

					/*$addition = $math->pow($movie_error, 2) * ($movie['vector_value'][$index]/($math->pow($math->abs($movie['vector_value'][$index]), 1/2)));*/


					$addition = $this->get_error_addition($movie_error, $movie['vector_value'][$index]);

					/*$addition = $movie['vector_value'][$index] * ($movie_error / ($math->pow($math->abs($movie_error), 1/2)));*/
					

					if($object->isset($addition) && $addition != 'nan' && $addition > 0) {
						$addition = $addition / $this->learning_rate;
					}
					
					/*$object->log($addition);*/

					if($addition != 'nan') {
						$movie['vector_value'][$index] += $addition;
					}


					$this->errors[$movie['tag_value']] = $addition;

					$set_total_error_value += $movie_error;
					$items_count++;
				}

			}


			foreach($this->vectors_by_type['genres'] as $genre_title => $genre_item) {
				$set_movie_error = $this->train_sub_item($genre_item, $index);


				$set_total_error_value += $set_movie_error;
				$items_count++;
			}



			foreach($this->vectors_by_type['companies'] as $genre_title => $genre_item) {
				$set_movie_error = $this->train_sub_item($genre_item, $index);


				$set_total_error_value += $set_movie_error;
				$items_count++;
			}

			foreach($this->vectors_by_type['persons'] as $genre_title => $genre_item) {
				$set_movie_error = $this->train_sub_item($genre_item, $index);


				$set_total_error_value += $set_movie_error;
				$items_count++;
			}


			foreach($this->vectors_by_type['tropes'] as $genre_title => $genre_item) {
				$set_movie_error = $this->train_sub_item($genre_item, $index, true);
				$set_total_error_value += $set_movie_error;
				$items_count++;
			}

			foreach($this->vectors_by_type['popculture'] as $genre_title => $genre_item) {
				$set_movie_error = $this->train_sub_item($genre_item, $index, true);
				$set_total_error_value += $set_movie_error;
				$items_count++;
			}

			foreach($this->vectors_by_type['themes'] as $genre_title => $genre_item) {
				$set_movie_error = $this->train_sub_item($genre_item, $index, true);
				$set_total_error_value += $set_movie_error;
				$items_count++;
			}
			
			$object->log('iteration : '.$counter_iteration);
			$object->log($set_total_error_value/$items_count);

			foreach($this->tags_vectors_index as $tag_value => $vector) {
				$normalized = $this->vector->normalize_vector($vector);
				foreach($vector as $index => $value) {
					$vector[$index] = $normalized[$index];
				}
			}
			$counter_iteration++;
		/*}*/

		/*return ['tags' => $this->tags_vectors_index, 'errors' => $this->errors];*/

		$object->log($this->tags_vectors_index);
		$object->log($object->keys($this->tags_vectors_index)->length);

		foreach($this->tags_vectors_index as $tag_value => $vector) {
			/*$query = 'UPDATE tag_vectors SET ';

			$data_values = [...$vector];

			foreach($this->set_columns as $index => $column) {
				if($index > 0) {
					$query = $query.' , ';
				}
				$query = $query.' '.$column.' = ? ';
			}

			$query = $query.' WHERE tag_value = ?';

			$object->log($query);


			$data_values[] = $tag_value;

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

			/*$object->log($tag_value);
			$object->log($vector);
			$object->log($object->toJSON($vector));*/

			$query = 'UPDATE tag_vectors SET vector_value = ?, rd7 = 150 WHERE tag_value = ?';
			$this->data->execute($query, [$object->toJSON($vector), $tag_value]);

			/*$object->log('saved');*/
		}

	}

	public function store($tags) {
		foreach($tags as $tag_value => $vector) {
			$object->log('store');
			$object->log($tag_value);
			$object->log($object->toJSON($vector));
			/*$query = 'UPDATE tag_vectors SET ';

			$data_values = [...$vector];

			foreach($this->set_columns as $index => $column) {
				if($index > 0) {
					$query = $query.' , ';
				}
				$query = $query.' '.$column.' = ? ';
			}

			$query = $query.' WHERE tag_value = ?';

			$object->log($query);


			$data_values[] = $tag_value;

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

			$query = 'UPDATE tag_vectors SET vector_value = ?, rd7 = 150 WHERE tag_value = ?';
			/*$vector = $this->vector->normalize_vector($vector);*/
			$this->data->execute($query, [$object->toJSON($vector), $tag_value]);

			/*$object->log('saved');*/
		}
	}

	private $tag_type_index;
}

?>