package fnnc.algo;

import fnnc.model.DistanceCalculator;
import fnnc.model.DistanceObjectPair;

import java.lang.Comparable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;

public class OrchardsAlgorithm<T> extends FastNearestNeighbourClassificator<T, Double> {

  private HashMap<Integer, LinkedList<DistanceObjectPair<Double, Integer>>> orderedLists;
  private HashMap<Integer, T> indexedObjects;

  /**
   * Creates an OrchardsAlgorithm object.
   */
  public OrchardsAlgorithm(
      DistanceCalculator<T, Double> distanceCalculator
  ) {
    super(distanceCalculator);
  }

  /**
   * Prepares search for nearest neighboor.
   */
  public void preProcessing(Collection<T> objectCollection) {
    super.preProcessing(objectCollection);
    this.orderedLists =
        new HashMap<Integer, LinkedList<DistanceObjectPair<Double, Integer>>>(
          objectCollection.size()
        );
    this.indexedObjects =
        new HashMap<Integer, T>(objectCollection.size());
    int counter = 0;
    for (T curr : this.objectCollection) {
      LinkedList<DistanceObjectPair<Double, Integer>> itemList =
          new LinkedList<DistanceObjectPair<Double, Integer>>();
      int innerCounter = 0;
      for (T item : this.objectCollection) {
        if (curr != item) {
          double distance = this.distanceCalculator.calculateDistance(curr, item);
          itemList.add(new DistanceObjectPair<Double, Integer>(distance, innerCounter));
        }
        innerCounter++;
      }
      Collections.sort(itemList);
      this.orderedLists.put(counter, itemList);
      this.indexedObjects.put(counter, curr);
      counter++;
    }
  }

  /**
   * Calculates the nearest neighbour of the given query object.
   */
  public T calculateNearestNeighbour(T queryObject) {
    Random random = new Random();
    int currentIndex = random.nextInt(this.objectCollection.size());
    T currentObject = this.indexedObjects.get(currentIndex);
    double currentDistanceToQuery = this.distanceCalculator
        .calculateDistance(currentObject, queryObject);
    LinkedList<DistanceObjectPair<Double, Integer>> currentList =
        this.orderedLists.get(currentIndex);
    Iterator<DistanceObjectPair<Double, Integer>> iterator = currentList.iterator();
    while (iterator.hasNext()) {
      DistanceObjectPair<Double, Integer> tempDistObjPair = iterator.next();
      T tempObject = this.indexedObjects.get(tempDistObjPair.getObject());
      if (tempDistObjPair.getDistance() > 2 * currentDistanceToQuery) {
        break;
      }
      double tempDistanceToQuery = this.distanceCalculator
          .calculateDistance(tempObject, queryObject);
      if (tempDistanceToQuery < currentDistanceToQuery) {
        currentDistanceToQuery = tempDistanceToQuery;
        currentIndex = tempDistObjPair.getObject();
        currentObject = tempObject;
        currentList = this.orderedLists.get(currentIndex);
        iterator = currentList.iterator();
      }
    }
    return currentObject;
  }
}

@@ -1275,24 +1275,298 @@
 nteger%3E%3E();%0A
+      this.orderedLists.put(counter, itemList);%0A      this.indexedObjects.put(counter, curr);%0A      counter++;%0A    %7D%0A    counter = 0;%0A    for (T curr : this.objectCollection) %7B%0A      LinkedList%3CDistanceObjectPair%3CDouble, Integer%3E%3E itemList = this.orderedLists.get(counter);%0A
       int in
@@ -1647,9 +1647,9 @@
 urr 
-!
+=
 = it
@@ -1652,24 +1652,49 @@
 = item) %7B%0A  
+        break;%0A        %7D%0A
         doub
@@ -1762,18 +1762,16 @@
  item);%0A
-  
         
@@ -1861,185 +1861,252 @@
     
-%7D%0A        innerCounter++;%0A      %7D%0A      Collections.sort(itemList);%0A      this.orderedLists.put(
+this.orderedLists.get(innerCounter).add(new DistanceObjectPair%3CDouble, Integer%3E(distance, counter));%0A        innerCounter++;%0A      %7D%0A      counter++;%0A    %7D%0A    for (int i = 0; i %3C 
 counter
-, itemList);%0A      this.indexedObjects.put(counter, curr);%0A      counter++
+; i++) %7B%0A      Collections.sort(this.orderedLists.get(i))
 ;%0A  

improve orchards preprocessing