<?

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

		$ireator->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]];
		});

		$perform_error = 0;

		while($counter < $iteration_count) {

			$total_error = 0;

			foreach($this->clusters as $cluster) {
				
				foreach($cluster['vectors'] as $vector) {
					$vector = [...$vector];

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

					$input = $vector;

					$total_error = $total_error + $cluster->adder_h->get_error_alt($input, $hs[0]);	
					$total_error = $total_error + $cluster->adder_s->get_error_alt($input, $hs[1]);
				}
			}
			$object->log('total error: '.$total_error);
			$counter = $counter + 1;

			$perform_error = $this->perform($inputs, $outputs, 3);

			$object->log('perform error: '.$perform_error);
		}
	}

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

		$outputs_was_null = false;

		if($outputs == NULL) {

			$outputs_was_null = true;

			$generator = new generator();

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

		$clusters = $this->clusters;

		$set_total_error = 0;

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

			$filter_iterator = new iterator();

			if(($x+3) < $input->length && ($y+3) < $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));*/

				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(!$outputs_was_null) {
					$main_error = 0;

					$main_error_h = $main_error + $this->main_adder_h->get_error_alt($filter_parameter_outputs_h, $outputs[$y][$x][0][0]);
					$object->log('main error h: '.$main_error_h);
					$main_error_s = $main_error + $this->main_adder_s->get_error_alt($filter_parameter_outputs_s, $outputs[$y][$x][0][1]);
					$object->log('main error s: '.$main_error_s);

					$set_total_error = $main_error_h + $main_error_s;
				} else {
					$outputs[$y][$x] = [
						$input[$y][$x],
						$this->main_adder_h->perform($filter_parameter_outputs),
						$this->main_adder_s->perform($filter_parameter_outputs)
					];

					$object->log($object->toJSON($outputs));
				}
			}
			return NULL;
		});

		if($outputs_was_null) {
			return $set_total_error;
		}


		return $outputs;
	}
}


?>