package test.sim.scenario;

import jist.swans.Constants;
import jist.runtime.JistAPI;
import brn.sim.AbstractParams;
import brn.sim.scenario.mchannel.McExORParams;
import brn.sim.builder.BuilderException;
import brn.sim.builder.FieldBuilder;
import brn.sim.builder.MacBuilder;
import brn.sim.builder.PathLossBuilder;
import brn.sim.builder.RouteBuilder;
import brn.analysis.mcexor.McExOREval;
import brn.analysis.mcexor.TestConstants;
import brn.analysis.mcexor.ImgCandidateSet;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.io.File;
import java.io.FileWriter;
import java.util.*;

/**
 * Tests the udp trhoughput of McExOR with RTS/CTS.
 */
public class EvalMcExORCSetBRateRtsCtsMChannelSim extends AbstractEvalMcExOR {

  protected String testRtsCtsRunParamAsString;
  protected int channelNumber;

  protected String getFileName() {
    return "test_cs_rate_rts_mch_" + channelNumber  + "_" + exponent + "_"
              + stdDeviation + "_" + coherenceTime + "_" + fading + "_" + constantDataBitRate / Constants.BANDWIDTH_1Mbps
              + "_" + constantCtrlBitRate / Constants.BANDWIDTH_1Mbps + "_" + testRtsCtsRunParamAsString +  ".dat";
  }

  /**
   * Called after successful hookup. Overwrite if you want to do some
   * custom initialization.
   *
   * @param opts
   * @throws brn.sim.builder.BuilderException
   */
  protected void postHookUp(AbstractParams opts) throws BuilderException {

    McExORParams params = (McExORParams)opts;

    seed = params.seed;
    exponent = ((PathLossBuilder.DistShadowingParams)
        ((FieldBuilder.FieldParams)params.field).pathloss).exponent;
    stdDeviation = ((PathLossBuilder.DistShadowingParams)
        ((FieldBuilder.FieldParams)params.field).pathloss).stdDeviation;
    coherenceTime = ((PathLossBuilder.DistShadowingParams)
        ((FieldBuilder.FieldParams)params.field).pathloss).coherenceTime;
    fading = getFadingParameter(((FieldBuilder.FieldParams)params.field).fading);

    constantDataBitRate = ((MacBuilder.MCExORParams)params.node.mac).constantDataBitRate;
    constantCtrlBitRate = ((MacBuilder.MCExORParams)params.node.mac).constantCtrlBitRate;

    eval = new McExOREval(nodes, params.appParams.serverAddr.getId());
    eval.registerHandlers();

    testRunParamAsString = setTestRunParamString(((RouteBuilder.MCExORParams)params.node.route).testRunOpts);

    testRtsCtsRunParamAsString = setTestRtsRunParamString(((RouteBuilder.MCExORParams)params.node.route).testRunOpts2);

    channelNumber = ((FieldBuilder.FieldParams)params.field).channelNumber;

    JistAPI.runAt(new Runnable() {
      public void run() {
        try {

          int sendData  = eval.getSendData().size();
          int retryData = eval.getRetryPackets().size();
          int notDetectedDuplicates = eval.getNotDetectedDuplicates().size();
          long cumDist  = eval.getCumulatedDistances();

          // write the stuff in DB
          Connection conn = null;

          try {
             String userName = "userdb";
             String password = "userdb";
             String url = "jdbc:mysql://localhost:3306/sim";
             Class.forName ("com.mysql.jdbc.Driver").newInstance ();
             conn = DriverManager.getConnection (url, userName, password);
             System.out.println ("Database connection established");

             PreparedStatement s = conn.prepareStatement (
                 "INSERT INTO EVAL_MCEXOR (seed, spec, rtsspec, channel, exponent, stdDeviation, coherenceTime, fading, drate, crate,"
                 + " send, retry, dupl, dist) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)");

             int idx = 1;

             s.setInt(idx++,    seed);
             s.setString(idx++, testRunParamAsString);
             s.setString(idx++, testRtsCtsRunParamAsString);
             s.setInt(idx++,    channelNumber);
             s.setDouble(idx++, exponent);
             s.setDouble(idx++, stdDeviation);
             s.setLong(idx++,   coherenceTime);
             s.setInt(idx++,    fading);
             s.setInt(idx++,    constantDataBitRate / Constants.BANDWIDTH_1Mbps);
             s.setInt(idx++,    constantCtrlBitRate / Constants.BANDWIDTH_1Mbps);
             s.setInt(idx++,    sendData);
             s.setInt(idx++,    retryData);
             s.setInt(idx++,    notDetectedDuplicates);
             s.setLong(idx++,   cumDist);

             s.executeUpdate ();

             s.close ();
          } catch (Exception e) {
           e.printStackTrace();
          } finally {
             if (conn != null) {
                 try {
                     conn.close ();
                     System.out.println ("Database connection terminated");
                 } catch (Exception e) { /* ignore close errors */ }
             }
          }

          File f = new File(getFileName());
          FileWriter fw = new FileWriter(f, true);

          StringBuffer content = new StringBuffer();
          content.append(testRunParamAsString).append("\t");
          content.append(testRtsCtsRunParamAsString).append("\t");
          content.append(channelNumber).append("\t");
          content.append(sendData).append("\t");
          content.append(retryData).append("\t");
          content.append(notDetectedDuplicates).append("\t");
          content.append(cumDist).append("\t");
          content.append("\n");

          fw.write(content.toString());
          fw.flush();
          fw.close();

          System.out.println("seed                = " + seed);
          System.out.println("spec                = " + testRunParamAsString);
          System.out.println("rtsspec             = " + testRtsCtsRunParamAsString);
          System.out.println("channels            = " + channelNumber);
          System.out.println("data rate           = " + constantDataBitRate);
          System.out.println("ctrl rate           = " + constantCtrlBitRate);
          System.out.println("sendPackets.size    = " + sendData);
          System.out.println("retryPackets.size   = " + retryData);
          System.out.println("duplPackets.size    = " + notDetectedDuplicates);
          System.out.println("mean distance gain  = " + cumDist);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }, JistAPI.END);
  }


  public static void main(String[] args) {
    EvalMcExORCSetBRateRtsCtsMChannelSim test = new EvalMcExORCSetBRateRtsCtsMChannelSim();

    if (args.length < 1) {
      System.out.println("args required: seed KEY VALUE");
      return;
    } else {
      System.out.println("called with: " + args[0]);
    }

    try {
      StringTokenizer tk = new StringTokenizer(args[0]);

      /**
       * seed, key, idx, exponent, stdDeviation, coherenceTime, fading, dRate, cRate
       */
      // old: evalCandidateSetSelectionBitRateRtsCts
      McExORParams options = McExORParams.evalCandidateSetSelectionBitRateRtsCtsMChannel(
          new Integer(tk.nextToken()), new Integer(tk.nextToken()), new Integer(tk.nextToken()),
          new Integer(tk.nextToken()), new Integer(tk.nextToken()), new Integer(tk.nextToken()),
          new Integer(tk.nextToken()), new Integer(tk.nextToken()), new Integer(tk.nextToken()),
          new Integer(tk.nextToken()), new Integer(tk.nextToken()));

      test.run(options);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
}
