package brn.sim.handler;

import jist.swans.Constants;
import jist.swans.misc.Event;
import jist.swans.misc.MessageAnno;
import jist.swans.misc.Util;
import jist.swans.radio.AbstractRadio;
import jist.swans.radio.RadioInterface;
import brn.sim.DataManager;
import brn.sim.DataManager.DataContributor;
import brn.sim.data.TimeBar;

public class TimeBarRadioPacketHandler extends DataContributor {

  // ////////////////////////////////////////////////
  // constants
  //

  private static final String ID = "TimeBarRadioPacketHandler";


  // ////////////////////////////////////////////////
  // locals
  //

  private TimeBar radioTimeBar;


  // ////////////////////////////////////////////////
  // initialization
  //

  public TimeBarRadioPacketHandler() {
    radioTimeBar = new TimeBar(new String[] {"Global", "Radio", "Packet Timebar"});
  }

  public void registerHandlers() {
    Event.addHandler(AbstractRadio.RadioSendEvent.class, new Event.Handler() {
      public void handle(Event event) {
        AbstractRadio.RadioSendEvent ev = (AbstractRadio.RadioSendEvent) event;

        String text = "";
        if (ev.anno != null) {
          RadioInterface.RFChannel txChannel
                  = (RadioInterface.RFChannel)ev.anno.get(MessageAnno.ANNO_MAC_RF_CHANNEL);
          if (txChannel != null)
            text = text + txChannel.getChannel();
        }
        radioTimeBar.add(ev.nodeId, ev.time, ev.time + ev.duration,
            TimeBar.COLOR_GREEN, text, ev.data.toString());
      }
    });

    Event.addHandler(AbstractRadio.RadioReceiveEvent.class, new Event.Handler() {
      public void handle(Event event) {
        AbstractRadio.RadioReceiveEvent ev = (AbstractRadio.RadioReceiveEvent) event;

        boolean statusCrc = false;
        boolean statusPhy = false;
        boolean detectionOnly = false;
        
        StringBuilder builder = null;
        String text = "";
        if (ev.anno != null) {
          builder = new StringBuilder();
          
          RadioInterface.RFChannel txChannel = (RadioInterface.RFChannel)
            ev.anno.get(MessageAnno.ANNO_MAC_RF_CHANNEL);
          if (txChannel != null)
            text += txChannel.getChannel();

          Double per = (Double) ev.anno.get(MessageAnno.ANNO_RADIO_PACKET_PER);
          if (per != null) {
            builder.append("[per ").append(per).append("]");
            if (per.doubleValue() >= .99)
              detectionOnly = true;
          }

          Double snr = (Double) ev.anno.get(MessageAnno.ANNO_RADIO_PACKET_SNR);
          if (snr != null)
            builder.append("[sinr ").append(Util.toDB(snr.doubleValue())).append(" dB]");

          Double power_mW = (Double) ev.anno.get(MessageAnno.ANNO_RADIO_SIGNAL_POWER);
          if (power_mW != null)
            builder.append("[power ").append(Util.toDB(power_mW.doubleValue())).append(" dBm]");

          Double intf_mW = (Double) ev.anno.get(MessageAnno.ANNO_RADIO_INTF_POWER);
          if (intf_mW != null)
            builder.append("[intf ").append(Util.toDB(intf_mW.doubleValue())).append(" dBm]");

          Byte status = (Byte) ev.anno.get(MessageAnno.ANNO_RADIO_RECV_STATUS);
          if (status != null) {
            if (status.equals(Constants.RADIO_RECV_STATUS_CRC))
              statusCrc = true;
            if (status.equals(Constants.RADIO_RECV_STATUS_PHY)) {
              statusPhy = true;
              // heuristics for phy errors: snr < 0 dB could not be received
              if (snr != null && snr.doubleValue() <= 1.)
                detectionOnly = true;
            }
          }
        }
        
        byte color = TimeBar.COLOR_YELLOW; // TimeBar.COLOR_GREEN;
        if (statusCrc) color = TimeBar.COLOR_DARK_YELLOW;
        if (statusPhy) color = TimeBar.COLOR_DARK_RED;
        if (detectionOnly) color = TimeBar.COLOR_WHITE;
        
        radioTimeBar.add(ev.nodeId, ev.start, ev.end, color,
            text, (builder == null ? "" : builder.toString()));
      }
    });
  }


  // ////////////////////////////////////////////////
  // implementation
  //

  /**
   * @return the radioTimeBar
   */
  public TimeBar getRadioTimeBar() {
    return radioTimeBar;
  }

  /*
   * (non-Javadoc)
   * @see brn.sim.DataManager.DataContributor#getId()
   */
  public String getId() {
    return ID;
  }

  /* (non-Javadoc)
   * @see brn.sim.DataManager.DataContributor#setDataManager(brn.sim.DataManager)
   */
  public void setDataManager(DataManager manager) {
    super.setDataManager(manager);
    manager.addData(this, radioTimeBar);
  }

}
