/********************************************************************
Copyright ?2007 LGC Wireless, Inc. All rights reserved
File Name: 		aifg_if.c
Description:	Interface of AIFG 
Version:		v9.0.0
Author:			Roy Jiang
Create Date:	2007-3-12

History:
2007-3-6		v9.0.1	Create
*********************************************************************/
#include "./include/aifg_var_ext.h"
#include "../../public/src/include/license_id.h"
/*
Name: 		aifg_bind
Purpose:	Request to create a SAP in AIFG module.
Input:		aifg_sap_type type:	type of upper layer entity 
			int (*callback)(): pointer to call back function 
Output:		SAP id
*/
int aifg_bind(aifg_sap_type type, int (*callback)(aifg_indication, aifg_msg_pre_decoded *))
{
	//checking parameters
	assert(type == AIFG_SAP_MSC || type == AIFG_SAP_BSC);
	assert(callback != NULL);
	assert(sap[type].enable == 0);

	if (wxc2_get_license(LIC_AIF) != 1)
		return -1;
	
	sap[type].enable = 1;
	sap[type].callback_func = callback;
	
	return (int)type;
}

/*
Name: 		aifg_modify
Purpose:	Request to modify the SAP parameter in AIFG module.
Input:		aifg_sap_type type:	type of upper layer entity 
			aifg_callback_func *callback:	new callback functions, null if no need to modify
Output:		None
*/
void aifg_modify(int sapid, int (*callback)(aifg_indication, aifg_msg_pre_decoded*))
{
	//checking parameters
	assert(sapid == AIFG_SAP_MSC || sapid == AIFG_SAP_BSC);
	assert(sap[sapid].enable == 1);

	sap[sapid].enable = 1;
	if(callback != NULL)
		sap[sapid].callback_func = callback;

	return;
}

/*
Name: 		aifg_set_running_mode
Purpose:	Set the running mode of AIFG module.
Input:		enum aifg_run_mode mode:	running mode, 0 - single, 1 - dual
			int alter_ip:IP address of the alternative server, hex format
Output:		None
*/
void aifg_set_running_mode(aifg_run_mode mode)
{
	assert(mode == AIFG_RUN_MODE_SINGLE || mode == AIFG_RUN_MODE_DUAL);

	dual_server.mode = mode;

	return;
}

/*
Name: 		aifg_createCircuitGroup
Purpose:	Request to create a circuit group in AIFG module.
Input:		int sapid: SAP ID of upper layer entity
			int dpc:	DPC of the circuit group.
			aifg_ni ni: NI of the circuit group.
Output:		Circuit Group ID - Upper layer entity should record this ID and pass it to AIFG module 
			whenever it request to send a message through this circuit group
			AIFG_ERR_NO_RESOURCE: Create failed
*/
int aifg_createCircuitGroup(int sapid, int dpc, aifg_ni ni, int tgid)
{
	int i;

	assert(sapid == AIFG_SAP_MSC || sapid == AIFG_SAP_BSC);
	assert(ni >= 0 && ni <= 3);
	assert(dpc >= 0);

	if (sap[sapid].enable == 0)
		goto ERR_PROC;	

	//check if there is a existing CG with the same dpc and ni
	for(i=0; i < AIFG_MAX_CG; i++){
		if(cg[i].enable == 1 && cg[i].dpc == dpc && cg[i].ni == ni)
			return i;
	}

	//create a new circuit group
	i = 0;
	while(cg[i].enable == 1)
		i++;

	if(i >= AIFG_MAX_CG){
		aifg_event = AIFG_ERR_OUT_OF_RESOURCE;
		goto ERR_PROC;
	}
	
	cg[i].enable = 1;
	cg[i].dpc = dpc;
	cg[i].ni = ni;
	cg[i].sapid = sapid;
	cg[i].tgid = tgid;

	return i;

ERR_PROC:
	return -1;
}

/*
Name: 		aifg_delCircuitGroup
Purpose:	Request to delete a circuit group in AIFG module.
Input:		int sapid: SAP ID of upper layer entity
			int cgid:	Circuit Group ID
Output:		None
*/
void aifg_delCircuitGroup(int sapid, int cgid)
{
	assert(sapid == AIFG_SAP_MSC || sapid == AIFG_SAP_BSC);
	assert(cgid >= 0 && cgid < AIFG_MAX_CG);
	
	cg[cgid].enable = 0;
	cg[cgid].dpc = 0;
	cg[cgid].ni = 0;
	cg[cgid].sapid = 0;
	cg[cgid].tgid = 0;

	return;
}

/*
Name: 		aifg_modCircuitGroup
Purpose:	Request to modify the parameter of a circuit group in AIFG module.
Input:		int sapid: SAP ID of upper layer entity
			int cgid:	Circuit Group ID
			int dpc:	new DPC of the circuit group, -1 if no need to change.
			enum aifg_ni:	new NI of the circuit group, -1 if no need to change.
Output:		Circuit Group ID - Upper layer entity should record this ID and pass it to AIFG module 
			whenever it request to send a message through this circuit group
*/
int aifg_modCircuitGroup(int sapid, int cgid, int dpc, int ni)
{
	assert(sapid == AIFG_SAP_MSC || sapid == AIFG_SAP_BSC);
	assert(cg[cgid].sapid == sapid);
	assert(ni >= 0 && ni <= 3);
	assert(dpc >= 0);
	assert(cgid >= 0 && cgid < AIFG_MAX_CG);
	
	cg[cgid].enable = 1;
	cg[cgid].dpc = dpc;
	cg[cgid].ni = ni;

	return cgid;
}

