/*******************************************************************************

  Eurecom OpenAirInterface
  Copyright(c) 1999 - 2011 Eurecom

  This program is free software; you can redistribute it and/or modify it
  under the terms and conditions of the GNU General Public License,
  version 2, as published by the Free Software Foundation.

  This program is distributed in the hope it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  more details.

  You should have received a copy of the GNU General Public License along with
  this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.

  The full GNU General Public License is included in this distribution in
  the file called "COPYING".

  Contact Information
  Openair Admin: openair_admin@eurecom.fr
  Openair Tech : openair_tech@eurecom.fr
  Forums       : http://forums.eurecom.fsr/openairinterface
  Address      : Eurecom, 2229, route des crêtes, 06560 Valbonne Sophia Antipolis, France

*******************************************************************************/

/*! \file main.c
* \brief main program for OTG CX + RX
* \author A. Hafsaoui
* \date 2011
* \version 0.1
* \company Eurecom
* \email: openair_tech@eurecom.fr
* \note
* \warning
*/


#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#include "otg_tx.h"
#include "otg_rx.h"
#include "otg_kpi.h"
#include "otg.h"
#include "otg_tx_socket.h"
#include "otg_vars.h"
#include "traffic_config.h"

#include "../MATH/oml.h"



int SIMU_TIME=1200000;
int simu_time=0, duration=0, seed=0, simu_mode=0;


// init OTG with config parameters

void init_config_otg(char *protocol, char *ip_version)
{

  int i, j, k;

  if (simu_time>0)
    SIMU_TIME=simu_time;

  printf("OTG :: INIT CONFIG\n");

  if (seed>0)
    g_otg->seed=seed;
  else
    g_otg->seed=ceil(uniform_rng()*67534);

  printf("duration %d, seeds %d \n", duration, g_otg->seed);


  for (i=0; i<(NUMBER_OF_eNB_MAX + NUMBER_OF_UE_MAX); i++) {



    if (duration>0)
      g_otg->duration[i]=duration;
    else
      g_otg->duration[i]=10000;


    g_otg->dst_port[i]=DST_PORT;
    g_otg->dst_ip[i]=(char*)malloc(100*sizeof(char*));
    g_otg->dst_ip[i]=DST_IP;
    g_otg->dst_ip[i]=DST_IP;

    //config ip version


    if (ip_version !=NULL) {
      if ((strcmp(ip_version,"IP4")==0) ||(strcmp(ip_version,"ip4")==0))
        g_otg->ip_v[i]=IPV4;
      else if ((strcmp(ip_version,"IP6")==0) ||(strcmp(ip_version,"ip6")==0))
        g_otg->ip_v[i]=IPV6;
    } else
      g_otg->ip_v[i]=IPV4;


    //config transport protocol version
    if (protocol!=NULL) {
      if ((strcmp(protocol,"TCP")==0) ||(strcmp(protocol,"tcp")==0))
        g_otg->trans_proto[i]=TCP;
      else if ((strcmp(protocol,"UDP")==0) ||(strcmp(protocol,"udp")==0))
        g_otg->trans_proto[i]=UDP;
    } else
      g_otg->trans_proto[i]=TCP;

    for (j=0; j<(NUMBER_OF_eNB_MAX + NUMBER_OF_UE_MAX); j++) {
      g_otg->application_type[i][j]=OPENARENA;

      for (k=0; k<MAX_NUM_TRAFFIC_STATE; k++) {
        LOG_I(OTG,"INIT CONFIG Source =%d, Destination =%d,State =%d \n",i, j, k);
        g_otg->idt_dist[i][j][k]=IDT_DIST;
        g_otg->idt_min[i][j][k]=IDT_MIN;
        g_otg->idt_max[i][j][k]=IDT_MAX;
        g_otg->idt_std_dev[i][j][k]=IDT_STD_DEV;
        g_otg->idt_lambda[i][j][k]=IDT_LAMBDA;
        g_otg->size_dist[i][j][k]=PKTS_SIZE_DIST;
        g_otg->size_min[i][j][k]=PKTS_SIZE_MIN;
        g_otg->size_max[i][j][k]=PKTS_SIZE_MAX;
        g_otg->size_std_dev[i][j][k]=PKTS_SIZE_STD_DEV;
        g_otg->size_lambda[i][j][k]=PKTS_SIZE_LAMBDA;
      }

    }


  }



}



