/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

/*
                                mce_app.c
                             -------------------
  AUTHOR  : Javier Morgade
  COMPANY : VICOMTECH Spain
  EMAIL   : javier.morgade@ieee.org
*/

#include <string.h>
#include <stdio.h>

#include "mce_app.h"
#include "mce_config.h"
#include "assertions.h"
#include "common/ran_context.h"
#include "targets/RT/USER/lte-softmodem.h"

#include "common/utils/LOG/log.h"

# include "intertask_interface.h"
#   include "s1ap_eNB.h"
#   include "sctp_eNB_task.h"
#   include "gtpv1u_eNB_task.h"
#   include "flexran_agent.h"

#   include "x2ap_eNB.h"
#   include "x2ap_messages_types.h"
#   include "m2ap_eNB.h"
#   include "m2ap_MCE.h"
#   include "m2ap_messages_types.h"
#   include "m3ap_MCE.h"
#   include "m3ap_messages_types.h"
#   define X2AP_ENB_REGISTER_RETRY_DELAY   10

#include "openair1/PHY/INIT/phy_init.h"
extern unsigned char NB_MCE_INST;

extern RAN_CONTEXT_t RC;

#   define MCE_REGISTER_RETRY_DELAY 10

#include "targets/RT/USER/lte-softmodem.h"

static m2ap_mbms_scheduling_information_t * m2ap_mbms_scheduling_information_local = NULL;
static m2ap_setup_resp_t * m2ap_setup_resp_local = NULL;
static m2ap_setup_req_t * m2ap_setup_req_local = NULL;


/*------------------------------------------------------------------------------*/

static uint32_t MCE_app_register(ngran_node_t node_type,uint32_t mce_id_start, uint32_t mce_id_end) {
  uint32_t         mce_id;
  MessageDef      *msg_p;
  uint32_t         register_mce_pending = 0;

  for (mce_id = mce_id_start; (mce_id < mce_id_end) ; mce_id++) {
    {
      // M3AP registration
        /* note:  there is an implicit relationship between the data structure and the message name */
        msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_REGISTER_MCE_REQ);
        //RCconfig_S1(msg_p, mce_id);

        //if (mce_id == 0) 
		//RCconfig_gtpu();

        //LOG_I(MCE_APP,"default drx %d\n",((M3AP_REGISTER_MCE_REQ(msg_p)).default_drx));

        LOG_I(ENB_APP,"[MCE %d] MCE_app_register via M3AP for instance %d\n", mce_id, ENB_MODULE_ID_TO_INSTANCE(mce_id));
        itti_send_msg_to_task (TASK_M3AP, ENB_MODULE_ID_TO_INSTANCE(mce_id), msg_p);

      //if (NODE_IS_DU(node_type)) { // F1AP registration
      //  // configure F1AP here for F1C
      //  LOG_I(ENB_APP,"ngran_eNB_DU: Allocating ITTI message for F1AP_SETUP_REQ\n");
      //  msg_p = itti_alloc_new_message (TASK_ENB_APP, F1AP_SETUP_REQ);
      //  RCconfig_DU_F1(msg_p, enb_id);

      //  LOG_I(ENB_APP,"[eNB %d] eNB_app_register via F1AP for instance %d\n", enb_id, ENB_MODULE_ID_TO_INSTANCE(enb_id));
      //  itti_send_msg_to_task (TASK_DU_F1, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
      //  // configure GTPu here for F1U
      //}
      //else { // S1AP registration
      //  /* note:  there is an implicit relationship between the data structure and the message name */
      //  msg_p = itti_alloc_new_message (TASK_ENB_APP, S1AP_REGISTER_ENB_REQ);
      //  RCconfig_S1(msg_p, enb_id);

      //  if (enb_id == 0) RCconfig_gtpu();

      //  LOG_I(ENB_APP,"default drx %d\n",((S1AP_REGISTER_ENB_REQ(msg_p)).default_drx));

      //  LOG_I(ENB_APP,"[eNB %d] eNB_app_register via S1AP for instance %d\n", enb_id, ENB_MODULE_ID_TO_INSTANCE(enb_id));
      //  itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
      //}

      register_mce_pending++;
    }
  }

  return register_mce_pending;
}


