<?

class filters {

	private $clusters;

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

		/*$iterator = new iterator();

		$l_index = $object->create();

		$iterator->iterate($clusters->length, function($x, $y) {

		});*/


		$this->main_adder_h = new adder_linear($this->clusters->length);
		$this->main_adder_s = new adder_linear($this->clusters->length);

		foreach($this->clusters as $cluster) {
			$cluster->adder_h = new adder_linear(9);
			$cluster->adder_s = new adder_linear(9);
		}

	}

	public $main_adder_h;
	public $main_adder_s;


	public function train($iteration_count, $input_field, $size=20) {
		$counter = 0;

		$generator = new generator();

		$inputs = $generator->random_points($size, 1, 0);
		$outputs = $generator->random_points($size, 1, 0);

		$iterator = new iterator();

		$iterator->iterate($size, function($x, $y) {
			$inputs[$y][$x] = $input_field[$y][$x][0];
			$outputs[$y][$x] = [$input_field[$y][$x][1], $input_field[$y][$x][2]];
		});

		$last_total_error = 0;

		$m_vector = new m_vector();

		/*foreach($this->clusters as $cluster) {
			
			$set_vectors = $object->create();

				
			foreach($cluster['vectors'] as $vector) {

				$vector = [...$vector];

				foreach($vector as $v_key => $value) {
					$vector[$v_key] = $object->color_to_byte($value);
				}

				$hs = $object->splice($vector, 0, 2);


				$vector = $object->toJSON($vector);

				$get_dict = $set_vectors[$vector];

				if($object->isset($get_dict) && $get_dict != NULL) {
					$object->log('duplicate found');
					$object->log($get_dict);
					$object->log($hs);

					if($get_dict != $hs) {
						$object->log('different value: '.$object->toJSON($hs).' '.$object->toJSON($get_dict));
					}
				}
				$set_vectors[$vector] = $hs;

				$set_vectors_values = [];
			}


			$same_lines = $object->create();

			foreach($set_vectors as $set_vector => $hs_value) {
				$set_vector = $object->fromJSON($set_vector);
				$set_vector = [...$set_vector];

				$set_vector[] = $hs_value[0];
				$set_vector[] = $hs_value[1];

				$normalized = $m_vector->normalize($set_vector);

				$normalized = $object->toJSON($normalized);

				if(!$object->isset($same_lines[$normalized])) {
					$same_lines[$normalized] = [];
				}
				$same_lines_item = $same_lines[$normalized];

				$same_lines_item[] = $set_vector;
				$set_vectors_values[] = $set_vector;
			}

			$object->log('same line count: ');
			$object->log($object->keys($same_lines)->length);


			foreach($same_lines as $normalized_key => $same_line_vectors) {

				$median = NULL;


				$object->log('same lines count: ');
				$object->log($object->keys($same_line_vectors)->length);

				foreach($same_line_vectors as $same_line_vector) {
					if($median == NULL) {
						$median = [...$same_line_vector];
					} else {
						$median = $m_vector->add_vector($median, $same_line_vector);
					}
				}

				$median = $m_vector->stretch_vector($median, (1/$same_line_vectors->length));
				$object->log('median is');
				$object->log($object->toJSON($median));
			}
		}

		return false;*/

		/*$restart = true;

		while($restart) {*/

		while($counter < $iteration_count) {
			$total_error = 0;

			foreach($this->clusters as $cluster) {
			
				/*$h_total = 0;

				$s_total = 0;

				$cluster_vector_count = 0;*/

				/*$cluster->adder_h->perform_normalize();
				$cluster->adder_s->perform_normalize();*/

				foreach($cluster['vectors'] as $vector) {
					$vector = [...$vector];

					$hs = $object->splice($vector, 0, 2);

					$input = $vector;


					$error_value_h = $cluster->adder_h->get_error_alt($input, $hs[0]);

					$object->log('error value h: '.$error_value_h);

					$total_error = $total_error + $error_value_h;
					/*$h_total = $h_total + $error_value_h;*/

					$error_value_s = $cluster->adder_s->get_error_alt($input, $hs[1]);


					$object->log('error value s: '.$error_value_s);

					$total_error = $total_error + $error_value_s;
					/*$s_total = $h_total + $error_value_s;

					$cluster_vector_count = $cluster_vector_count + 1;*/
				}

				/*$h_total = $h_total / $cluster_vector_count;
				$s_total = $s_total / $cluster_vector_count;

				if($h_total > $this->reset_threshold) {
					$cluster->adder_h->reset();
				}

				if($s_total > $this->reset_threshold) {
					$cluster->adder_s->reset();
				}*/
			}


			$object->log('total error: '.$total_error.' last: '.$last_total_error);
			$last_total_error = $total_error;
		/*}*/

			/*$this->perform($inputs, $outputs, $object->default_filter_size);*/
			$counter = $counter + 1;
		}
	}

	public $reset_threshold = 3;

	public function perform($input, $outputs=NULL, $filter_size=3, $for_print=true) {
		$iterator = new iterator();

		$result_set = false;

		if($outputs == NULL) {

			$result_set = true;

			$generator = new generator();

			$outputs = $generator->random_points($input->length, 1, 0);
		}

		$clusters = $this->clusters;

		$total_error_alt = 0;

		$iterator->iterate($input->length, function($x, $y) {
			$filter_parameter_inputs = [];

			$filter_iterator = new iterator();

			/*if(!$result_set) {

				$this->main_adder_h->perform_normalize();
				$this->main_adder_s->perform_normalize();
			}*/

			if(($x+$filter_size) < $input->length && ($y+$filter_size) < $input->length) {

				$filter_iterator->iterate($filter_size, function($x2, $y2) {
					/*$object->log($object->toJSON(['filter iteration' => $input[$y+$y2][$x+$x2]]));*/
					$filter_parameter_inputs[] = $input[$y+$y2][$x+$x2][0];
					return NULL;
				});

				$filter_parameter_outputs_h = [];
				$filter_parameter_outputs_s = [];

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

				$object->log('filter parameter inputs size: '.$filter_parameter_inputs->length);*/

				foreach($clusters as $cluster) {
					$filter_parameter_outputs_h[] = $cluster->adder_h->perform($filter_parameter_inputs);
					$filter_parameter_outputs_s[] = $cluster->adder_s->perform($filter_parameter_inputs);
				}

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

				if(!$result_set) {
					$main_error = 0;

					$main_error_h = $this->main_adder_h->get_error_alt($filter_parameter_outputs_h, $outputs[$y][$x][0][0]);
					$object->log('main error h: '.$main_error_h.' last h: ');

					/*$errors_h = $this->main_adder_h->error_list;
					$errors_h[] = $main_error_h;

					$object->log($object->toJSON($this->main_adder_h->error_list));*/
					$main_error_s = $this->main_adder_s->get_error_alt($filter_parameter_outputs_s, $outputs[$y][$x][0][1]);
					$object->log('main error s: '.$main_error_s);

					$total_error_alt = $total_error_alt + $main_error_h + $main_error_s;
					/*$errors_s = $this->main_adder_s->error_list;
					$errors_s[] = $main_error_s;
					$object->log($object->toJSON($this->main_adder_s->error_list));*/
				} else {

					$output_item = [
						$input[$y][$x][0]/*,
						$this->main_adder_h->perform($filter_parameter_outputs_h),
						$this->main_adder_s->perform($filter_parameter_outputs_s)*/
					];


					$output_item = $object->concat($output_item, $filter_parameter_inputs);
					$output_item = $object->concat($output_item, $filter_parameter_outputs_h);
					$output_item = $object->concat($output_item, $filter_parameter_outputs_s);

					/*if(!$for_print) {
					}*/

					/*$output_item[] = $input[$y][$x][0];
					$output_item[] = $input[$y][$x][0];*/

					$outputs[$y][$x] = $output_item;

					/*$object->log($object->toJSON($output_item));*/
				}
			}
			return NULL;
		});

		$object->log('total error alt: '.$total_error_alt);

		return $outputs;
	}
}


?>