int main_below_ip()
{
  int i, j, k, l, rtt_owd ,rx_otg=0, simu_time=0, ctime=0, nb_round=0;
  float p;
  char *packet;
  int rx_packet_out;
  int pkt_size;
  printf(" max enb %d, max ue %d \n", NUMBER_OF_eNB_MAX, NUMBER_OF_UE_MAX);

  do {

    nb_round=nb_round+1;

    // for (stime=0; stime < SIMU_TIME; stime++) // discrete event generation : tick, stime generate the ctime
    for (i=0; i<(NUMBER_OF_eNB_MAX + NUMBER_OF_UE_MAX); i++) {

      for (j=0; j<(NUMBER_OF_eNB_MAX + NUMBER_OF_UE_MAX); j++) {

        for (k=0; k<MAX_NUM_TRAFFIC_STATE; k++) {
          LOG_I(OTG,"OTG emulation src=%d, dst=%d, state=%d \n", i, j, k);



          ctime=0; // set the ctime to 0

          do {

            if (simu_time> SIMU_TIME) {

              otg_info->ctime=SIMU_TIME;
              return(0);
            }

            LOG_I(OTG,"val :: ctime=%d\n", ctime);
            char *packet=NULL;
            /*packet=packet_gen(i, j, k, ctime);*/ packet=packet_gen(i, j, ctime, &pkt_size);



            if (packet!=NULL) {
              if ((ceil(g_otg->duration[i]*uniform_rng()))==ctime)  {
                printf("DROP PACKET (i=%d,j=%d) seq num=%d\n",i, j, otg_info->seq_num[i][j]);

              } else  {
                printf("SEND PACKET (i=%d,j=%d) seq num=%d\n",i, j, otg_info->seq_num[i][j]);

                rtt_owd=ceil(uniform_rng()*8.56);
                LOG_I(OTG,"one way delay= %d , (src=%d, dst=%d, state=%d)\n", rtt_owd, i, j, k);
                ctime+=rtt_owd;
                otg_info->rx_pkt_owd[i][j]=rtt_owd;
                simu_time+=rtt_owd;

                //rx_packet_out=check_packet(i, j, ctime, packet);
                rx_packet_out=otg_rx_pkt(i,j, ctime, packet, pkt_size);
                //if (rx_packet_out==NULL)
                //  LOG_I(OTG,"PKTS INFO:: DROPED\n");
                //else{
                //  if (rx_packet_out!=NULL){
                //    rx_packet_out=NULL;
                free(packet);
                //  }

                //}

                //Do not increase the ctime and simu_time with the one way delay.
                ctime-=rtt_owd;
                simu_time-=rtt_owd;


                LOG_I(OTG,"PKTS INFO:: (src=%d, dst=%d, state=%d),NB PKTS=%d  ,sequence NB=%d,  RTT (one way)ms= %d \n ",i, j, k, otg_info->tx_num_pkt[i][j], otg_info->seq_num[i][j], otg_info->rx_pkt_owd[i][j]);
              }
            } else
              printf("Node (i=%d,j=%d) seq num=%d, ctime %d, prb %lf\n",i, j, otg_info->seq_num[i][j], ctime,(ceil(g_otg->duration[i]*uniform_rng())));

            LOG_I(OTG,"Time:: ctime=%d, duration=%d, simu_time=%d, max=%d, (src=%d, dst=%d, state=%d) \n", ctime,  g_otg->duration[i],simu_time, SIMU_TIME, i, j,k);
            ctime+=1;
            simu_time+=1;
          } while (ctime<=g_otg->duration[i]) ;
        }



        if  (otg_info->tx_num_pkt[i][j]>otg_info->rx_num_pkt[i][j])
          LOG_I(OTG,"STAT: (LOSS):: (src=%d, dst=%d) NB packet TX= %d,  NB packet RX = %d, seq NUM=%d\n ",i, j, otg_info->tx_num_pkt[i][j], otg_info->rx_num_pkt[i][j],otg_info->seq_num[i][j] );
        else
          LOG_I(OTG,"STAT: :: (src=%d, dst=%d) NB packet TX= %d,  NB packet RX= %d, seq NUM=%d \n ",i, j, otg_info->tx_num_pkt[i][j], otg_info->rx_num_pkt[i][j], otg_info->seq_num[i][j]);



      }
    }



  } while (simu_time<=SIMU_TIME);

}


