/*
 *  pal/rm.c
 *
 *  Copyright (C) 2008  ACRD
 *  Written by: Xinyu Yan <xinyu.yan@adc.com>
 *
 *  Description: Protocol Abstraction Layer - resource management part
 */

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

struct  resource_mgmt {
	pal_sap_struct sap[PAL_MAX_SAP];
	pal_cg_struct cg[PAL_MAX_CG];
	pal_circuit_struct circuit[PAL_MAX_CIRCUIT];
};

#define ERROR_STRING_LEN	256

static u8 version[4] = {9, 0, 0, 1};
static struct resource_mgmt pal_resource;
static char error_string[ERROR_STRING_LEN+1];

u8 *pal_version(void)
{
	return version;
}

char *pal_error(void)
{
	return error_string;
}

/****************************************************/
/*************** PAL upper layer interface ***************/
/****************************************************/
int pal_bind_sap(sap_attrib_struct *attrib)
{
	int i;
	pal_sap_struct *sap;
	
	for(i = 0; i < PAL_MAX_SAP; i++)
	{
		sap = &pal_resource.sap[i];
		if(sap->enable == 0)
		{
			sap->id = i;
			sap->enable = 1;
			memcpy(&sap->attrib, attrib, sizeof(sap_attrib_struct));
			return i;
		}
	}
	sprintf(error_string, "%s: no free sap\r\n", __FUNCTION__);
	return -1;
}

int pal_unbind_sap(u8 sap_id)
{
	//need not support//
	return -1;
}

int pal_create_cg(u8 sap_id, cg_attrib_struct *attrib)
{
	int i;
	pal_cg_struct *cg;

	if(sap_id >= PAL_MAX_SAP)
	{
		sprintf(error_string, "%s: sap id(%d) out of range\r\n", __FUNCTION__, sap_id);
		return -1;
	}
	if(pal_resource.sap[sap_id].enable == 0)
	{
		sprintf(error_string, "%s: sap (%d) is not created\r\n", __FUNCTION__, sap_id);
		return -1;
	}
	
	for(i = 0; i < PAL_MAX_CG; i++)
	{
		cg = &pal_resource.cg[i];
		if(cg->enable == 0)
		{
			cg->id = i;
			cg->enable = 1;
			cg->sap_id = sap_id;
			cg->circuit_num = 0;
			memcpy(&cg->attrib, attrib, sizeof(cg_attrib_struct));
			return i;
		}
	}
	sprintf(error_string, "%s: no free cg\r\n", __FUNCTION__);
	return -1;
}

int pal_delete_cg(int cg_id)
{
	pal_cg_struct *cg;
	
	if(cg_id >= PAL_MAX_CG)
	{
		sprintf(error_string, "%s: cg id(%d) out of range\r\n", __FUNCTION__, cg_id);
		return -1;
	}
	cg = &pal_resource.cg[cg_id];
	if(cg->circuit_num > 0)
	{
		sprintf(error_string, "%s: %d circuit in used\r\n", __FUNCTION__, cg->circuit_num);
		return -1;
	}
	cg->enable = 0;
	return 0;
}

int pal_modify_cg(int cg_id, cg_attrib_struct *attrib)
{
	pal_cg_struct *cg;
	
	if(cg_id >= PAL_MAX_CG)
	{
		sprintf(error_string, "%s: cg id(%d) out of range\r\n", __FUNCTION__, cg_id);
		return -1;
	}
	cg = &pal_resource.cg[cg_id];
	memcpy(&cg->attrib, attrib, sizeof(cg_attrib_struct));
	return 0;
}

int pal_create_circuit(int cg_id, circuit_attrib_struct *attrib)
{
	int i;
	pal_cg_struct *cg;
	pal_circuit_struct *circuit;

	if(cg_id >= PAL_MAX_CG)
	{
		sprintf(error_string, "%s: cg id(%d) out of range\r\n", __FUNCTION__, cg_id);
		return -1;
	}
	cg = &pal_resource.cg[cg_id];
	if(cg->enable == 0)
	{
		sprintf(error_string, "%s: cg(%d) is not created\r\n", __FUNCTION__, cg_id);
		return -1;
	}
	for(i = 0; i < PAL_MAX_CIRCUIT; i++)
	{
		circuit = &pal_resource.circuit[i];
		if(circuit->enable == 0)
		{
			circuit->id = i;
			circuit->enable = 1;
			circuit->cg_id = cg_id;
			memcpy(&circuit->attrib, attrib, sizeof(circuit_attrib_struct));
			cg->circuit_num++;
			return i;
		}
	}
	sprintf(error_string, "%s: no free circuit\r\n", __FUNCTION__);
	return -1;
}

int pal_delete_circuit(int circuit_id)
{
	pal_cg_struct *cg;
	pal_circuit_struct *circuit;

	if(circuit_id >= PAL_MAX_CIRCUIT)
	{
		sprintf(error_string, "%s: circuit id(%d) out of range\r\n", __FUNCTION__, circuit_id);
		return -1;
	}
	circuit = &pal_resource.circuit[circuit_id];
	cg = &pal_resource.cg[circuit->cg_id];
	circuit->enable = 0;
	cg->circuit_num--;
	return 0;
}

