/*	ID management c file				*/
/*	written by Liu zhiguo 2002-08-06	*/
/*	version 2.0							*/
/*	-----------------------------		*/

#include "../../sccp/src/include/sccp.h"
#include "./include/tcap_public.h"
#include "./include/tcap_struct.h"

/*@ignore@*/
#define	ID_VM_KEY		0xa0800000
#define ID_VM_PERM		0664

typedef struct id_struct
{
	u32		current_did;
	u32		count_did;
	u32     count_did_occupied;
	u32     count_did_max;
    u32     count_did_tmp;
	u8		dialogue_id[MAX_DIALOGUEID];
    u8      current_iid[MAX_DIALOGUEID];
	u8		invoke_id[MAX_DIALOGUEID][MAX_INVOKEID];
}id_struct;

struct	id_struct	*ID_ptr;

typedef struct _did_queunce_struct
{
	u32		head;
	u32		tail;
	u32		idle_did[MAX_DIALOGUEID*2];
}did_queunce_struct;

did_queunce_struct	tcap_did_queunce;
 
void init_id(int grantdid)	// init the ID share memory
{
	int		shm_id,i;

	/*	tcap state machine share memory	*/
	if ((shm_id = shmget(ID_VM_KEY,sizeof(id_struct),ID_VM_PERM|IPC_CREAT)) == -1)
	{
		printf("can not init ID share memory");
		exit(0);
	}
	if ((ID_ptr = (id_struct *)shmat(shm_id,(char *)0,0)) == (id_struct *) -1)
	{
		printf("can not init ID share memory");
		exit(0);
	}
	memset(ID_ptr,0,sizeof(id_struct));

	memset(&tcap_did_queunce,0,sizeof(did_queunce_struct));
	for(i=1;i<grantdid;i++)
	{
		tcap_did_queunce.idle_did[tcap_did_queunce.head++]=i;
		tcap_did_queunce.head %= (MAX_DIALOGUEID*2);		
	}
}

u32	chkcount_did(void)
{
	return ID_ptr->count_did;
}

u32	chkcount_did_occupied(void)
{
	return ID_ptr->count_did_occupied;
}

u32	chkcount_did_max(void)
{
	return ID_ptr->count_did_max;
}

void	clrcount_did_max(void)
{
	ID_ptr->count_did_max = 0;
}

u8	xapp_check_did_state(u32 did);

u32 assign_did(void)
{
	u32		tmp_did=0;
	struct	tcapdebug_struct	*debug_ptr = (tcapdebug_struct *) &tcap_ptr->tcap_debug;

	if(tcap_did_queunce.head != tcap_did_queunce.tail)
	{
	
		tmp_did = tcap_did_queunce.idle_did[tcap_did_queunce.tail++];
		tcap_did_queunce.tail %= (MAX_DIALOGUEID*2);
		
		if(ID_ptr->dialogue_id[tmp_did])
		{
			debug_ptr->watch_dog[218] ++;
			assign_did();
		}

		ID_ptr->dialogue_id[tmp_did] = 1;
		ID_ptr->count_did ++;		
		debug_ptr->watch_dog[223]++;
	}
	else
	{
			debug_ptr->watch_dog[218] ++;
	}
	
	return tmp_did%MAX_DIALOGUEID;
}

u32 assign_did1(void)	// assign dialogue id
{
	u32		ii;
	u32		jj;
	struct	tcapdebug_struct	*debug_ptr = (tcapdebug_struct *) &tcap_ptr->tcap_debug;
	
	for (ii = 1;ii < (tcap_ptr->grantdid);ii++)
	{
		jj = (ID_ptr->current_did++) % (tcap_ptr->grantdid);
		if ((jj != 0) && (ID_ptr->dialogue_id[jj] == 0) && (xapp_check_did_state(jj)))
		{
			ID_ptr->dialogue_id[jj] = 1;
			ID_ptr->count_did ++;
			ID_ptr->current_did = ID_ptr->current_did % (tcap_ptr->grantdid);
			debug_ptr->watch_dog[223]++;
			return jj;
		}
	}
	debug_ptr->watch_dog[218] ++;
	return 0;
}