int main_above_ip()
{
  int i, j, k,  simu_time=0, ctime=0, nb_round=0;
  char *packet=NULL;
  printf(" max enb %d, max ue %d \n", NUMBER_OF_eNB_MAX, NUMBER_OF_UE_MAX);

  do {
    nb_round=nb_round+1;

    for (i=0; i<(NUMBER_OF_eNB_MAX + NUMBER_OF_UE_MAX); i++) {

      for (j=0; j<(NUMBER_OF_eNB_MAX + NUMBER_OF_UE_MAX); j++) {

        for (k=0; k<MAX_NUM_TRAFFIC_STATE; k++) {
          LOG_I(OTG,"SOCKET:: OTG emulation src=%d, dst=%d, state=%d \n", i, j, k);
          ctime=0;
          //    socket_packet_send(i, j, k, ctime);
        }
      }
    }


    ctime+=1;
    simu_time+=1;
  } while (simu_time<=SIMU_TIME);

}





void config_traffic_type(char *traffic)
{
  Application application;
  int i,j;

  if (strcmp(traffic, "SCBR")==0)
    application=SCBR;

  else if (strcmp(traffic, "OPENARENA")==0)
    application=OPENARENA;

  else if (strcmp(traffic, "BICYCLE_RACE")==0)
    application=BICYCLE_RACE;

  else if (strcmp(traffic, "AUTO_PILOT")==0)
    application=AUTO_PILOT;

  else if (strcmp(traffic, "TEAM_FORTRESS")==0)
    application=TEAM_FORTRESS;

  else
    application=NO_PREDEFINED_TRAFFIC;

  printf("Config Application: %d \n", application);

  for (i=0; i<(NUMBER_OF_eNB_MAX + NUMBER_OF_UE_MAX); i++) {

    for (j=0; j<(NUMBER_OF_eNB_MAX + NUMBER_OF_UE_MAX); j++) {

      g_otg->application_type[i][j] =application;

    }
  }

}



cunstom_config(simu_time, duration)
{
  int i;

  //--config introduced Global simulation time for each node
  if (simu_time>0)
    SIMU_TIME=simu_time;

  //--config introduced duartion for each node
  if (duration>0)
    for (i=0; i<NUMBER_OF_eNB_MAX + NUMBER_OF_UE_MAX; i++) {
      g_otg->duration[i] = duration;
    }
}



