/* Learning Net - shlomy boshy 031868912
 * Reinforcement Learning network simulation  
 */
package learnnet;
import java.util.*;

public class QROUTINGRouter implements Router {
   /** decides which of the neighbor 
   * nodes to send a packet through 
   */

  private static final double alpha=0.7; 
  /* learning rate - doesn't change-always learning (network can change) */
  
  public synchronized Node getBestRouting(lookupTable Q,Node sender,Node dest,Node RoutingNode){
     /** returns node to route through */
      
      Enumeration e= Q.getNeighbors();
      double Min = -1,val;
      Node node,MinNode = null;     
        
     /* find neighbor with smallest estimate */
     /* REMARK: neighbors with UNKNOWN_VALUE(=0) 
      * will have smaller estimates so exploration
      * is achieved at start.
      * (in current lookup-implementation BF estimate is used when unknown) 
      */
     
     if (RoutingNode.NT.lookupTableType.equals("ARRAY")) {     
      /* array gives more efficient estimate */
       node = Q.getMinNodeForDest(dest);
       if (Network.Debug_Routing)
          Network.debugPrint("Node "+RoutingNode+"QROUTING:Chosen route is"+node+"to dest"+dest);
       return node;
     }
     else  {/* HASHTABLE */                    
      while (e.hasMoreElements()) {
        node = (Node)e.nextElement();
        if (node == sender) continue; 
        val = Q.getValue(node,dest);               
        if (Network.Debug_Routing)
          Network.debugPrint("Node "+RoutingNode+":Choosing node to route to dest"+dest+":Neighbor "+node+" with value "+val);
        if ((Min == -1) || (val<Min)) {
            Min=val;
            MinNode=node; 
         }
        
      }
      if (Network.Debug_Routing)
               Network.debugPrint("Node "+RoutingNode+":Chosen route:node "+MinNode+" with value "+Min);      
      return MinNode;      
    }
  }
  
  public synchronized void updateFromReply(lookupTable Q,double reply,double transferTime,double queueTime,Node sender,Node dest,Node RoutingNode){
    /** performs update from reply */    
    double newEstimate = reply + transferTime + queueTime;
    double oldEstimate = Q.getValue(sender,dest);
    
    if (Network.Debug_Routing)
         Network.debugPrint("Node"+RoutingNode+":Performing update:reply="+reply+",transfer time="+transferTime+",queue time="+queueTime+",old estimate="+oldEstimate+",newEstimate=" + (oldEstimate + alpha*(newEstimate - oldEstimate)));            
      Q.setValue(sender,dest, oldEstimate + alpha*(newEstimate - oldEstimate));    
    if (Network.Debug_Routing)
         Network.debugPrint("Node "+RoutingNode+":New value of "+sender+" to dest "+dest+" is "+Q.getValue(sender,dest));
    
  }
  
}