/*------------------------------------------------------------------------------*/
//static uint32_t MCE_app_register_x2(uint32_t mce_id_start, uint32_t mce_id_end) {
//  uint32_t         mce_id;
//  MessageDef      *msg_p;
//  uint32_t         register_mce_m2_pending = 0;
//
//  for (mce_id = mce_id_start; (mce_id < mce_id_end) ; mce_id++) {
//    {
//      msg_p = itti_alloc_new_message (TASK_ENB_APP, X2AP_REGISTER_ENB_REQ);
//      RCconfig_X2(msg_p, mce_id);
//      itti_send_msg_to_task (TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(mce_id), msg_p);
//      register_mce_x2_pending++;
//    }
//  }
//
//  return register_mce_x2_pending;
//}

/*------------------------------------------------------------------------------*/
//static uint32_t MCE_app_register_m2(uint32_t mce_id_start, uint32_t mce_id_end) {
//  uint32_t         mce_id;
//  MessageDef      *msg_p;
//  uint32_t         register_mce_m2_pending = 0;
//
//  LOG_W(MCE_APP,"Register ...");
//  for (mce_id = mce_id_start; (mce_id < mce_id_end) ; mce_id++) {
//    {
//  //	LOG_W(MCE_APP,"Register commes inside ...\n");
//      msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_REGISTER_MCE_REQ);
//      //RCconfig_M2_MCE(msg_p, mce_id);
//      itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(mce_id), msg_p);
//  //	LOG_W(MCE_APP,"Register sent ...\n");
//      register_mce_m2_pending++;
//    }
//  }
//
//  return register_mce_m2_pending;
//}
//
/*------------------------------------------------------------------------------*/
static uint32_t MCE_app_register_m3(uint32_t mce_id_start, uint32_t mce_id_end) {
  uint32_t         mce_id;
  MessageDef      *msg_p;
  uint32_t         register_mce_m3_pending = 0;

  LOG_D(MCE_APP,"Register ...\n");
  for (mce_id = mce_id_start; (mce_id < mce_id_end) ; mce_id++) {
    {
  //	LOG_W(MCE_APP,"Register commes inside ...\n");
      msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_REGISTER_MCE_REQ);
      RCconfig_M3(msg_p, mce_id);
      itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(mce_id), msg_p);
  	LOG_D(MCE_APP,"Register sent ...\n");
      register_mce_m3_pending++;
    }
  }

  return register_mce_m3_pending;
}

/***************************  M3AP MCE handle **********************************/
//static uint32_t MCE_app_handle_m3ap_mbms_session_start_req(instance_t instance){
//  	//uint32_t         mce_id=0;
//  //	MessageDef      *msg_p;
//  //      msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_MBMS_SESSION_START_RESP);
//  //      itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
//	
//	
//	return 0;
//}

static uint32_t MCE_app_handle_m3ap_mbms_session_stop_req(instance_t instance){
  	//uint32_t         mce_id=0;
  	MessageDef      *msg_p;
        msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_MBMS_SESSION_STOP_RESP);
        itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
	
	return 0;
}

static uint32_t MCE_app_handle_m3ap_mbms_session_update_req(instance_t instance){
  	//uint32_t         mce_id=0;
  	MessageDef      *msg_p;
        msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_MBMS_SESSION_UPDATE_RESP);
        itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
	
	return 0;
}
//// end M3AP MCE handle **********************************/


/***************************  M2AP MCE handle **********************************/
static uint32_t MCE_app_handle_m2ap_setup_req(instance_t instance){
	
  	//uint32_t         mce_id=0;
  	MessageDef      *msg_p;
        msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_SETUP_RESP);
	if(m2ap_setup_resp_local)
		memcpy(&M2AP_SETUP_RESP(msg_p),m2ap_setup_resp_local,sizeof(m2ap_setup_resp_t));
	else
		RCconfig_M2_MCCH(msg_p,0);

	
        itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
	
	return 0;
}

static uint32_t MCE_app_handle_m2ap_mbms_session_start_resp(instance_t instance){
	MessageDef      *msg_p;
  	msg_p = itti_alloc_new_message (TASK_MCE_APP, M3AP_MBMS_SESSION_START_RESP); 
	itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
	return 0;
}

