<?

class mapper {
	public $result_parameter_index = 1;

	public $mapped;

	public function __construct($mapped_set, $filter_size) {
		$this->mapped = [];

		foreach($mapped_set as $mapped) {
			$field = new field($mapped->length, $mapped);

			$set_mapped = $this->mapped;
			
			$self = $this;

			$iterator = new iterator();

			$iterator->iterate($mapped->length, function($x, $y) {
				$slice = $field->get_cut($filter_size, $x, $y);

				if($slice->length > 0) {


					$iterator_slice = new iterator();


					$mapped_item = [];


					$mapped_item[] = $slice[0][0][1];
					$mapped_item[] = $slice[0][0][2];

					$iterator_slice->iterate($filter_size, function($x, $y) {
						/*$mapped_item[] = ($x - 1);
						$mapped_item[] = ($y - 1);*/
						$mapped_item[] = $slice[$y][$x][0];


						/*$mapped_item[] = $slice[$y][$x][1];
						$mapped_item[] = $slice[$y][$x][2];*/


						$set_mapped[] = $mapped_item;

						return NULL;
					});



				}

				return NULL;
			});
		}
		$object->log('map len: '.$set_mapped->length);
	}

	private $distances = [];

	private $items;

	public function update_range_item($range_item, $vector) {
		$vectors = $range_item['vectors'];


		$m_vector = new m_vector();

		$median = $range_item['range'];

		$median = $m_vector->stretch_vector($median, $vectors->length);

		$vectors[] = $vector;

		$median = $m_vector->add_vector($median, $vector);

		/*foreach($vectors as $item_vector) {
			if($median === NULL) {
				$median = [...$item_vector];
			} else {
				$median = $m_vector->add_vector($median, $item_vector);
			}
		}*/



		$median = $m_vector->stretch_vector($median, (1/$vectors->length));

		$range_item['range'] = $median; 
	}

	public function get_clusters_alt() {
		$ranges_items = [];

		$vectors = [...$this->mapped];

		$vectors = $object->array_unique($vectors);

		$vectors = $object->randomize_list($vectors);

		$error_margin = 35/100; /*15*/




		$m_vector = new m_vector();

		$object->log('vectors len: '.$vectors->length);

		foreach($vectors as $vector_key => $vector) {
			$object->log('iterate vector: '.$vector_key);
			$object->log('vectors len: '.$vectors->length);
			$object->log($ranges_items->length);
			if($ranges_items->length == 0) {
				$object->log('add range item');
				$ranges_items[] = [
					'range' => [...$vector],
					'vectors' => [$vector]
				];
			} else {
				$min_distance = (-1);
				$min_distance_value = (-1);
				foreach($ranges_items as $key => $range_item) {
					$object->log($object->toJSON($range_item['range']));
					$object->log($object->toJSON($vector));
					$distance = $m_vector->length_value($range_item['range'], $vector);
					$object->log('distance: '.$distance.' : '.$error_margin);
					if($distance < $error_margin) {
						if($min_distance == (-1) || $distance < $min_distance_value) {
							$min_distance = $key;
							$min_distance_value = $distance;
						}
					}
				}
				$object->log('min distance value: '.$min_distance_value);
				$object->log('min distance: '.$min_distance);

				if($min_distance == (-1)) {
					$object->log('add range item');
					$ranges_items[] = [
						'range' => [...$vector],
						'vectors' => [$vector]
					];
				} else {
					$object->log('update range item');
					$this->update_range_item($ranges_items[$min_distance], $vector);
				}
			}
		}

		$object->log('ranges: '.$ranges_items->length);

		return $ranges_items;
	}

