package overlay;
import java.io.PrintStream;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import uk.ac.ic.doc.automed.DSRConfiguration;
import uk.ac.ic.doc.automed.p2p.overlay.OverlayController;
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;

/**
 * OverlayApplication.java<br><br>
 *
 * Shows how to construct a test application with several peers joining a
 * Chord-based overlay network
 *
 * @author Duc M Le  <a href="mailto:dmle@doc.ic.ac.uk"><i>dmle@doc.ic.ac.uk</i></a>
 * <br>Created on August 7, 2006
 * <br>Department of Computing, Imperial College
 */

public class OverlayApplication extends OverlayExample {
  
  private int debugSection = Debugger.DEBUG_P2P_OVERLAY;
  private int debugLevel = Debugger.DEBUG_LEVEL_STD;
  private PrintStream out = System.out;
  
  /**
   * Creates a new instance of OverlayExample
   */
  public OverlayApplication() throws Exception {
    //
  }

  /**
   * Default command-line options
   */
  public static Options getDefaultOptions() {
    Options opts = new Options();
    opts.addOption(OptionBuilder.withArgName("numHosts")
                    .hasArg()
                    .withDescription("number of virtual hosts to create. E.g.: -n 5")
                    .isRequired(true)
                    .create("n"));
    opts.addOption(OptionBuilder.withArgName("startNumber")
                    .hasArg()
                    .withDescription("starting host number")
                    .isRequired(false)
                    .create("s"));
    opts.addOption(OptionBuilder.withArgName("host:port")
                    .hasArgs()
                    .withDescription("join DHT with an existing host on the specified port. " +
                      "E.g.: -j host5:8805")
                      .isRequired(false)
                      .create("j"));
    opts.addOption(OptionBuilder.withArgName("m.n (...)")
                    .hasArg()
                    .withDescription("one or more set of debug options in format section.level (if more " +
                      "than one then must enclose inside double quotes). E.g.: -d \"9.8 20.5 21.1\"")
                      .isRequired(false)
                      .create("d"));    
    return opts;
  }
  
  public static void main(String[] args) throws Exception {
    
//    Debugger.setSectionDebugLevel(Debugger.DEBUG_HELLO, Debugger.DEBUG_LEVEL_ALL);
////    Debugger.setSectionDebugLevel(Debugger.DEBUG_DIRECTORY, Debugger.DEBUG_LEVEL_ERROR);
////    Debugger.setSectionDebugLevel(Debugger.DEBUG_P2P, Debugger.DEBUG_LEVEL_PACKET);
//    Debugger.setSectionDebugLevel(Debugger.DEBUG_P2P_OVERLAY, Debugger.DEBUG_LEVEL_STD);
//    Debugger.setSectionDebugLevel(Debugger.DEBUG_GENERAL, Debugger.DEBUG_LEVEL_STD);
//    Logger.setOutputHandler(new LogOutputHandler(LogOutputHandler.CONSOLE +
//      LogOutputHandler.FILE));
    
    Options opts = getDefaultOptions();
    CommandLineParser parser = new GnuParser();
    CommandLine cli = null;
    
    int numPeers = OverlayController.DEF_NUM_HOSTS;
    int startNum = 0;
    String hostPort = null;
    boolean withoutDSP = true;
    boolean joinDS = false;
    
    if (args == null || args.length < 1) {
      AutoMedUtils.printCmdUsage("OverlayApplication", opts);
      System.exit(0);
    } else {
      try {
        // parse the command line arguments
        cli = parser.parse( opts, args );
      } catch( ParseException exp ) {
        // oops, something went wrong
        System.err.println("Parsing failed.  Reason: " + exp.getMessage());
        System.exit(0);
      }
      
      if (!cli.hasOption("n")) {
        AutoMedUtils.printCmdUsage("OverlayApplication", opts);
        System.exit(0);
      }
      
      numPeers = Integer.parseInt(cli.getOptionValue("n"));
      
      if (cli.hasOption("s")) {
        startNum = Integer.parseInt(cli.getOptionValue("s"));
      }
      
      if (cli.hasOption("j")) {
        hostPort = cli.getOptionValue("j");
        if (hostPort != null && hostPort.length()==0)
          hostPort = null;
      }      
    }
    
    Debugger.setSectionDebugLevel(args);
    DSRConfiguration.setDefaultConfigFileName(args);
    
    Logger.setOutputHandler(new LogOutputHandler(LogOutputHandler.CONSOLE +
      LogOutputHandler.FILE));
    
    Peer.initOverlay(numPeers);
    
    OverlayApplication oex = null;
    do {
      
      if (oex != null && AutoMedUtils.dialogYesNo("Start a new set of peers ?", 0) == 1) {
        oex.finalize();        
        oex = new OverlayApplication();
      } else if (oex == null) {
        oex = new OverlayApplication();
      }

      // ask for the number of peers to initialise      
      oex.startPeers(numPeers, true, hostPort);
      
      if (AutoMedUtils.dialogYesNo("Display Overlay Network status ?", 0) == 1) {
        oex.displayOverlayStatus();
      }
      
      // prompt user for a peer
      int peerIndex  = oex.displayPeerList();
      
      // ask to put a number of test key, value pairs to network
      int numTestKeys = numPeers * 3;
      
      if (AutoMedUtils.dialogYesNo("Put "+(numTestKeys)+" test (key,value) pairs to network ?", 0) == 1) {
        for (int i = 0; i < numTestKeys; i++) {
          String tk = "KEY_"+System.currentTimeMillis();
          String tv = "VAL_"+System.currentTimeMillis();
          int ttl = 60 * 60 * 1000; // 1h
          
          OverlayController.waitBeforeAccess();
          oex.put(peerIndex, tk, tv, ttl);
        }
      }
            
      if (AutoMedUtils.dialogYesNo("Peer "+peerIndex+": display overlay status ?", 1) == 1) {
        oex.displayOverlayStatus(peerIndex);
      }
      
//      if (AutoMedUtils.dialogYesNo("Peer "+peerIndex+": get local keys ?", 1) == 1) {
//        oex.displayLocalKeys(peerIndex);
//      }
//      
//      if (AutoMedUtils.dialogYesNo("Peer "+peerIndex+": get ALL local values ?", 1) == 1) {
//        oex.displayLocalValues(peerIndex);
//      }
      
      if (AutoMedUtils.dialogYesNo("Peer "+peerIndex+": get values for a key from the network ?", 1) == 1) {
        String key = AutoMedUtils.getCmdLineInput("Enter key: ");
        oex.get(peerIndex, key);
      }            
    } while (AutoMedUtils.dialogYesNo("Run again?", 0) == 1);
    
    AutoMedUtils.banner("~END~");
    System.exit(0);
  }
}