int main (int argc, char **argv)
{


  int i,j, tx;

  char *protocol=NULL;
  char *ip_version=NULL;
  char *traffic=NULL;




  init_all_otg();
  otg_info->ctime=0;
  LOG_I(OTG,"Emulation time %d \n ", otg_info->ctime);
  g_otg->num_nodes=NUMBER_OF_eNB_MAX + NUMBER_OF_UE_MAX;
  LOG_I(OTG,"OTG emulation number of nodes= %d \n", g_otg->num_nodes);



  for (i = 1; i <argc ; i ++) {
    if ('-' == argv[i][0]) {

      if(('h' == argv[i][1]) || ('H' == argv[i][1])) {
        printf("Help OTG: \n./otg [-M [s (socket mode)] [b (Below IP)]] [-T (Simu Time)] [-d (duration per node)] [-s (seed)] [-P (protocol: TCP or UDP)] [-I (ip version: IP4 or IP6)] -A [(application: CBR, AUTO_PILOT, BICYCLE_RACE, OPENARENA, TEAM_FORTRESS)]\n");
        return(0);

      }

      else if ('M' == argv[i][1]) {
        if (strcmp("s",argv[i+1])==0) {
          printf("Above IP: SOCKET MODE \n");
          simu_mode=1;
        } else if (strcmp("b",argv[i+1])==0) {
          printf("Below IP: IPC/RPC MODE\n");
          simu_mode=0;
        }

      }

      else if ('T' == argv[i][1]) {
        simu_time=atoi(argv[i+1]);
        printf("simu_time=%d\n", simu_time);
      }


      else if ('d' == argv[i][1]) {
        duration=atoi(argv[i+1]);
        printf("duration node=%d\n", duration);
      }

      else if ('s' == argv[i][1]) {
        seed=atoi(argv[i+1]);
        printf("seed val =%d\n", seed);
      }


      else if ('P' == argv[i][1]) {
        protocol=argv[i+1];

        if ((strcmp(argv[i+1],"TCP")==0) || (strcmp(argv[i+1],"UDP")==0) || (strcmp(argv[i+1],"tcp")==0) || (strcmp(argv[i+1],"udp")==0)) {
          protocol=argv[i+1];
          printf("Protocol=%s\n", protocol);
        }
      }

      else if ('I' == argv[i][1]) {
        if ((strcmp(argv[i+1],"IP4")==0) || (strcmp(argv[i+1],"IP6")==0) || (strcmp(argv[i+1],"ip4")==0) || (strcmp(argv[i+1],"ip6")==0)) {
          ip_version=argv[i+1];
          printf("IP version=%s\n", ip_version);
        }


      }

      else if ('A' == argv[i][1]) {
        if ((strcmp(argv[i+1],"CBR")==0) || (strcmp(argv[i+1],"AUTO_PILOT")==0) || (strcmp(argv[i+1],"BICYCLE_RACE")==0) || (strcmp(argv[i+1],"OPENARENA")==0) || (strcmp(argv[i+1],"TEAM_FORTRESS")==0))
          traffic=argv[i+1];

        config_traffic_type(traffic);

      }


    }



  }



  if (traffic!=NULL)
    init_predef_traffic();
  else
    init_config_otg(protocol, ip_version);


  init_seeds(g_otg->seed);
  cunstom_config(simu_time, duration);



  if (simu_mode==0)
    tx=main_below_ip();

  else if (simu_mode==1)
    tx=main_above_ip();



  // Compute KPI after the end of the simu
  kpi_gen();

  free_otg();



  return 0;

}


/*
int main(void) {

int i, min=40, max=1500, std_dev=100;
int n;

for(i=1; i<=100000; i++)
{

init_seeds(i);
n = uniform_dist(min, max);
//n = ceil(gaussian_dist((min + max)/2 , std_dev));
//n = ceil(exponential_dist(0.05));
//n =ceil(poisson_dist(4));
//n =ceil(weibull_dist(0,0));
//n =ceil(pareto_dist(16,4));
//n =ceil(gamma_dist(0.5,25));
//n =ceil(cauchy_dist(1,10));

if ((n<min) || (n>max))
 printf("number=%d out of range \n", n);
 else
  {printf("gen_nb=%d \n", n);
// printf("ceil gen_nb=%lf \n", ceil(n));
   }
}

printf("%d\n", n);

return 0;
    }
*/
