/********************************************************************
Copyright ?2007 LGC Wireless, Inc. All rights reserved
File Name: 	aifg_csta.c
Description:	CSTA of AIFG 
Version:		v9.0.0
Author:			XH Chen
Create Date:	2008-3-12

History:
2007-3-6		v9.0.1	Create
*********************************************************************/
#include "../../../plat/public/src/include/includes.h"
#include "../../../plat/snmp/src/include/snmp.h"
#include "./include/aifg_type_def.h"

#define NO_EXIST 		0
#define EXIST			1
#define OID_OFFSET		14
#define AIF_10SEC		1000
struct obj_view {
	int		entry_oidlen;
	int		column_oidlen;
	int		full_oidlen;
	DWORD	*entry;
	DWORD	*column;
	DWORD	*iid;		/* Instance ID */
	BYTE	csta_pos;
	BYTE	csta_len;
};

typedef void *(*lookup_level_1)(u32 *oid_1);
typedef void *(*lookup_level_2)(u32 oid_1, u32 *oid_2);
typedef int (*get_csta)(struct obj_view *view, u8 *pdata, u8 *vartype);

struct tab_view{
	BYTE exist_flag;
	BYTE entry_id;
	BYTE level;	/* Three level: 1, 2*/
	lookup_level_1 lookup_1;
	lookup_level_2 lookup_2;
	get_csta get_aif_csta;
	u8 next_column[16];
	struct obj_view view;
};

#define	AIF_OID				{1,3,6,1,4,1,1373,2,3,2,6}
#define	AIF_OIDLEN			11

typedef struct{
    unsigned long timestamp;
    int msg_stat[AIFG_MAX_MESSAGE*2];
}aifg_csta;

BYTE	aifCSTAInd;
aifg_csta	aifCSTA[96];
//DTAP:RR MM CC SS SMS; BSSMAP:Global Dedicated
const BYTE cstaLen[8] = {0, 2, 21, 31, 3, 4, 18, 36};
const BYTE postion[8] = {0, 0, 4, 46, 108, 114, 122, 158};

extern int msg_statistics[AIFG_MAX_MESSAGE][2];
u32 *findnext_quater(u32 *id);
int get_aif_csta(struct obj_view *view, BYTE *pdata, BYTE *vartype);
int aifg_get_resp(BYTE oidlen, DWORD *oid, BYTE *pdata, BYTE *vartype);
int aif_getnext_resp(u8 prev_oidlen, u32 *prev_oid, u8 *oidlen, u32 *oid, u8 *pdata, u8 *vartype);

static struct tab_view aif_csta_table[8]={
	{NO_EXIST},
	{
		EXIST, OID_OFFSET, 1, 
		(void *)findnext_quater, NULL, 
		get_aif_csta,
		{1, 2, 0}
	},
	{
		EXIST, OID_OFFSET, 1, 
		(void *)findnext_quater, NULL, 
		get_aif_csta,
		{1, 2, 0}
	},
	{
		EXIST, OID_OFFSET, 1, 
		(void *)findnext_quater, NULL, 
		get_aif_csta,
		{1, 2, 0}
	},
	{
		EXIST, OID_OFFSET, 1, 
		(void *)findnext_quater, NULL, 
		get_aif_csta,
		{1, 2, 0}
	},
	{
		EXIST, OID_OFFSET, 1, 
		(void *)findnext_quater, NULL, 
		get_aif_csta,
		{1, 2, 0}
	},
	{
		EXIST, OID_OFFSET, 1, 
		(void *)findnext_quater, NULL, 
		get_aif_csta,
		{1, 2, 0}
	},
	{
		EXIST, OID_OFFSET, 1, 
		(void *)findnext_quater, NULL, 
		get_aif_csta,
		{1, 2, 0}
	},
};
	
void aifg_csta_init(void)
{
	DWORD	aif_oid_prefix[20] = AIF_OID;

	inquire_getmsg(AIF_OIDLEN, aif_oid_prefix, aifg_get_resp); 
	inquire_getnextmsg(AIF_OIDLEN, aif_oid_prefix, aif_getnext_resp);

	memset(aifCSTA, 0, sizeof(aifCSTA));
}

void aifg_csta_proc(void)
{
	static int			counter = 0;
	static BYTE		flag = 0;
	struct tm		*t;
	unsigned long		l_time;

	if(counter ++ >= AIF_10SEC)
	{
		l_time = time(NULL);
		t = localtime(&l_time);
		counter = 0;
	
		if(t->tm_min % 15 < 2)	//per 15 min
		{
			if(flag == 0)
			{
				/* get csta index */
				aifCSTAInd = t->tm_hour * 4 + t->tm_min / 15;			
				/* copy the msg statistic to the csta buffer */
				memcpy(aifCSTA[aifCSTAInd].msg_stat, msg_statistics, sizeof(msg_statistics));
				aifCSTA[aifCSTAInd].timestamp = l_time;		
				/* clear msg statistic */
				memset(msg_statistics, 0, sizeof(msg_statistics));
				flag = 1;
			}
		}
		else
			flag = 0;
	}
}

