package test.brn.gateway;

import jist.runtime.Util;
import jist.swans.Constants;
import jist.swans.Node;
import jist.swans.field.Fading;
import jist.swans.field.Field;
import jist.swans.field.Mobility;
import jist.swans.field.PathLoss;
import jist.swans.field.Spatial;
import jist.swans.misc.Location;
import jist.swans.radio.RadioNoise;
import jist.swans.trans.AbstractTrans;
import brn.sim.AbstractDriver;
import brn.sim.AbstractParams;
import brn.sim.builder.Builder;
import brn.sim.builder.BuilderException;
import click.runtime.ClickAdapter;
import click.runtime.ClickException;
import click.sim.builder.ClickBuilder;
import click.sim.builder.ClickBuilder.NetParams;
import click.swans.net.ClickRouter;

public class GatewaySim extends AbstractDriver {
  
  protected Node superNode = null;

  /*
   * (non-Javadoc)
   * @see brn.sim.AbstractDriver#installHandlers(brn.sim.AbstractParams)
   */
  protected void installHandlers(AbstractParams options) throws Exception {
    super.installHandlers(options);

    // Use gui
    if (options.node.net instanceof ClickBuilder.NetParams) {
      NetParams params = (NetParams) options.node.net;
      if (params.clickGui)
        ClickAdapter.useGui();
    }
  }
  
  /*
   * (non-Javadoc)
   * @see brn.sim.AbstractDriver#installBuilders(brn.sim.AbstractParams)
   */
  protected void installBuilders(AbstractParams options) {
    super.installBuilders(options);
    
    builderProvider.addBuilder(new ClickBuilder.Mac());
    builderProvider.addBuilder(new ClickBuilder.Net());
    builderProvider.addBuilder(new ClickBuilder.HostNet());
  }

  /*
   * (non-Javadoc)
   * @see brn.sim.AbstractDriver#setupApplication(brn.sim.AbstractParams, int, jist.swans.Node)
   */
  protected void setupApplication(AbstractParams opts, int nodeId, Node node) throws BuilderException {
    super.setupApplication(opts, nodeId, node);
    GatewayParams params = (GatewayParams)opts;
    
    //    transport
    if (null != params.transParams) {
      Builder builder = builderProvider.getBuilder(params.transParams);
      AbstractTrans trans = (AbstractTrans) builder.build(params.transParams, node);
      builderProvider.addHookUp(builder, params.transParams, node, trans);
      node.addTransport(trans);
    }

    /*
    // app
    if (null != params.trafficParams) {
      Builder builder = builderProvider.getBuilder(params.trafficParams);
      Object ret = builder.build(params.trafficParams, node);
      builderProvider.addHookUp(builder, params.trafficParams, node, ret);
    }
    */

    // flow
    if (null != params.flowParams) {
      Builder builder = builderProvider.getBuilder(params.flowParams);
      Object ret = builder.build(params.flowParams, node);
      builderProvider.addHookUp(builder, params.flowParams, node, ret);
    }
  }

  /* (non-Javadoc)
   * @see brn.sim.AbstractDriver#buildAdditionNodes(brn.sim.AbstractParams, int, jist.swans.field.Field)
   */
  protected void buildAdditionNodes(AbstractParams params, int nextNodeId,
      Field field) throws BuilderException {
    GatewayParams opts = (GatewayParams) params;

    // build clients
    for (int i = nextNodeId; i < nextNodeId + opts.clients; i++) {
      Node node = buildNode(opts.clientNode, i, field);
      nodes.add(node);

      // trans + app
      setupApplication(opts, i, node);
    }
    
    // build super node
    {
      Location loc = new Location.Location2D(100, 100);
      Field fieldEth0 = new Field(new Spatial.LinearList(loc), new Fading.None(), 
          new PathLoss.None(), new Mobility.Static(), 
          Constants.PROPAGATION_LIMIT_DEFAULT);

      Util.assertion(nextNodeId < opts.internetNodeId);
      Node node = buildNode(opts.internetNode, opts.internetNodeId, fieldEth0);
      nodes.add(node);
      superNode = node;

      // trans + app
      setupApplication(opts, opts.internetNodeId, node);
    }
  }

  /*
   * (non-Javadoc)
   * @see brn.sim.AbstractDriver#postHookUp(brn.sim.AbstractParams)
   */
  protected void postHookUp(AbstractParams opts) throws BuilderException {
    super.postHookUp(opts);

    Field wire = superNode.getField(0);

    try {
      Node node = (Node) nodes.get(0);
      RadioNoise radio = (RadioNoise) node.getRadio(1);
      
      ((Field)node.getField(1)).delRadio(radio.getRadioInfo().getIdInteger());
      wire.addRadio(radio.getRadioInfo(), radio.getProxy(), 
          new Location.Location2D(10, 10));
      radio.setFieldEntity(wire.getProxy());
      
      ((ClickRouter) node.getNet()).writeHandler("meshNode/services/gw/gateway", 
          "add_gateway", "255 1.1.1.1 false");
    } catch (ClickException e) {
      throw new BuilderException(e);
    }
  }

  /*
   * (non-Javadoc)
   * @see brn.sim.AbstractDriver#runLocal()
   */
  protected void runLocal() {
    try {
      GatewayParams params = GatewayParams.defaultParams(new GatewayParams());
      //params = params.setParamsTest();
      run(params);
    } catch (Throwable e) {
      e.printStackTrace();
      System.exit(1);
    }
  }
  
  public static void main(String[] args) throws Throwable {
    GatewaySim test = new GatewaySim();
    test.run(args);
  }

}
