/*!
 * \file      GeoNetworkingLayer.hh
 * \brief     Header file for ITS GeoNetworking protocol layer.
 * \author    ETSI STF525
 * \copyright ETSI Copyright Notification
 *            No part may be reproduced except as authorized by written permission.
 *            The copyright and the foregoing restriction extend to reproduction in all media.
 *            All rights reserved.
 * \version   0.1
 */
#pragma once

#include <unistd.h>
#include <signal.h>
#include <time.h>

#include <mutex>

#include "TLayer.hh"
#include "GeoNetworkingCodec.hh"
#include "LocationTable.hh"

namespace LibItsGeoNetworking__TestSystem {
  class GeoNetworkingPort;
  class GeoNetworkingReq;
  class GeoNetworkingInd;
}

namespace LibItsGeoNetworking__TypesAndValues {
  class GeoNetworkingPdu;
  class BeaconHeader;
  class LongPosVector;
  class GN__Address;
}

class GeoNetworkingLayer : public TLayer<LibItsGeoNetworking__TestSystem::GeoNetworkingPort> {
  Params _params;
  GeoNetworkingCodec _codec;
  LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu* _beacon;
  LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu* _packet;
  LocationTable _location_table;
  LocationTable _pass_beacon_table;
  std::mutex _sendData; // FIXME To be removed, useless
  timer_t _timerid;
  struct sigevent _sev;
  struct itimerspec _its;
  long long _freq_nanosecs;
  sigset_t _mask;
  struct sigaction _sa;

  /**
   * @desc Initialize a beacon object for a stand alone beaconing
   *       This object could be replaced in case of start_beaconing call from the Adapter Control Port
   * @param p_latitude
   * @param p_longitude
   * @param p_address
   */ 
  void fill_beacon(INTEGER& p_latitude, INTEGER& p_longitude, OCTETSTRING& p_ll_address);
  /**
   * @desc Initialize a GeoNetworking packet to send GeoNetworking Facility messages
   *       This object shall be updated before to be sent
   * @param p_latitude
   * @param p_longitude
   * @param p_address
   */ 
  void fill_packet(const INTEGER& p_latitude, const INTEGER& p_longitude, const OCTETSTRING& p_ll_address, const INTEGER& p_geoAreaPosLatitude, const INTEGER& p_geoAreaPosLongitude, const INTEGER& p_distanceA, const INTEGER& p_distanceB, const INTEGER& p_angle = 0);
  
  static void timer_irq_sigalrm_handler(int p_signal, siginfo_t *p_signal_info, void *p_uc);

  const int _signal_id = SIGTERM;

public:
  GeoNetworkingLayer() : TLayer<LibItsGeoNetworking__TestSystem::GeoNetworkingPort>(), _params(), _codec(), _beacon(NULL), _sendData(), _timerid{0}, _sev{0}, _its{0}, _freq_nanosecs(0), _mask{0}, _sa{0} { };
  GeoNetworkingLayer(const std::string& p_type, const std::string& param);
  virtual ~GeoNetworkingLayer();
  
  void sendMsg(const LibItsGeoNetworking__TestSystem::GeoNetworkingReq&, Params& param);
  
  virtual void sendData(OCTETSTRING& data, Params& params);
  virtual void receiveData(OCTETSTRING& data, Params& params);
  virtual OCTETSTRING trigger_ac_event(OCTETSTRING& data, Params& params);
  
  void start_beaconing();
  void start_beaconing(const LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu& p_beacon);
  void stop_beaconing();
  void send_beacon();
  void start_pass_beaconing(const LibItsGeoNetworking__TypesAndValues::BeaconHeader& p_beacon);
  void stop_pass_beaconing();
  const LibItsGeoNetworking__TypesAndValues::LongPosVector* get_lpv(const LibItsGeoNetworking__TypesAndValues::GN__Address& p_gn_address);
  
}; // End of class GeoNetworkingLayer