u32 *findnext_quater(u32 *id)
{
	int csta_inst = aifCSTAInd;

	//CHECKME: to make sure it can run across 24 hours
	if(csta_inst > 0)
		csta_inst -= 1;
	if(*id != csta_inst)
	{
		*id = csta_inst;
		return id;
	}
	*id = 0;
	return NULL;
}

struct obj_view *gen_obj_view(struct tab_view *table, u32 *oid)
{
	struct obj_view *view = &table->view;

	view->entry = oid + table->entry_id;
	view->entry_oidlen = table->entry_id + 1;
	view->column =view->entry + 1;
	view->column_oidlen = view->entry_oidlen + 1;
	view->iid = view->column + 1;
	view->full_oidlen = view->column_oidlen + table->level;
	view->csta_pos = postion[oid[table->entry_id-1]];
	view->csta_len = cstaLen[oid[table->entry_id-1]];
	return view;
}

struct tab_view *lookup_csta_table(BYTE oidlen, DWORD *oid)
{
	int index;
	
	if(oidlen < AIF_OIDLEN +2)
		return NULL;

	index = oid[AIF_OIDLEN];
	if(index >= 8)
		return NULL;
	else if(aif_csta_table[index].exist_flag == 0)
		return NULL;
	else
		return &aif_csta_table[index];
}

void aifg_encode_csta(BYTE *pData, BYTE pos, BYTE Len, aifg_csta *pCsta)
{
	unsigned long		*pDW = (unsigned long *)pData;
	int				*pSrc = (int *)&pCsta->msg_stat[2];
	int				*pDst = (int *)(pData + 4);
	int				i;

	pDW[0] = htonl(pCsta->timestamp);
	
	for(i = 0; i < Len*2; i++)
		pDst[i] = htonl(pSrc[pos + i]);	
}

int get_aif_csta(struct obj_view *view, BYTE *pdata, BYTE *vartype)
{
	int dataLen = 0;
	int csta_inst;
	
	if((csta_inst = view->iid[0]) >= 96)
		return -1;
	switch(*(view->column))
	{
		case 1:
			*((int *)pdata) = htonl(csta_inst); 
			*vartype = 0x02; 
			dataLen = 4; 
			break;
		case 2:
			if(aifCSTA[csta_inst].timestamp == 0)
				return 0;
		    *vartype = 0x04;
			aifg_encode_csta(pdata,view->csta_pos, view->csta_len, &aifCSTA[csta_inst]);
			dataLen = (view->csta_len*sizeof(int)*2+4);
			break;
	}
	return dataLen;
}


int aifg_get_resp(BYTE oidlen, DWORD *oid, BYTE *pdata, BYTE *vartype)
{
	struct tab_view *table;
	struct obj_view *view;

	if((table = lookup_csta_table(oidlen, oid)) == NULL)
		return -1;
	view = gen_obj_view(table, oid);
	if(oidlen != view->full_oidlen)
		return -1;
	if(*(view->entry) != 1)
		return -1;
	if(table->get_aif_csta == NULL)
		return -1;
	else
		return table->get_aif_csta(view, pdata, vartype);
}


static int get_nextOid(u8 *oidlen, u32 *oid)
{
	struct tab_view *table;
	struct obj_view *view;
		
	if((table = lookup_csta_table(*oidlen, oid)) == NULL)
		return 0;
	view = gen_obj_view(table, oid);
	if(*oidlen < view->full_oidlen)
	{
		memset(&oid[*oidlen], 0, view->full_oidlen-*oidlen);
		if(*oidlen < view->entry_oidlen)
			*view->entry = 1;
		if(*oidlen < view->column_oidlen)
			*view->column = table->next_column[0];
		if(*oidlen == view->full_oidlen-1)
		{
			*oidlen = view->full_oidlen;
		}
		*oidlen = view->full_oidlen;
	}
	
	for(; *(view->column) != 0; *(view->column) = table->next_column[*(view->column)])
	{
		switch(table->level)
		{
			case 1:
				if(table->lookup_1(view->iid) != NULL)
					return 1;
				break;
			case 2:
				break;
			case 3:
				break;
		}
	}
	return 0;
}

int aif_getnext_resp(u8 prev_oidlen, u32 *prev_oid, u8 *oidlen, u32 *oid, u8 *pdata, u8 *vartype)
{
	memcpy(oid, prev_oid, prev_oidlen*sizeof(u32));
	*oidlen = prev_oidlen;

	if(get_nextOid(oidlen, oid))
	{
		return aifg_get_resp(*oidlen, oid, pdata, vartype);
	}
	else
		return -1;
}