//// end M2AP MCE handle **********************************/


/***************************  M2AP MCE send **********************************/
static uint32_t MCE_app_send_m2ap_mbms_scheduling_information(instance_t instance){
	
  	//uint32_t         mce_id=0;
  	MessageDef      *msg_p;
        msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_MBMS_SCHEDULING_INFORMATION);
	if(m2ap_mbms_scheduling_information_local)
		memcpy(&M2AP_MBMS_SCHEDULING_INFORMATION(msg_p),m2ap_mbms_scheduling_information_local,sizeof(m2ap_mbms_scheduling_information_t));
	else
		RCconfig_M2_SCHEDULING(msg_p,0);
        itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
	
	return 0;
}

static uint32_t MCE_app_send_m2ap_session_start_req(instance_t instance){
	
  	//uint32_t         mce_id=0;
  	MessageDef      *msg_p;
        msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_MBMS_SESSION_START_REQ);
        itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
	
	return 0;
}
//static uint32_t MCE_app_send_m2ap_session_stop_req(instance_t instance){
//	
//  	//uint32_t         mce_id=0;
//  	MessageDef      *msg_p;
//        msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_MBMS_SESSION_STOP_REQ);
//        itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
//	
//	return 0;
//}
//static uint32_t MCE_app_send_m2ap_mce_configuration_update(instance_t instance){
//	
//  	//uint32_t         mce_id=0;
//  	MessageDef      *msg_p;
//        msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_MCE_CONFIGURATION_UPDATE);
//        itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
//	
//	return 0;
//}
//static uint32_t MCE_app_send_m2ap_enb_configuration_update_ack(instance_t instance){
//	
//  	//uint32_t         mce_id=0;
//  	MessageDef      *msg_p;
//        msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_ENB_CONFIGURATION_UPDATE_ACK);
//        itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
//	
//	return 0;
//}
//static uint32_t MCE_app_send_m2ap_enb_configuration_update_failure(instance_t instance){
//	
//  	//uint32_t         mce_id=0;
//  	MessageDef      *msg_p;
//        msg_p = itti_alloc_new_message (TASK_MCE_APP, M2AP_ENB_CONFIGURATION_UPDATE_FAILURE);
//        itti_send_msg_to_task (TASK_M2AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
//	
//	return 0;
//} //// end M2AP MCE send **********************************/

//static uint32_t MCE_app_send_MME_APP(instance_t instance){
//	
//  	//uint32_t         mce_id=0;
//  	MessageDef      *msg_p;
//        msg_p = itti_alloc_new_message (TASK_MCE_APP, MESSAGE_TEST);
//        itti_send_msg_to_task (TASK_MME_APP, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
//	
//	return 0;
//}

//static uint32_t MCE_app_send_MME_APP2(instance_t instance){
//	
//  	//uint32_t         mce_id=0;
//  	MessageDef      *msg_p;
//        msg_p = itti_alloc_new_message (TASK_MCE_APP, MESSAGE_TEST);
//        itti_send_msg_to_task (TASK_M3AP_MCE, ENB_MODULE_ID_TO_INSTANCE(instance), msg_p);
//	
//	return 0;
//}

