package network;

import java.util.Enumeration;
import general.Utility;
import general.Set;
import general.Sortable;

public class RemoteTrafficConstraint {

  /**
   * sort the switches by their distance to swt, return a set of switches with distance
   * greater than r. If the number of neighbors(switches with distances smaller than r) is 
   * smaller than minN, change it to minN by taking away a few switches from the remote set,
   * if the number of neighbor is greater than maxN, put the extras into remote set.
   * make sure minN and maxN are in proper ranger, i.e. not negative number, 
   * not exceeding switches.size().
   */
  public static Set remoteSwitches(Switch swt, Set switches, double r,
				   int minN, int maxN) {
    SortableSwitch[] allSwitches = new SortableSwitch[switches.size()];
    Enumeration e = switches.elements();
    int i = 0;
    while (e.hasMoreElements()) {
      Switch s = (Switch)e.nextElement();
      double dist = Switch.distance(swt, s);
      allSwitches[i] = new SortableSwitch(s, dist);
      i++;
    }
    // sort the switches by their distances to swt, in ascending order.
    Utility.QuickSort(allSwitches, 0, switches.size() -1);
    Set remotes = null;
    try {
      remotes = new Set(Class.forName("network.Switch"));
    }
    catch (ClassNotFoundException err) {
      System.out.println("Network.RemoteTrafficConstraint: " + err.getMessage());
    }

    // find the nearest switch belong to remote set
    int startIndex = -1;
    if (allSwitches[minN + 1].getDoubleValue() >= r)
      startIndex = minN + 1;
    else if (allSwitches[maxN + 1].getDoubleValue() <= r)
      startIndex = maxN + 1;
    else {
      startIndex = minN + 1;
      while (allSwitches[startIndex].getDoubleValue() < r) ++startIndex;
    }
    
    for (i = startIndex; i < allSwitches.length; i++) {
      Switch theSwitch = allSwitches[i].getSwitch();
      remotes.put(theSwitch.getName(), theSwitch);
    }
    return remotes;
  }

}

/** a wrapper class to associate a double with a Switch, so it becomes sortable,
 *  the val could be distance to another switch.
 */
class SortableSwitch implements Sortable {
  public SortableSwitch(Switch s, double val) {
    this.swt = s;
    this.val = val;
  }
  public Switch getSwitch() {
    return this.swt;
  }
  public double getDoubleValue() {
    return val;
  }
  Switch swt;
  double val;
}