/*
Name: 		aifg_send
Purpose:	Request to send a message through A-interface. 
Input:		int sapid: SAP ID of upper layer entity.
			int cgid: Circuit Group ID
			int u_port: process port of upper layer entity
			aifg_msg *msg: content of assign request message
Output:		0 - succeed
			-1 - failed, no free port available
			-2 - failed, circuit group not ready
*/
int aifg_send(int sapid, int cgid, int u_port, aifg_msg_t *msg)
{
	int protocol;
	assert(sapid == AIFG_SAP_MSC || sapid == AIFG_SAP_BSC);
	assert(cgid >= 0 && cgid < AIFG_MAX_CG);
	assert(msg != NULL);

	if (sap[sapid].enable == 0){
		aifg_event = AIFG_ERR_SAP_NOT_CREATED;
		goto ERR_PROC;
	}

	//check message protocol and pd
	msg->app_port = u_port;
	if(msg->id <= AIFG_MSG_ID_RP_SMMA){
		if(msg->id <= AIFG_MSG_ID_MM_INFO)
			msg->pd = AIFG_PD_DTAP_MM;
		else if(msg->id <= AIFG_MSG_ID_FACILITY)
			msg->pd = AIFG_PD_DTAP_CC;
		else if(msg->id <= AIFG_MSG_ID_RELEASE_CMP_SS)
			msg->pd = AIFG_PD_DTAP_SS;
		else if(msg->id <= AIFG_MSG_ID_RP_SMMA)
			msg->pd = AIFG_PD_DTAP_SMS;
		else
			assert(0);
		protocol = AIFG_MSG_DTAP;
	}
	else{
		if(msg->id <= AIFG_MSG_ID_HO_CAN_RESP)
			msg->pd = AIFG_PD_BSSMAP_GLOBAL;
		else if(msg->id <= AIFG_MSG_ID_LSA_INFO)
			msg->pd = AIFG_PD_BSSMAP_DEDICATED;
		else
			assert(0);
		protocol = AIFG_MSG_BSSMAP;
	}

	if(msg->aif_port == -1 || msg->pd == AIFG_PD_BSSMAP_GLOBAL){
		if(msg->pd != AIFG_PD_BSSMAP_GLOBAL || msg->id == AIFG_MSG_ID_PAGING){
			if((msg->aif_port = aifg_port_assign(sapid, cgid, -1)) < 0){
				aifg_event = AIFG_ERR_ASSIGN_PORT_FAIL;
				goto ERR_PROC;
			}
			aifg_pcb[msg->aif_port].upper_port = u_port;
			aifg_pcb[msg->aif_port].trace_flag = msg->trace_flag;
		}
		else{
			msg->aif_port = -1;	//no port need
			aifg_send_udt(cgid, msg, NULL);	//global BSSMAP message needs no aifg port, except paging
		}
	}
	else if (aifg_pcb[msg->aif_port].stat == AIFG_PORT_TRANSACTION && aifg_pcb[msg->aif_port].ti_type != AIFG_TRANS_UNKNOW){
		if((msg->id == AIFG_MSG_ID_SETUP 
				&& (aifg_pcb[msg->aif_port].ti_stat > 0 || aifg_pcb[msg->aif_port].ti_type != AIFG_TRANS_CC))
			|| (msg->id == AIFG_MSG_ID_RP_DATA 
				&& aifg_pcb[msg->aif_port].ti_type != AIFG_TRANS_SMS))
		{
			//new transaction
			int new_port = aifg_port_assign(sapid, cgid, -1);
			if (new_port < 0){
				aifg_event = AIFG_ERR_ASSIGN_PORT_FAIL;
				goto ERR_PROC;
			}
			aifg_pcb[new_port].upper_port = u_port;
			aifg_pcb[new_port].link_id = aifg_pcb[msg->aif_port].link_id;
			aifg_pcb[new_port].trace_flag = msg->trace_flag;
			msg->aif_port = new_port;
		}
	}

	if(msg->aif_port != -1){
		if (aifg_pcb[msg->aif_port].stat == AIFG_PORT_IDLE){
			aifg_event = AIFG_ERR_MSG_SD_TO_IDLE_PORT;
			goto ERR_PROC;
		}
		aifg_pcb[msg->aif_port].cgid = cgid;
		aifg_port_proc(&aifg_pcb[msg->aif_port], msg, NULL);
	}

	aifg_debug_print(msg->aif_port, AIFG_EVENT_RV_REQ, msg, 0);

	return AIFG_SUCCEED;

ERR_PROC:
	aifg_debug_print(msg->aif_port, aifg_event, msg, u_port);
	return AIFG_ERROR;
}