/****************************************************/
/*************** PAL lower layer interface ***************/
/****************************************************/
static int protocol_is_ss7(u8 proto)
{
	if((proto == PROTO_AIF) || (proto == PROTO_ISUP) || (proto == PROTO_BICC))
		return 1;
	else
		return 0;
}

void *pal_get_handler(u32 cg_id)
{
	u32 sap_id;

	sap_id = pal_resource.cg[cg_id].sap_id;
	return pal_resource.sap[sap_id].attrib.event_handle;
}

const pal_sap_struct *pal_sap_ptr(u8 sap_id)
{
	if(sap_id < PAL_MAX_SAP)
		return &pal_resource.sap[sap_id];
	else
		return NULL;
}

const pal_cg_struct *pal_cg_ptr(u32 cg_id)
{
	if(cg_id < PAL_MAX_CG)
		return &pal_resource.cg[cg_id];
	else
		return NULL;
}

const pal_circuit_struct *pal_circuit_ptr(u32 circuit_id)
{
	if(circuit_id < PAL_MAX_CIRCUIT)
		return &pal_resource.circuit[circuit_id];
	else
		return NULL;
}

const pal_cg_struct *pal_ss7_find_cg(u8 ni, u32 dpc, u32 opc)
{
	int i;
	pal_cg_struct *cg;

	for(i = 0; i < PAL_MAX_CG; i++)
	{
		cg = &pal_resource.cg[i];
		if(cg->enable == 0)
			continue;
		if(protocol_is_ss7(cg->attrib.protocol) == 0)
			continue;
		if((cg->attrib.network_id == ni) &&
			(cg->attrib.opc == opc) &&
			(cg->attrib.dpc == dpc))
			return cg;
	}
	return NULL;
}

const pal_cg_struct *pal_isdn_find_cg(u32 link_id)
{
	int i;
	pal_circuit_struct *circuit;

	for(i = 0; i < PAL_MAX_CIRCUIT; i++)
	{
		circuit = &pal_resource.circuit[i];
		if(circuit->enable == 0)
			continue;
		if(pal_resource.cg[circuit->cg_id].attrib.protocol != PROTO_ISDN)
			continue;
		if(circuit->attrib.link_id == link_id)
			return &pal_resource.cg[circuit->cg_id];
	}
	return NULL;
}

const pal_cg_struct *pal_sip_find_cg(char *domain, char *their_domain)
{
	int i;
	pal_cg_struct *cg;

	for(i = 0; i < PAL_MAX_CG; i++)
	{
		cg = &pal_resource.cg[i];
		if(cg->enable == 0)
			continue;
		if(cg->attrib.protocol != PROTO_SIP)
			continue;
		if((strcmp(cg->attrib.local_domain, domain) == 0) && \
			(strcmp(cg->attrib.dest_domain, their_domain) == 0))
			return cg;
	}
	return NULL;
}

/* 
 * Use "locate" when received primitive from upper layer
 * Use "find" when received message from network
 */
const pal_circuit_struct *pal_locate_circuit(u32 cg_id, u32 cic)
{
	int i;
	pal_circuit_struct *circuit;
	circuit_attrib_struct *attrib;

	for(i = 0; i < PAL_MAX_CIRCUIT; i++)
	{
		circuit = &pal_resource.circuit[i];
		if(circuit->cg_id != cg_id)
			continue;
		attrib = &circuit->attrib;
		if((cic >= attrib->head_cic) && (cic < attrib->head_cic+attrib->cic_range))
			return circuit;
	}
	return NULL;
}

const pal_circuit_struct *pal_ss7_find_circuit(u8 ni, u32 dpc, u32 opc, u32 cic)
{
	const pal_cg_struct *cg;

	if((cg = pal_ss7_find_cg(ni, dpc, opc)) == NULL)
		return NULL;
	return pal_locate_circuit(cg->id, cic);
}

const pal_circuit_struct *pal_isdn_find_circuit(u32 link_id, u32 cic)
{
	const pal_cg_struct *cg;

	if((cg = pal_isdn_find_cg(link_id)) == NULL)
		return NULL;
	return pal_locate_circuit(cg->id, cic);
}

const pal_circuit_struct *pal_isdn_find_circuit_of_link(u32 link_id)
{
	int i;
	pal_circuit_struct *circuit;

	for(i = 0; i < PAL_MAX_CIRCUIT; i++)
	{
		circuit = &pal_resource.circuit[i];
		if(circuit->enable == 0)
			continue;
		if(pal_resource.cg[circuit->cg_id].attrib.protocol != PROTO_ISDN)
			continue;
		if(circuit->attrib.link_id == link_id)
			return circuit;
	}
	return NULL;
}

