package brn.sim.builder;

import brn.swans.app.rtp.RtpApplication;
import jist.swans.Constants;
import jist.swans.Node;
import jist.swans.misc.Util;
import jist.swans.net.NetAddress;
import jist.swans.trans.TransUdp;

public class RtpFlowBuilder extends FlowBuilder {

	public static class RtpFlowParams extends FlowBuilder.FlowParams {
    private static final long serialVersionUID = 1L;
    /*
     * (non-Javadoc)
     * @see brn.sim.builder.Builder.ParamsWithBuilder#builderClass()
     */
    public Class builderClass() {
      return RtpFlowBuilder.class;
    }

    /** 0 - bidirectional, 1 - client server, 2 - server client*/
    public int direction = 0;
    /** Number of ms to send messages. */
    public long duration = 30000;

    /** rtp payload type */
    public int payloadType = 0;

    /** bandwidth for the specified payload type, for rtcp timings, bytes/second */
    public int bandwidth = 8000;

    /** Name of the file to stream over the network */
    public String fileName = null;
    /** whether the names of output files should be generated */
    public boolean autoOutputFileNames = false;

    public int getDirection() {
      return direction;
    }
    public void setDirection(int direction) {
      this.direction = direction;
    }
    public long getDuration() {
      return duration;
    }
    public void setDuration(long duration) {
      this.duration = duration;
    }
    public int getPayloadType() {
      return payloadType;
    }
    public void setPayloadType(int payloadType) {
      this.payloadType = payloadType;
    }
    public int getBandwidth() {
      return bandwidth;
    }
    public void setBandwidth(int bandwidth) {
      this.bandwidth = bandwidth;
    }
    public String getFileName() {
      return fileName;
    }
    public void setFileName(String fileName) {
      this.fileName = fileName;
    }
    public boolean isAutoOutputFileNames() {
      return autoOutputFileNames;
    }
    public void setAutoOutputFileNames(boolean autoOutputFileNames) {
      this.autoOutputFileNames = autoOutputFileNames;
    }
    @Override
    public int hashCode() {
      final int prime = 31;
      int result = super.hashCode();
      result = prime * result + (autoOutputFileNames ? 1231 : 1237);
      result = prime * result + bandwidth;
      result = prime * result + direction;
      result = prime * result + (int) (duration ^ (duration >>> 32));
      result = prime * result + ((fileName == null) ? 0 : fileName.hashCode());
      result = prime * result + payloadType;
      return result;
    }
    @Override
    public boolean equals(Object obj) {
      if (this == obj)
        return true;
      if (!super.equals(obj))
        return false;
      if (getClass() != obj.getClass())
        return false;
      RtpFlowParams other = (RtpFlowParams) obj;
      if (autoOutputFileNames != other.autoOutputFileNames)
        return false;
      if (bandwidth != other.bandwidth)
        return false;
      if (direction != other.direction)
        return false;
      if (duration != other.duration)
        return false;
      if (fileName == null) {
        if (other.fileName != null)
          return false;
      } else if (!fileName.equals(other.fileName))
        return false;
      if (payloadType != other.payloadType)
        return false;
      return true;
    }

	}

  /* (non-Javadoc)
   * @see brn.sim.builder.Builder#getParamClass()
   */
  @Override
  public Class getParamClass() {
    return RtpFlowParams.class;
  }

  /* (non-Javadoc)
   * @see brn.sim.builder.Builder#build(brn.sim.builder.Builder.Params, jist.swans.Node)
   */
  @Override
  public Object build(Params params, Node node) throws BuilderException {
    RtpFlowParams opts = (RtpFlowParams) params;
    Util.assertion(opts.clientAddr != null && opts.serverAddr != null);

    // initialize client/server apps
    RtpApplication rtpApp = null;
    if (node.getNet().getAddress().equals(opts.serverAddr)) {
      boolean serverSender = (0 == opts.direction || 2 == opts.direction);
      rtpApp = RtpApplication.createAudioPCMU(opts.clientAddr,
          (short)opts.clientPort, opts.serverAddr, (short)opts.serverPort,
          serverSender, opts.fileName, opts.start * Constants.MILLI_SECOND,
          opts.duration * Constants.MILLI_SECOND);
    }
    else if (node.getNet().getAddress().equals(opts.clientAddr)) {
      boolean clientSender = (0 == opts.direction || 1 == opts.direction);
      rtpApp = RtpApplication.createAudioPCMU(opts.serverAddr,
          (short)opts.serverPort, opts.clientAddr, (short)opts.clientPort,
          clientSender, opts.fileName, opts.start * Constants.MILLI_SECOND,
          opts.duration * Constants.MILLI_SECOND);
    }

    return rtpApp;
  }

  /* (non-Javadoc)
   * @see brn.sim.builder.Builder#hookUp(brn.sim.builder.Builder.Params, jist.swans.Node, java.lang.Object)
   */
  @Override
  public void hookUp(Params params, Node node, Object entity)
      throws BuilderException {
    RtpFlowParams opts = (RtpFlowParams) params;
    RtpApplication app = (RtpApplication) entity;
    TransUdp udp = (TransUdp) node.getTransport(0);

    NetAddress addr;
    int port;
    boolean server;
    if (node.getNet().getAddress().equals(opts.serverAddr)) {
      addr = opts.clientAddr;
      port = opts.clientPort;
      server = true;
    } else if (node.getNet().getAddress().equals(opts.clientAddr)) {
      addr = opts.serverAddr;
      port = opts.serverPort;
      server = false;
    } else
      return;
//    node.getTransport(0).setFlow(opts.flowId, addr, port);

    app.setFlowId(server ? opts.flowId : opts.flowId+100 );

    app.setUdpEntity(udp.getProxy());
    app.getProxy().run();
  }
}