void free_did(u32 did)
{
	struct	tcapdebug_struct	*debug_ptr = (tcapdebug_struct *) &tcap_ptr->tcap_debug;
	
	if (did == 0 || did >= (tcap_ptr->grantdid))
	{
		debug_ptr->watch_dog[219] ++;
		return;
	}
	if (ID_ptr->dialogue_id[did] == 1)
	{
		ID_ptr->dialogue_id[did] = 0;
		if (ID_ptr->count_did != 0)
			ID_ptr->count_did --;
		memset(ID_ptr->invoke_id[did],0,MAX_INVOKEID);	// free all invoke id
		debug_ptr->watch_dog[213] ++;
		
		tcap_did_queunce.idle_did[tcap_did_queunce.head++] = did;
		tcap_did_queunce.head %= (MAX_DIALOGUEID*2);
	}
	debug_ptr->watch_dog[220] ++;
		

}

void free_did1(u32 did)	// free dialogue id
{
	struct	tcapdebug_struct	*debug_ptr = (tcapdebug_struct *) &tcap_ptr->tcap_debug;
	
	if (did == 0 || did >= (tcap_ptr->grantdid))
	{
		debug_ptr->watch_dog[219] ++;
		return;
	}
	if (ID_ptr->dialogue_id[did] == 1)
	{
		ID_ptr->dialogue_id[did] = 0;
		if (ID_ptr->count_did != 0)
			ID_ptr->count_did --;
		memset(ID_ptr->invoke_id[did],0,MAX_INVOKEID);	// free all invoke id
		debug_ptr->watch_dog[213] ++;
	}
	debug_ptr->watch_dog[220] ++;
}

int check_did(u32 did)
{
	if (did == 0 || did >= (tcap_ptr->grantdid))
		return 0;
	if (ID_ptr->dialogue_id[did] == 0)	// dialogue id is not assigned
		return 0;
	else
		return 1;
}

u8 assign_iid(u32 did)  // assign invoke id,need know the dialogue id
{
    u32     ii, iid=64;
    u8      current_iid;
	//char    buf[128];

    if (did == 0 || did >= (tcap_ptr->grantdid))
        return 0xff;
    current_iid = ID_ptr->current_iid[did];
    for (ii = 0;ii < MAX_INVOKEID;ii ++)
    {
        iid = (ii  + 64 + current_iid) % MAX_INVOKEID;// % MAX_INVOKEID;
        if (ID_ptr->invoke_id[did][iid] == 0)
        {
			//sprintf(buf,"assign iid: iid=%d, ii=%d, current_iid=%d\n",
			//	iid,ii,current_iid);
			// tcap_send_ascout(buf);
            ID_ptr->invoke_id[did][iid] = 1;
            ID_ptr->current_iid[did]++;
            return iid;
        }
    }
	//tcap_send_ascout("assign iid failed\n");
    memset(ID_ptr->invoke_id[did],0,MAX_INVOKEID);
    return assign_iid(did);
}

void free_iid(u32 did,u8 iid)	// free invoke id
{
	//u8 info[1024];
	//u8 suc = 0;
	
	if (did >= 0 && did < (tcap_ptr->grantdid))
	{
		ID_ptr->invoke_id[did][iid] = 0;
		//suc = 1;
	}

	//sprintf(info, "free_iid: did: %d, iid: %d suc: %d\r\n", did, iid, suc);
	//tcap_send_ascout(info);
}

int	check_iid(u32 did,u8 iid)	// check invoke id
{
	if (did == 0 || did >= (tcap_ptr->grantdid))
		return 0;
	if (ID_ptr->invoke_id[did][iid] == 0)
		return 0;
	else
		return 1;
}

u8 store_iid(u32 did,u8 iid)	// store invoke id
{
	//u8 info[1024];

	//sprintf(info, "store_iid: did: %d, iid: %d\r\n", did, iid);
	//tcap_send_ascout(info);
	
	if (did == 0 || did >= (tcap_ptr->grantdid))
		return 0;
	//if (iid == 0)
	//	memset(ID_ptr->invoke_id[did],0,MAX_INVOKEID);
	
	//Change by daniel on 2006-6-19
	////tcap do not has state machine for receiving invoke, so no need to look at the iid state everytime,
	////just set it to be occupied everytime
	
	//if (ID_ptr->invoke_id[did][iid] == 1)
	//    return 0;
	ID_ptr->invoke_id[did][iid] = 1;
	ID_ptr->current_iid[did]++;
	return 1;
}

void SetCurrentDid(u_short  did)
{
	ID_ptr->current_did = did % (tcap_ptr->grantdid);
}
/*@end@*/