/*------------------------------------------------------------------------------*/
void *MCE_app_task(void *args_p) {
  uint32_t                        mce_nb = 1;//RC.nb_inst; 
  uint32_t                        mce_id_start = 0;
  uint32_t                        mce_id_end = mce_id_start + mce_nb;
  uint32_t                        register_mce_pending=0;
  uint32_t                        registered_mce=0;
  //long                            mce_register_retry_timer_id;
  long 				  mce_scheduling_info_timer_id;
  //uint32_t                        m3_register_mce_pending = 0;
 // uint32_t                        x2_registered_mce = 0;
 // long                            x2_mce_register_retry_timer_id;
 // uint32_t                        m2_register_mce_pending = 0;
 // uint32_t                        m2_registered_mce = 0;
 // long                            m2_mce_register_retry_timer_id;
  MessageDef                     *msg_p           = NULL;
  instance_t                      instance;
  int                             result;
  /* for no gcc warnings */
  (void)instance;
  itti_mark_task_ready (TASK_MCE_APP);

  /* Try to register each MCE */
  // This assumes that node_type of all RRC instances is the same
  if ( EPC_MODE_ENABLED && RC.rrc == NULL )
	  LOG_E(RRC, "inconsistent global variables\n");
  if (EPC_MODE_ENABLED && RC.rrc ) {
    register_mce_pending = MCE_app_register(RC.rrc[0]->node_type, mce_id_start, mce_id_end);
  }

    /* Try to register each MCE with each other */
 // if (is_x2ap_enabled() && !NODE_IS_DU(RC.rrc[0]->node_type)) {
 //   x2_register_enb_pending = MCE_app_register_x2 (enb_id_start, enb_id_end);
 // }
 // MCE_app_send_MME_APP2(0);


 if (is_m2ap_MCE_enabled() /*&& !NODE_IS_DU(RC.rrc[0]->node_type)*/) {
  RCconfig_MCE();

  if(!m2ap_mbms_scheduling_information_local)
	m2ap_mbms_scheduling_information_local = (m2ap_mbms_scheduling_information_t*)calloc(1,sizeof(m2ap_mbms_scheduling_information_t));
  if(m2ap_mbms_scheduling_information_local)
  	RCconfig_m2_scheduling(m2ap_mbms_scheduling_information_local,0);

  if(!m2ap_setup_resp_local)
	m2ap_setup_resp_local = (m2ap_setup_resp_t*)calloc(1,sizeof(m2ap_setup_resp_t));
  if(m2ap_setup_resp_local)
	RCconfig_m2_mcch(m2ap_setup_resp_local,0);
 }

 // /* Try to register each MCE with MCE each other */
 if (is_m3ap_MCE_enabled() /*&& !NODE_IS_DU(RC.rrc[0]->node_type)*/) {
   	///*m3_register_mce_pending =*/ 
	MCE_app_register_m3 (mce_id_start, mce_id_end);
   }

  do {
    // Wait for a message
    itti_receive_msg (TASK_MCE_APP, &msg_p);
    instance = ITTI_MSG_INSTANCE (msg_p);

    switch (ITTI_MSG_ID(msg_p)) {
    case TERMINATE_MESSAGE:
      LOG_W(MCE_APP, " *** Exiting MCE_APP thread\n");
      itti_exit_task ();
      break;

    case MESSAGE_TEST:
      LOG_I(MCE_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
      break;

    case SOFT_RESTART_MESSAGE:
      //handle_reconfiguration(instance);
      break;

    case M3AP_REGISTER_MCE_CNF:
      //AssertFatal(!NODE_IS_DU(RC.rrc[0]->node_type), "Should not have received S1AP_REGISTER_ENB_CNF\n");
          LOG_I(MCE_APP, "[MCE %d] Received %s: associated MME %d\n", instance, ITTI_MSG_NAME (msg_p),
                M3AP_REGISTER_MCE_CNF(msg_p).nb_mme);
          DevAssert(register_mce_pending > 0);
          register_mce_pending--;

          /* Check if at least MCE is registered with one MME */
          if (M3AP_REGISTER_MCE_CNF(msg_p).nb_mme > 0) {
            registered_mce++;
          }

          /* Check if all register MCE requests have been processed */
          if (register_mce_pending == 0) {
            if (registered_mce == mce_nb) {
              /* If all MCE are registered, start L2L1 task */
             // MessageDef *msg_init_p;
             // msg_init_p = itti_alloc_new_message (TASK_ENB_APP, INITIALIZE_MESSAGE);
             // itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p);
            } else {
              LOG_W(MCE_APP, " %d MCE not associated with a MME, retrying registration in %d seconds ...\n",
                    mce_nb - registered_mce,  MCE_REGISTER_RETRY_DELAY);

            //  /* Restart the MCE registration process in MCE_REGISTER_RETRY_DELAY seconds */
            //  if (timer_setup (MCE_REGISTER_RETRY_DELAY, 0, TASK_MCE_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
            //                   NULL, &mce_register_retry_timer_id) < 0) {
            //    LOG_E(MCE_APP, " Can not start MCE register retry timer, use \"sleep\" instead!\n");
            //    sleep(MCE_REGISTER_RETRY_DELAY);
            //    /* Restart the registration process */
            //    registered_mce = 0;
            //    register_mce_pending = MCE_app_register (RC.rrc[0]->node_type,mce_id_start, mce_id_end);
            //  }
            }
          }

      break;

   case M3AP_MBMS_SESSION_START_REQ:
        LOG_I(MCE_APP, "Received M3AP_MBMS_SESSION_START_REQ message %s\n", ITTI_MSG_NAME (msg_p));
	//MCE_app_handle_m3ap_mbms_session_start_req(ITTI_MESSAGE_GET_INSTANCE(msg_p));
	if(m2ap_setup_req_local)
		if (timer_setup (2, 0, TASK_MCE_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
                               NULL, &mce_scheduling_info_timer_id) < 0) {
   		}


	break;

   case M3AP_MBMS_SESSION_STOP_REQ:
        LOG_I(MCE_APP, "Received M3AP_MBMS_SESSION_STOP_REQ message %s\n", ITTI_MSG_NAME (msg_p));
	MCE_app_handle_m3ap_mbms_session_stop_req(ITTI_MESSAGE_GET_INSTANCE(msg_p));
	break;

   case M3AP_MBMS_SESSION_UPDATE_REQ:
        LOG_I(MCE_APP, "Received M3AP_MBMS_SESSION_UPDATE_REQ message %s\n", ITTI_MSG_NAME (msg_p));
	MCE_app_handle_m3ap_mbms_session_update_req(ITTI_MESSAGE_GET_INSTANCE(msg_p));
	break;



   case M3AP_SETUP_RESP:
      LOG_I(MCE_APP, "Received M3AP_SETUP_RESP message %s\n", ITTI_MSG_NAME (msg_p));
   //   //AssertFatal(NODE_IS_DU(RC.rrc[0]->node_type), "Should not have received F1AP_REGISTER_ENB_CNF in CU/MCE\n");

   //   //LOG_I(MCE_APP, "Received %s: associated ngran_MCE_CU %s with %d cells to activate\n", ITTI_MSG_NAME (msg_p),
   //         //F1AP_SETUP_RESP(msg_p).gNB_CU_name,F1AP_SETUP_RESP(msg_p).num_cells_to_activate);
   //   
   //   //handle_f1ap_setup_resp(&F1AP_SETUP_RESP(msg_p));
   //   handle_m3ap_setup_resp(&M3AP_SETUP_RESP(msg_p));

   //   DevAssert(register_mce_pending > 0);
   //   register_mce_pending--;

   //   /* Check if at least MCE is registered with one MME */
   //   //if (M3AP_SETUP_RESP(msg_p).num_cells_to_activate > 0) {
   //   //  registered_enb++;
   //   //}

   //   /* Check if all register MCE requests have been processed */
   //   if (register_mce_pending == 0) {
   //     if (registered_mce == mce_nb) {
   //       /* If all MCE cells are registered, start L2L1 task */
   //       MessageDef *msg_init_p;

   //       //msg_init_p = itti_alloc_new_message (TASK_MCE_APP, INITIALIZE_MESSAGE);
   //       //itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p);

   //     } else {
   //       LOG_W(MCE_APP, " %d MCE not associated with a MME, retrying registration in %d seconds ...\n",
   //             mce_nb - registered_mce,  MCE_REGISTER_RETRY_DELAY);

   //       /* Restart the MCE registration process in MCE_REGISTER_RETRY_DELAY seconds */
   //       if (timer_setup (MCE_REGISTER_RETRY_DELAY, 0, TASK_MCE_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
   //                        NULL, &mce_register_retry_timer_id) < 0) {
   //         LOG_E(ENB_APP, " Can not start MCE register retry timer, use \"sleep\" instead!\n");

   //         sleep(MCE_REGISTER_RETRY_DELAY);
   //         /* Restart the registration process */
   //         registered_mce = 0;
   //         register_mce_pending = MCE_app_register (RC.rrc[0]->node_type,mce_id_start, mce_id_end);//, enb_properties_p);
   //       }
   //     }
   //   }

      break;

    case M3AP_DEREGISTERED_MCE_IND:
      if (EPC_MODE_ENABLED) {
  	LOG_W(MCE_APP, "[MCE %d] Received %s: associated MME %d\n", instance, ITTI_MSG_NAME (msg_p),
  	      M3AP_DEREGISTERED_MCE_IND(msg_p).nb_mme);
  	/* TODO handle recovering of registration */
      }

      break;

    case TIMER_HAS_EXPIRED:
	      LOG_I(MCE_APP, " Received %s: timer_id %ld\n", ITTI_MSG_NAME (msg_p), TIMER_HAS_EXPIRED(msg_p).timer_id);

	      if (TIMER_HAS_EXPIRED (msg_p).timer_id == mce_scheduling_info_timer_id/*mce_register_retry_timer_id*/) {
		/* Restart the registration process */
		//registered_mce = 0;
		//register_mce_pending = MCE_app_register (RC.rrc[0]->node_type, mce_id_start, mce_id_end);
		MCE_app_send_m2ap_mbms_scheduling_information(0);
	      }

	      //if (TIMER_HAS_EXPIRED (msg_p).timer_id == x2_mce_register_retry_timer_id) {
	      //  /* Restart the registration process */
	      //  x2_registered_mce = 0;
	      //  x2_register_mce_pending = MCE_app_register_x2 (mce_id_start, mce_id_end);
	      //}

      break;

 //   case X2AP_DEREGISTERED_ENB_IND:
 //     LOG_W(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p),
 //           X2AP_DEREGISTERED_ENB_IND(msg_p).nb_x2);
 //     /* TODO handle recovering of registration */
 //     break;

 //   case X2AP_REGISTER_ENB_CNF:
 //     LOG_I(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p),
 //           X2AP_REGISTER_ENB_CNF(msg_p).nb_x2);
 //     DevAssert(x2_register_enb_pending > 0);
 //     x2_register_enb_pending--;

 //     /* Check if at least MCE is registered with one target MCE */
 //     if (X2AP_REGISTER_ENB_CNF(msg_p).nb_x2 > 0) {
 //       x2_registered_enb++;
 //     }

 //     /* Check if all register MCE requests have been processed */
 //     if (x2_register_enb_pending == 0) {
 //       if (x2_registered_enb == enb_nb) {
 //         /* If all MCE are registered, start RRC HO task */
 //         } else {
 //         uint32_t x2_not_associated = enb_nb - x2_registered_enb;
 //         LOG_W(ENB_APP, " %d MCE %s not associated with the target\n",
 //               x2_not_associated, x2_not_associated > 1 ? "are" : "is");

 //         // timer to retry
 //         /* Restart the MCE registration process in ENB_REGISTER_RETRY_DELAY seconds */
 //         if (timer_setup (X2AP_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP,
 //       		   INSTANCE_DEFAULT, TIMER_ONE_SHOT, NULL,
 //       		   &x2_enb_register_retry_timer_id) < 0) {
 //           LOG_E(ENB_APP, " Can not start MCE X2AP register: retry timer, use \"sleep\" instead!\n");
 //           sleep(X2AP_ENB_REGISTER_RETRY_DELAY);
 //           /* Restart the registration process */
 //           x2_registered_enb = 0;
 //           x2_register_enb_pending = MCE_app_register_x2 (enb_id_start, enb_id_end);
 //         }
 //       }
 //     }

 //     break;

 //   case M2AP_DEREGISTERED_ENB_IND:
 //     LOG_W(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p),
 //           M2AP_DEREGISTERED_ENB_IND(msg_p).nb_m2);
 //     /* TODO handle recovering of registration */
 //     break;

 //   case M2AP_REGISTER_ENB_CNF:
 //     LOG_I(ENB_APP, "[MCE %d] Received %s: associated MCE %d\n", instance, ITTI_MSG_NAME (msg_p),
 //           M2AP_REGISTER_ENB_CNF(msg_p).nb_m2);
 //     DevAssert(m2_register_enb_pending > 0);
 //     m2_register_enb_pending--;

 //     /* Check if at least MCE is registered with one target MCE */
 //     if (M2AP_REGISTER_ENB_CNF(msg_p).nb_m2 > 0) {
 //       m2_registered_enb++;
 //     }

 //     /* Check if all register MCE requests have been processed */
 //     if (m2_register_enb_pending == 0) {
 //       if (m2_registered_enb == enb_nb) {
 //         /* If all MCE are registered, start RRC HO task */
 //         } else {
 //         uint32_t m2_not_associated = enb_nb - m2_registered_enb;
 //         LOG_W(ENB_APP, " %d MCE %s not associated with the target\n",
 //               m2_not_associated, m2_not_associated > 1 ? "are" : "is");

 //         // timer to retry
 //         /* Restart the MCE registration process in ENB_REGISTER_RETRY_DELAY seconds */
 //         //if (timer_setup (X2AP_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP,
 //         //      	   INSTANCE_DEFAULT, TIMER_ONE_SHOT, NULL,
 //         //      	   &x2_enb_register_retry_timer_id) < 0) {
 //         //  LOG_E(ENB_APP, " Can not start MCE X2AP register: retry timer, use \"sleep\" instead!\n");
 //         //  sleep(X2AP_ENB_REGISTER_RETRY_DELAY);
 //         //  /* Restart the registration process */
 //         //  x2_registered_enb = 0;
 //         //  x2_register_enb_pending = MCE_app_register_x2 (enb_id_start, enb_id_end);
 //         //}
 //       }
 //     }

 //     break;
   case M2AP_RESET:
      LOG_I(MCE_APP, "Received M2AP_RESET message %s\n", ITTI_MSG_NAME (msg_p));
	break;

   case M2AP_SETUP_REQ:
      LOG_I(MCE_APP, "Received M2AP_SETUP_REQ message %s\n", ITTI_MSG_NAME (msg_p));
	if(!m2ap_setup_req_local)
		m2ap_setup_req_local = (m2ap_setup_req_t*)calloc(1,sizeof(m2ap_setup_req_t));
	if(m2ap_setup_req_local)
		memcpy(m2ap_setup_req_local,&M2AP_SETUP_REQ(msg_p),sizeof(m2ap_setup_req_t));
	MCE_app_handle_m2ap_setup_req(ITTI_MESSAGE_GET_INSTANCE(msg_p));
	//MCE_app_send_m2ap_mbms_scheduling_information(0);
	//if (timer_setup (2, 0, TASK_MCE_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
        //                       NULL, &mce_scheduling_info_timer_id) < 0) {
   	//}


   	/*m3_register_mce_pending =*/ //MCE_app_register_m3 (mce_id_start, mce_id_end);

	//MCE_app_send_m2ap_session_start_req(0);
	break;

   case M2AP_MBMS_SESSION_START_RESP:
      LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_START_RESP message %s\n", ITTI_MSG_NAME (msg_p));
	//MCE_app_send_m2ap_session_stop_req(0);
	MCE_app_handle_m2ap_mbms_session_start_resp(0);
	break;

   case M2AP_MBMS_SESSION_STOP_RESP:
      LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_STOP_RESP message %s\n", ITTI_MSG_NAME (msg_p));
	//MCE_app_send_m2ap_session_start_req(0);
	//MCE_app_handle_m2ap_mbms_session_start_resp(0);
	//MCE_app_send_MME_APP(0);
	break;

   case M2AP_MBMS_SCHEDULING_INFORMATION_RESP:
      LOG_I(MCE_APP, "Received M2AP_MBMS_SCHEDULING_INFORMATION_RESP message %s\n", ITTI_MSG_NAME (msg_p));
	MCE_app_send_m2ap_session_start_req(0);
	break;

   case M2AP_ENB_CONFIGURATION_UPDATE:
      LOG_I(MCE_APP, "Received M2AP_ENB_CONFIGURATION_UPDATE message %s\n", ITTI_MSG_NAME (msg_p));
	break;
	
   case M2AP_ERROR_INDICATION:
      LOG_I(MCE_APP, "Received M2AP_ERROR_INDICATION message %s\n", ITTI_MSG_NAME (msg_p));
	break;

   case M2AP_MBMS_SESSION_UPDATE_RESP:
      LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_UPDATE_RESP message %s\n", ITTI_MSG_NAME (msg_p));
	break;

   case M2AP_MBMS_SESSION_UPDATE_FAILURE:
      LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_UPDATE_FAILURE message %s\n", ITTI_MSG_NAME (msg_p));
	break;

   case M2AP_MBMS_SERVICE_COUNTING_REPORT:
      LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_UPDATE_REPORT message %s\n", ITTI_MSG_NAME (msg_p));
	break;

   case M2AP_MBMS_OVERLOAD_NOTIFICATION:
      LOG_I(MCE_APP, "Received M2AP_MBMS_OVERLOAD_NOTIFICATION message %s\n", ITTI_MSG_NAME (msg_p));
	break;

   case M2AP_MBMS_SERVICE_COUNTING_RESP:
      LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_UPDATE_RESP message %s\n", ITTI_MSG_NAME (msg_p));
	break;

   case M2AP_MBMS_SERVICE_COUNTING_FAILURE:
      LOG_I(MCE_APP, "Received M2AP_MBMS_SESSION_UPDATE_FAILURE message %s\n", ITTI_MSG_NAME (msg_p));
	break;

   case M2AP_MCE_CONFIGURATION_UPDATE_ACK:
      LOG_I(MCE_APP, "Received M2AP_MCE_CONFIGURATION_UPDATE_ACK message %s\n", ITTI_MSG_NAME (msg_p));
	break;
   case M2AP_MCE_CONFIGURATION_UPDATE_FAILURE:
      LOG_I(MCE_APP, "Received M2AP_MCE_CONFIGURATION_UPDATE_FAILURE message %s\n", ITTI_MSG_NAME (msg_p));
	break;

    default:
      LOG_E(MCE_APP, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
      break;
    }

    result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
  } while (1);

  return NULL;
}

//void handle_reconfiguration(module_id_t mod_id) {
//  struct timespec start, end;
//  clock_gettime(CLOCK_MONOTONIC, &start);
//  flexran_agent_info_t *flexran = RC.flexran[mod_id];
//  LOG_I(ENB_APP, "lte-softmodem soft-restart requested\n");
//
//  if (ENB_WAIT == flexran->node_ctrl_state) {
//    /* this is already waiting, just release */
//    pthread_mutex_lock(&flexran->mutex_node_ctrl);
//    flexran->node_ctrl_state = ENB_NORMAL_OPERATION;
//    pthread_mutex_unlock(&flexran->mutex_node_ctrl);
//    pthread_cond_signal(&flexran->cond_node_ctrl);
//    return;
//  }
//
//  if (stop_L1L2(mod_id) < 0) {
//    LOG_E(ENB_APP, "can not stop lte-softmodem, aborting restart\n");
//    return;
//  }
//
//  /* node_ctrl_state should have value ENB_MAKE_WAIT only if this method is not
//   * executed by the FlexRAN thread */
//  if (ENB_MAKE_WAIT == flexran->node_ctrl_state) {
//    LOG_I(ENB_APP, " * MCE %d: Waiting for FlexRAN RTController command *\n", mod_id);
//    pthread_mutex_lock(&flexran->mutex_node_ctrl);
//    flexran->node_ctrl_state = ENB_WAIT;
//
//    while (ENB_NORMAL_OPERATION != flexran->node_ctrl_state)
//      pthread_cond_wait(&flexran->cond_node_ctrl, &flexran->mutex_node_ctrl);
//
//    pthread_mutex_unlock(&flexran->mutex_node_ctrl);
//  }
//
//  if (restart_L1L2(mod_id) < 0) {
//    LOG_E(ENB_APP, "can not restart, killing lte-softmodem\n");
//    exit_fun("can not restart L1L2, killing lte-softmodem");
//    return;
//  }
//
//  clock_gettime(CLOCK_MONOTONIC, &end);
//  end.tv_sec -= start.tv_sec;
//
//  if (end.tv_nsec >= start.tv_nsec) {
//    end.tv_nsec -= start.tv_nsec;
//  } else {
//    end.tv_sec -= 1;
//    end.tv_nsec = end.tv_nsec - start.tv_nsec + 1000000000;
//  }
//
//  LOG_I(ENB_APP, "lte-softmodem restart succeeded in %ld.%ld s\n", end.tv_sec, end.tv_nsec / 1000000);
//}