package rodex;

import ow.id.ID;
import uk.ac.ic.doc.automed.p2p.overlay.OverlayController;
import uk.ac.ic.doc.automed.p2p.overlay.OverlayToolKit;
import uk.ac.ic.doc.automed.util.Debugger;
import uk.ac.ic.doc.automed.util.LogOutputHandler;
import uk.ac.ic.doc.automed.util.Logger;
import uk.ac.ic.doc.rodex.p2p.Peer;
import utils.AutoMedUtils;

/**
 * EnhancedDON.java
 *
 * This version of the DON application supports more features than the {@link RodexDON}:
 * <ol>
 *  <li>Supports range guards on a set of index attributes, not just the primary key
 *  <li>Does NOT require that the number of peers is scaled with the size index attribute's domain.
 *      A peer's ID is hashed randomly.
 * </ol>
 *
 * @author Duc M Le  <a href="mailto:dmle@doc.ic.ac.uk"><i>dmle@doc.ic.ac.uk</i></a>
 * Created on 21 August 2006
 * Department of Computing, Imperial College
 */

public class EnhancedDON extends RodexDON {
  
  /**
   * Creates a new instance of EnhancedDON
   */
  public EnhancedDON() throws Exception {
    super();
  }
  
  /**
   * Use this method to calculate a hashed-key for a numeric range of an index
   * attribute. 
   */
  public static ID getHashKeyForRange(String field, int rgMin, int rgMax) {
    // this method calculates hashed-key from both lower and upper lower bounds of the range
    String keyStr = rgMin + "<="+field+"<="+rgMax;
    ID hid = OverlayToolKit.createIDFromString(keyStr);
    return hid;
  }
  
  /**
   * Override parent's method to distribute ranges for both id and yob
   */
  public void distributeTableData(int peerIndex) throws Exception {
    distributeTableDataByAttribute(peerIndex, "yob");
    distributeTableDataByAttribute(peerIndex, "id");
  }  
    
  /**
   * Basically return the pre-configured set of range guards for a table column
   */
  public int[][] getRangeGuardDef(String field) {
    if (field.equalsIgnoreCase("id")) {
      return rgID;
    } else if (field.equalsIgnoreCase("yob")) {
      return rgYOB;
    }
    // add more cases here...
    
    return null;
  }  
  
  public void finalize() {
    super.finalize();
  }
  
  public static void main(String[] args) throws Exception {
//    Debugger.setSectionDebugLevel(Debugger.DEBUG_HELLO, Debugger.DEBUG_LEVEL_ALL);
//    Debugger.setSectionDebugLevel(Debugger.DEBUG_P2P, Debugger.DEBUG_LEVEL_STD);
//    Debugger.setSectionDebugLevel(Debugger.DEBUG_P2P_OVERLAY, Debugger.DEBUG_LEVEL_DETAILED);
//    Debugger.setSectionDebugLevel(Debugger.DEBUG_QUERY, Debugger.DEBUG_LEVEL_ALL);
//    Debugger.setSectionDebugLevel(Debugger.DEBUG_QUERY_REWRITE, Debugger.DEBUG_LEVEL_INFO);
//    Debugger.setSectionDebugLevel(Debugger.DEBUG_GENERAL, Debugger.DEBUG_LEVEL_INFO);
    // e.g. -d "9.8 20.5 21.1"
    Debugger.setSectionDebugLevel(args);
    
    Logger.setOutputHandler(new LogOutputHandler(LogOutputHandler.CONSOLE +
      LogOutputHandler.FILE));
    
    int numPeers = 3; //RodexDON.getRequiredNumPeers();
//    int numPeers = OverlayController.DEF_NUM_HOSTS;
    
    Peer.initOverlay(numPeers);
    
    EnhancedDON oex = null;
    boolean withSuperPeer = true;
    
    do {
      if (oex != null && AutoMedUtils.dialogYesNo("Start a new set of peers ?", 0) == 1) {
        oex.finalize();
        try {Thread.sleep(5 * 1000);} catch (InterruptedException ie) {}
        oex = new EnhancedDON();
        oex.startPeers(numPeers, true);
//        oex.startAutoMedPeers(numPeers, withSuperPeer);
      } else if (oex == null) {
        oex = new EnhancedDON();
        oex.startPeers(numPeers, true);
//        oex.startAutoMedPeers(numPeers, withSuperPeer);
      }
      
      if (AutoMedUtils.dialogYesNo("Display Overlay Network status ?", 0) == 1) {
        oex.displayOverlayStatus();
      }
      
      // prompt user for a peer
      int peerIndex  = oex.displayPeerList();
      
      // Publish person table data to the network according to a given scheme
      if (AutoMedUtils.dialogYesNo("Distribute person table data to network ?", 1) == 1) {
        oex.distributeTableData(peerIndex);
      }
      
      if (AutoMedUtils.dialogYesNo("Peer "+peerIndex+": display overlay status ?", 1) == 1) {
        oex.displayOverlayStatus(peerIndex);
      }
      
      // try query objects using exact match of record id
      if (AutoMedUtils.dialogYesNo("Peer "+peerIndex+": get values for a key from the network ?", 1) == 1) {
        oex.getValuesForNumericKey(peerIndex);
      }
      
      while (AutoMedUtils.dialogYesNo("Peer "+peerIndex+": try another key ?", 1) == 1) {
        oex.getValuesForNumericKey(peerIndex);
      }
      
      // try query objects using query
      while (AutoMedUtils.dialogYesNo("Peer "+peerIndex+": query object ?", 1) == 1) {
        oex.getValuesFromQuery(peerIndex);
      }
      
    } while (AutoMedUtils.dialogYesNo("Run again ?", 0) == 1);
    
    AutoMedUtils.banner("~END~");
    System.exit(0);
  }  
}