	public function build_clusters_depr($ranges) {
		$built_clusters = [];

		$generator = new generator();

		$set_points = $generator->random_points($set_size, 1, 0);

		$set_size = $object->default_filter_size;

		foreach($ranges as $range_item) {

			foreach($range_item['vectors'] as $vector) {
				$y = $vector[1];
				$x = $vector[0];

				/*$set_vector = ['original_input' => $vector[2], 'target' => [$vector[3], $vector[4]]];*/
				/*$set_vector = ['l' => $vector[2], 'hs' => [$vector[3], $vector[4]]];*/

				$l = $object->color_to_byte($vector[2]);

				$h = $object->color_to_byte($vector[3]);
				$s = $object->color_to_byte($vector[4]);
	/*
		targetid getur verid eitt gildi par (h,s) eða 9x2 gildi ?....

		það þyrfti þá að hafa 9 filtera ?

	*/



				$set_points_values = $set_points[$y][$x];
				if(!$object->isset($set_points_values['l_index'])) {
					$set_points_values['l_index'] = $object->create();
				}

				$set_pair = [$h, $s];

				/*if($object->isset($set_points_values['l_index'][$l])) {
					$object->log('duplicate index item');
					if($set_points_values['l_index'][$l] != $set_pair) {
						$object->log('different values');
						$object->log($object->toJSON([$set_pair, $set_points_values['l_index'][$l]]));
					}
				} else {*/
				if(!$object->isset($set_points_values['l_index'][$l])) {
					$set_points_values['l_index'][$l] = [];
				}
				$l_index = $set_points_values['l_index'][$l];
				if($object->index_of($l_index, $set_pair) == (-1)) {
					$l_index[] = $set_pair;
				}
				$object->log($object->toJSON($l_index));
				/*}*/
			}

			/*$built_clusters[] = $set_points;*/
		}


		/*$object->log($object->toJSON($object->keys($set_points[0][0])));
		$object->log($object->toJSON($object->values($set_points[0][0])));*/

		return $set_points;
	}

	public function get_clusters() {
		$this->items = [];
		foreach($this->mapped as $vector) {
			$this->items[] = [
				'vector' => $vector,
				'distances' => []
			];
		}

		$m_vector = new m_vector();

		foreach($this->items as $point_item) {
			$distances = [];

			$median = 0;

			foreach($this->mapped as $point_compare) {
				$distance = $m_vector->length_value($point_item['vector'], $point_compare);
				$distances[] = $distance;
				$median = $median + $distance;
			}

			$object->sort($distances, function($a, $b) {
				if($a > $b) {
					return 1;
				} else if($a == $b) {
					return 0;
				}
				return (-1);
			});

			$point_item['median'] = $median / $this->items->length;

			$point_item['distances'] = $distances;

			$point_item['mid_point'] = $point_item['median'] / 2;

			$set_distances = [...$distances];

			$set_distances = $object->splice($set_distances, 0, $math->floor($this->items->length / 2));

			$set_distances_median = 0;

			foreach($set_distances as $set_distance) {
				$set_distances_median = $set_distances_median + $set_distance;
			}

			$set_distances_median = $set_distances_median / $set_distances->length;

			$count_mid_point = 0;

			foreach($distances as $distance) {
				if($distance < $point_item['mid_point']) {
					$count_mid_point = $count_mid_point + 1;
				}
			}

			$point_item['count_mid_point'] = $count_mid_point;
			$point_item['set_distances_median'] = $set_distances_median;

		}

		$items = [...$this->items];

		$object->sort($items, function($a, $b) {
			if($a['set_distances_median'] < $b['set_distances_median']) {
				return 1;
			} else if($a['set_distances_median'] == $b['set_distances_median']) {
				return 0;
			}
			return (-1);
		});


		$clusters = [];

		while($items->length > 0) {

			$item = $object->splice($items, 0, 1)[0];

			$cluster = [
				'items' => [$item]
			];

			$count_mid_point = $item['count_mid_point'];

			$set_items = $cluster['items'];

			$to_remove = [];

			foreach($items as $item) {
				if($m_vector->length_value($item['vector'], $item['vector']) < $count_mid_point) {
					$to_remove[] = $item;
				}
			}

			foreach($to_remove as $item) {
				$index = $object->index_of($items, $item);
				if($index != (-1)) {
					$set_items[] = $object->splice($items, $index, 1)[0];
				}
			}
		}

		$todo = 'maximize distance between clusters and minimize distance within cluster';

		$object->log('clusters len: '.$clusters->length);

		foreach($clusters as $cluster) {
			$avg_distance = 0;
			$avg_mid_point = NULL;
			foreach($cluster['items'] as $item) {
				if($avg_mid_point == NULL) {
					$avg_mid_point = [...$item['vector']];
				} else {
					$avg_mid_point = $m_vector->add_vector($avg_mid_point, [...$item['vector']]);
				}
			}

			if($avg_mid_point != NULL) {
				$avg_mid_point = $m_vector->stretch_vector($avg_mid_point, (1/$cluster['items']->length));
			}

			$cluster['avg_mid_point'] = $avg_mid_point;

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



		/*foreach($clusters as $cluster) {
			foreach($clusters as $cluster_compare) {

			}
		}*/


		/*foreach($this->items as $item) {
			foreach($this->items as $item_compare) {
				if($object->index_of($item['distances'], $item_compare) == (-1)) {
					$item
				}
			}
		}*/
	}
}

?>