package test.brn.swans.radio;

import java.io.IOException;
import java.util.Iterator;

import brn.analysis.Statistics;
import brn.sim.data.AbstractDiagramData;
import brn.sim.data.AveragedTimeLine;
import brn.sim.data.Line;
import brn.sim.data.TimeLine;
import brn.sim.data.XplotSerializer;
import brn.sim.handler.LinkQualityHandler;
import brn.swans.app.AppLqMeasurement;
import brn.swans.radio.RadioEmpirical;

import jist.runtime.JistAPI;
import jist.swans.Constants;
import jist.swans.mac.Mac802_11;
import jist.swans.mac.MacAddress;
import jist.swans.misc.Mapper;
import jist.swans.net.NetAddress;
import jist.swans.net.NetIp;
import jist.swans.net.PacketLoss;
import jist.swans.radio.RadioFactory;
import jist.swans.radio.RadioInfo;
import jist.swans.rate.AnnoRate;

public class RadioEmpiricalTest {

  static LinkQualityHandler linkQualityHandler;

  protected static void finished(RadioEmpirical radio, AppLqMeasurement handlerB) throws IOException {
    long avgIntv = 50 * Constants.SECOND;
    int mode = AveragedTimeLine.MODE_C;
    double scale = 1.0;

    long[][][][] timeRateStatus = radio.getTimeRateStatus();
    long stationarityTime = radio.getStationarityTime();

    // process neighbour set
    Iterator it = handlerB.getNodes().iterator();
    while(it.hasNext()) {
      MacAddress node = (MacAddress) it.next();

      for (int idx = 0; idx < 12; idx++) {
        int rate = RadioEmpirical.getBitrate(idx);
        int rateDisplay = rate / Constants.BANDWIDTH_1Mbps;

        XplotSerializer seri = new XplotSerializer("packet arrival", "time", "packets");
        XplotSerializer seri2 = new XplotSerializer("TimeCOR", "time (log)", "COR");

        for (int status = 0; status < 4; status++) {
          String color = "blue";
          if (status==RadioEmpirical.RECV_STATUS_OK)
            color = "green";
          else if (status==RadioEmpirical.RECV_STATUS_CRC)
            color = "yellow";
          else if (status==RadioEmpirical.RECV_STATUS_PHY)
            color = "red";

          AbstractDiagramData data = linkQualityHandler.getTimeline(
              handlerB.getNode().getNodeId(), node, rate, status);
          if (null == data)
            continue;
          TimeLine tl = (TimeLine) data.getLine();
          seri.addLine(new AveragedTimeLine(tl, avgIntv, mode, scale), color);

          // calculate the time correlation diagramm
          double[] values = null;
          if (status < 3) {
            values = Statistics.timeCorrelation(
                toDoubleArray(timeRateStatus[idx][status][1]), tl.getY());
          }
          else {
            double[] reference = new double[timeRateStatus[idx][0][1].length];
            for (int i = 0; i < reference.length; i++)
              reference[i] = timeRateStatus[idx][0][1][i] +
                timeRateStatus[idx][1][1][i] + timeRateStatus[idx][2][1][i];
            values = Statistics.timeCorrelation(reference, tl.getY());
          }

          Line timeCOR = new Line("time-COR real-sim " + rateDisplay);
          for (int i = 0; i < values.length; i++)
            timeCOR.add(i, values[i]);
          seri2.addLine(timeCOR, color);
        }

        // save averaged time lines
        String fileName = node.toString();
        fileName.replace(':',  '_');
        seri.saveToFile(fileName + "-" + rateDisplay + "Mbps-" +
            stationarityTime/Constants.SECOND + "s.xpl");

        seri2.saveToFile(fileName + "-COR-" + rateDisplay + "Mbps-" +
            stationarityTime/Constants.SECOND + "s.xpl");
      }
    }
  }

  private static double[] toDoubleArray(long[] ls) {
    double[] ret = new double[ls.length];
    for (int i = 0; i < ls.length; i++)
      ret[i] = ls[i];
    return ret;
  }


  /**
   * Test code
   * @param args
   * @throws Exception
   */
  public static void main(String[] args) throws Exception {
    String traceFileName = args[0];

    final long stationarityTime = 100*Constants.SECOND;

    linkQualityHandler = new LinkQualityHandler();
    linkQualityHandler.registerHandlers();

    RadioInfo radioInfo = RadioFactory.createRadioInfoDefault80211g();
    Mac802_11 macA = new Mac802_11(new MacAddress(1), radioInfo);
    Mac802_11 macB = new Mac802_11(new MacAddress(2), radioInfo);
    Mapper mapper= new Mapper(new int[] { Constants.NET_PROTOCOL_HEARTBEAT, });
    PacketLoss pl = new PacketLoss.Zero();
    NetIp netA = new NetIp(new NetAddress(1), mapper, pl, pl);
    NetIp netB = new NetIp(new NetAddress(1), mapper, pl, pl);

    final RadioEmpirical radio = new RadioEmpirical(traceFileName,
        stationarityTime, 0, 1, true);
    radio.setMacEntity(macA.getProxy(), macB.getProxy());
    macA.setRadioEntity(radio.getProxy()[1]);
    macB.setRadioEntity(radio.getProxy()[0]);
    byte intIdA = netA.addInterface(macA.getProxy());
    byte intIdB = netB.addInterface(macB.getProxy());
    macA.setNetEntity(netA.getProxy(), intIdA);
    macB.setNetEntity(netB.getProxy(), intIdB);
    macA.setUseAnnotations(true);
    macB.setUseAnnotations(true);
    macA.setRateControlAlgorithm(new AnnoRate(macA.getRateControlAlgorithm()));
    macB.setRateControlAlgorithm(new AnnoRate(macB.getRateControlAlgorithm()));
    final AppLqMeasurement handlerA = new AppLqMeasurement(1, 500 * Constants.MILLI_SECOND, 0);
    final AppLqMeasurement handlerB = new AppLqMeasurement(2, 500 * Constants.MILLI_SECOND, 0);
    netA.setProtocolHandler(Constants.NET_PROTOCOL_HEARTBEAT, handlerA);
    netA.setProtocolHandler(Constants.NET_PROTOCOL_HEARTBEAT, handlerB);
    handlerA.setNetEntity(netA.getProxy());
    handlerB.setNetEntity(netB.getProxy());

    handlerA.getAppProxy().run(null);

    JistAPI.endAt(21000 * Constants.SECOND);
    JistAPI.runAt(new Runnable() {
      public void run() {
        try {
          finished(radio, handlerB);
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }, JistAPI.END);
  }


}
