/*
 * Note: this file originally auto-generated by mib2c using
 *  : mib2c.iterate.conf 15999 2007-03-25 22:32:02Z dts12 $
 */
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "opRxInputTable.h"

#include "../product_common/snmp_ipc_interfaceTC.h"
#define DBGTOKEN  "opRxInputTable"

#define MAX_STRING_SIZE 32
typedef struct {
    long            InputIndex;
#if defined(CONFIG_ZBL_SNMP)
	long            InputPower;
#else
    char            InputPower[MAX_STRING_SIZE];
#endif
    long           	InputWavelengthControl;
    long            InputStatus;

}snmp_RxInput_t;
snmp_RxInput_t g_RxInputInfo;


#define HC_DEFAULT_COMMIT_DELAY 1   //???

LOCAL_COMMIT_DECLARE();

#define RxInput_local_commit(x)  LOCAL_COMMIT(HC_DEFAULT_COMMIT_DELAY, opRxInputTable_commit, (void *)(x))


/** Initializes the opRxInputT module */
void
init_opRxInputTable(void)
{
    /*
     * here we initialize all the tables we're planning on supporting 
     */
    initialize_table_opRxInputTable();
}



/** Initialize the opRxInputTable table by defining its contents and how it's structured */
void
initialize_table_opRxInputTable(void)
{
    static oid      opRxInputTable_oid[] =
        { 1, 3, 6, 1, 4, 1, 17409, 1, 9, 3 };
    size_t          opRxInputTable_oid_len =
        OID_LENGTH(opRxInputTable_oid);
    netsnmp_handler_registration *reg;
    netsnmp_iterator_info *iinfo;
    netsnmp_table_registration_info *table_info;
#if defined(CONFIG_ZBL_SNMP)
	g_RxInputInfo.InputIndex = 1;
	g_RxInputInfo.InputPower = 0;
#else
	g_RxInputInfo.InputIndex = 0;
	strncpy(g_RxInputInfo.InputPower, "N/A", sizeof(g_RxInputInfo.InputPower));
#endif	
	g_RxInputInfo.InputStatus = 0;
	g_RxInputInfo.InputWavelengthControl = 0;
	
    reg =
        netsnmp_create_handler_registration("opRxInputTable",
                                            opRxInputTable_handler,
                                            opRxInputTable_oid,
                                            opRxInputTable_oid_len,
                                            HANDLER_CAN_RWRITE);

    table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
    netsnmp_table_helper_add_indexes(table_info, ASN_INTEGER,   /* index: dorInputIndex */
                                     0);
    table_info->min_column = COLUMN_DORINPUTINDEX;
    table_info->max_column = COLUMN_DORINPUTSTATUS;

    iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
    iinfo->get_first_data_point = opRxInputTable_get_first_data_point;
    iinfo->get_next_data_point = opRxInputTable_get_next_data_point;
    iinfo->table_reginfo = table_info;

    netsnmp_register_table_iterator(reg, iinfo);

    netsnmp_inject_handler( reg,
		    netsnmp_get_cache_handler(HC_CACHE_TIMEOUT,
			   		opRxInputTable_load, opRxInputTable_free,
					opRxInputTable_oid, OID_LENGTH(opRxInputTable_oid)));
    DEBUGMSGTL((DBGTOKEN,
                "initialize opRxInputTable\n"));     
	
    /*
     * Initialise the contents of the table here 
     */
}

    /*
     * Typical data structure for a row entry 
     */
struct opRxInputTable_entry {
    /*
     * Index values 
     */
    long            dorInputIndex;

    /*
     * Column values 
     */
#if defined(CONFIG_ZBL_SNMP)
    long            dorInputPower;
#else
	char            dorInputPower[MAX_STRING_SIZE];
#endif
    long            dorInputWavelengthControl;
    long            dorInputStatus;

    /*
     * Illustrate using a simple linked list 
     */
    int             valid;
	u_long 			row_updates;
	long 			value_bottom, value_top;
	int 			type, RxIput_id;
	u_long 			event_value;
    struct opRxInputTable_entry *next;
};


struct opRxInputTable_entry *opRxInputTable_head;
struct opRxInputTable_entry *opRxInputTable_commit_head;

/*
 * create a new row in the (unsorted) table 
 */
struct opRxInputTable_entry *
opRxInputTable_createEntry(struct opRxInputTable_entry *opRxInputTable)
{
    struct opRxInputTable_entry *entry;

    entry = SNMP_MALLOC_TYPEDEF(struct opRxInputTable_entry);
    if (!entry)
        return NULL;

    memcpy(entry, opRxInputTable, sizeof(*entry));
    entry->next = opRxInputTable_head;
    opRxInputTable_head = entry;
    return entry;
}

/*
 * remove a row from the table 
 */
void
opRxInputTable_removeEntry(struct opRxInputTable_entry *entry)
{
    struct opRxInputTable_entry *ptr, *prev;

    if (!entry)
        return;                 /* Nothing to remove */

    for (ptr = opRxInputTable_head, prev = NULL;
         ptr != NULL; prev = ptr, ptr = ptr->next) {
        if (ptr == entry)
            break;
    }
    if (!ptr)
        return;                 /* Can't find it */

    if (prev == NULL)
        opRxInputTable_head = ptr->next;
    else
        prev->next = ptr->next;

    SNMP_FREE(entry);           /* XXX - release any other internal resources */
}


void opRxInputTable_removeAllEntry(void )
{
    struct opRxInputTable_entry *ptr, *pnext;

    for (ptr = opRxInputTable_head; ptr != NULL; ptr = pnext) {
		 pnext = ptr->next;
		 SNMP_FREE(ptr); 
    }
	opRxInputTable_head = NULL;
}


void opRxInputTable_setEntry(
				struct opRxInputTable_entry *entry, 
				snmp_RxInput_t *pinfo
				)
{

	memset(entry, 0, sizeof(*entry));
	
	entry->dorInputIndex = pinfo->InputIndex;
	#if defined(CONFIG_ZBL_SNMP)
	entry->dorInputPower = pinfo->InputPower;
	#else
	strncpy(entry->dorInputPower, pinfo->InputPower, sizeof(entry->dorInputPower));
	#endif
	entry->dorInputStatus =pinfo->InputStatus;
	entry->dorInputWavelengthControl = pinfo->InputWavelengthControl;
}



struct opRxInputTable_entry *
opRxInputTable_backupCommitEntry(struct opRxInputTable_entry *opRxInputTable)
{
    struct opRxInputTable_entry *entry, *next;

	#if 1
	/*
    	for (entry = opRxInputTable_commit_head; entry != NULL; entry = entry->next) {
		if ((entry->analogAlarmParameterOID_len == opRxInputTable->analogAlarmParameterOID_len)
			&& !memcmp(entry->analogAlarmParameterOID, opRxInputTable->analogAlarmParameterOID, entry->analogAlarmParameterOID_len)){
			break;
		}		
    	}	
    */
    for(entry = opRxInputTable_commit_head; entry != NULL; entry = entry->next) 
    {	
    	if(entry->dorInputIndex == opRxInputTable->dorInputIndex)  //??
    	{
    		break;
    	}
    }
    
	#endif
	
	
	if (!entry){
		entry = SNMP_MALLOC_TYPEDEF(struct opRxInputTable_entry);
		if (!entry)
			return NULL;
		entry->next = opRxInputTable_commit_head;
		opRxInputTable_commit_head = entry;
	}

	
	next = entry->next;
	memcpy(entry, opRxInputTable, sizeof(*entry));
	entry->next = next;
	
    return entry;	
}


void opRxInputTable_removeAllCommitEntry(void )
{
    struct opRxInputTable_entry *ptr, *pnext;

    for (ptr = opRxInputTable_commit_head; ptr != NULL; ptr = pnext) {
		 pnext = ptr->next;
		 SNMP_FREE(ptr); 
    }
	opRxInputTable_commit_head = NULL;
}



/*
 * Example iterator hook routines - using 'get_next' to do most of the work 
 */
netsnmp_variable_list *
opRxInputTable_get_first_data_point(void **my_loop_context,
                                    void **my_data_context,
                                    netsnmp_variable_list * put_index_data,
                                    netsnmp_iterator_info *mydata)
{
    *my_loop_context = opRxInputTable_head;
    return opRxInputTable_get_next_data_point(my_loop_context,
                                              my_data_context,
                                              put_index_data, mydata);
}

netsnmp_variable_list *
opRxInputTable_get_next_data_point(void **my_loop_context,
                                   void **my_data_context,
                                   netsnmp_variable_list * put_index_data,
                                   netsnmp_iterator_info *mydata)
{
    struct opRxInputTable_entry *entry =
        (struct opRxInputTable_entry *) *my_loop_context;
    netsnmp_variable_list *idx = put_index_data;

    if (entry) {
        snmp_set_var_typed_integer(idx, ASN_INTEGER, entry->dorInputIndex);
        idx = idx->next_variable;
        *my_data_context = (void *) entry;
        *my_loop_context = (void *) entry->next;
        return put_index_data;
    } else {
        return NULL;
    }
}


/** handles requests for the opRxInputTable table */
int
opRxInputTable_handler(netsnmp_mib_handler *handler,
                       netsnmp_handler_registration *reginfo,
                       netsnmp_agent_request_info *reqinfo,
                       netsnmp_request_info *requests)
{

    netsnmp_request_info *request;
    netsnmp_table_request_info *table_info;
    struct opRxInputTable_entry *table_entry;
	int ret;

    if (((reqinfo->mode == MODE_GET) /*|| (reqinfo->mode == MODE_SET_ACTION)*/) 
		&& !netsnmp_cache_is_valid(reqinfo, reginfo->handlerName)) {
        //netsnmp_assert(!"cache == valid"); /* always false */
        opRxInputTable_load( NULL, NULL );	/* XXX - check for failure */
    }

    DEBUGMSGTL((DBGTOKEN, "Handler - mode %s\n",
                    se_find_label_in_slist("agent_mode", reqinfo->mode)));

    switch (reqinfo->mode) {
        /*
         * Read-support (also covers GetNext requests)
         */
    case MODE_GET:
        for (request = requests; request; request = request->next) {
            table_entry = (struct opRxInputTable_entry *)
                netsnmp_extract_iterator_context(request);
            table_info = netsnmp_extract_table_info(request);

            switch (table_info->colnum) {
            case COLUMN_DORINPUTINDEX:
                if (!table_entry) {
                    netsnmp_set_request_error(reqinfo, request,
                                              SNMP_NOSUCHINSTANCE);
                    continue;
                }
                snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
                                           table_entry->dorInputIndex);
                break;
            case COLUMN_DORINPUTPOWER:
                if (!table_entry) {
                    netsnmp_set_request_error(reqinfo, request,
                                              SNMP_NOSUCHINSTANCE);
                    continue;
                }
			#if defined(CONFIG_ZBL_SNMP)
				snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
                                           table_entry->dorInputPower);
			#else
			    snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
                                         table_entry->dorInputPower,
                                         strlen(table_entry->dorInputPower));
			#endif
                break;
			#if !defined(CONFIG_ZBL_SNMP)
            case COLUMN_DORINPUTWAVELENGTHCONTROL:
                if (!table_entry) {
                    netsnmp_set_request_error(reqinfo, request,
                                              SNMP_NOSUCHINSTANCE);
                    continue;
                }
                snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
                                           table_entry->dorInputWavelengthControl);
                break;
            case COLUMN_DORINPUTSTATUS:
                if (!table_entry) {
                    netsnmp_set_request_error(reqinfo, request,
                                              SNMP_NOSUCHINSTANCE);
                    continue;
                }
                snmp_set_var_typed_integer(request->requestvb, ASN_INTEGER,
                                           table_entry->dorInputStatus);
                break;
			#endif
            default:
                netsnmp_set_request_error(reqinfo, request,
                                          SNMP_NOSUCHOBJECT);
                break;
            }
        }
        break;

        /*
         * Write-support
         */
    case MODE_SET_RESERVE1:
        for (request = requests; request; request = request->next) {
            table_entry = (struct opRxInputTable_entry *)
                netsnmp_extract_iterator_context(request);
            table_info = netsnmp_extract_table_info(request);

            switch (table_info->colnum) {
            case COLUMN_DORINPUTWAVELENGTHCONTROL:
                /*
                 * or possibly 'netsnmp_check_vb_int_range' 
                 */
                ret = netsnmp_check_vb_int(request->requestvb);
                if (ret != SNMP_ERR_NOERROR) {
                    netsnmp_set_request_error(reqinfo, request, ret);
                    return SNMP_ERR_NOERROR;
                }
                break;
            default:
                netsnmp_set_request_error(reqinfo, request,
                                          SNMP_ERR_NOTWRITABLE);
                return SNMP_ERR_NOERROR;
            }
        }
        break;

    case MODE_SET_RESERVE2:
        break;

    case MODE_SET_FREE:
        break;

    case MODE_SET_ACTION:
        for (request = requests; request; request = request->next) {
            table_entry = (struct opRxInputTable_entry *)
                netsnmp_extract_iterator_context(request);
            table_info = netsnmp_extract_table_info(request);

            switch (table_info->colnum) {
            case COLUMN_DORINPUTWAVELENGTHCONTROL:
                table_entry->dorInputWavelengthControl =
                    *request->requestvb->val.integer;
				table_entry->row_updates |= (1 << table_info->colnum);
                break;
            }
        }
        break;

    case MODE_SET_UNDO:
        for (request = requests; request; request = request->next) {
            table_entry = (struct opRxInputTable_entry *)
                netsnmp_extract_iterator_context(request);
            table_info = netsnmp_extract_table_info(request);

            switch (table_info->colnum) {
            case COLUMN_DORINPUTWAVELENGTHCONTROL:
                table_entry->dorInputWavelengthControl = 0;
                break;
            }
        }
        break;

    case MODE_SET_COMMIT:
		for (table_entry = opRxInputTable_head; table_entry; table_entry = table_entry->next){
			if (table_entry->row_updates) {
				DEBUGMSGTL((DBGTOKEN, "opRxInputTable backup CommitEntry (%d)\n", table_entry->RxIput_id));
                opRxInputTable_backupCommitEntry(table_entry);				
			}	
		}		
		
		RxInput_local_commit(netsnmp_cache_reqinfo_extract(reqinfo, reginfo->handlerName));		
        break;	
    }
    return SNMP_ERR_NOERROR;
}


int opRxInputTable_load(netsnmp_cache *cache, void *vmagic)
{
	struct opRxInputTable_entry entry;
	int ret = 0;
	int i =0;
	snmp_RxInput_t *pinfo = NULL;
	int RxInput_num = 0;

	char val[MAX_CATVINFO_SIZE] = {0};

	COMMIT_PENDING_ASSERT();

	/* Free All */

	opRxInputTable_removeAllEntry();

	/* Load All */
	RxInput_num = 1;
	/*alarms_num =ipc_snmp_alarm_num(&agent)*/
	if (RxInput_num == 0){
		DBG_ASSERT(0, "RxInput num is 0");
		return 0;
	}

	pinfo = &g_RxInputInfo;

	#if defined(CONFIG_CATVCOM) 
	catvinfo_t *info = NULL;
	ipc_catvinfo_ack_t *pack = NULL;
	pack = ipc_catv_config(ipc_fd, IPC_CONFIG_GET, IPC_APPLY_NONE, NULL);
	if(pack && pack->hdr.status == IPC_STATUS_OK) 
	{		
		info = &pack->catvinfo;
		#if defined(CONFIG_ZBL_SNMP)
		pinfo->InputPower = info->input_laser_power_mw;
		#else
		strncpy(pinfo->InputPower, info->input_laser_power, sizeof(info->input_laser_power));
		#endif
		if(pack)
		{
			free(pack);
		}
	}
	else
	{	
		if(pack)
		{
			free(pack);
		}		
		DEBUGMSGTL((DBGTOKEN,"snmp get input_laser_power from master fail!\n"));
		return SNMP_ERR_GENERR;
	}
	#endif
	
	for (i = 0; i < RxInput_num; i ++)
	{
		opRxInputTable_setEntry(&entry, &pinfo[i]);	
		opRxInputTable_createEntry(&entry);	
	}

safe_exit:
	
	HC_IPC_ASSERT(ret);
	
    return ret; 
} 


void opRxInputTable_free(netsnmp_cache *cache, void *magic)
{
	DEBUGMSGTL((DBGTOKEN, "Free opRxInputTable Group\n"));  
}

static int opRxInputTable_checkEntry(struct opRxInputTable_entry *ptr)
{
	if (ptr){
		if (ptr->value_bottom < ptr->value_top){
			if ((ptr->value_bottom <= ptr->dorInputStatus)
				&& (ptr->dorInputStatus <= ptr->dorInputWavelengthControl)
				/*&& (ptr->dorInputWavelengthControl <= ptr->dorInputPower)*/){
				return 1;
			}
		}else {
			if ((ptr->value_top <= ptr->dorInputWavelengthControl)
				/*&& (ptr->dorInputPower <= ptr->dorInputWavelengthControl)*/
				&& (ptr->dorInputWavelengthControl <= ptr->dorInputStatus)
				&& (ptr->dorInputStatus <= ptr->value_bottom)){
				return 1;
			}
		}
	}
	return 0;
}

static int opRxInputTable_commitChange(void)
{
	int ret = 0, count;
	struct opRxInputTable_entry *ptr;
	snmp_RxInput_t *req_RxInput = NULL, *sa;

	count = 0;
	for (ptr = opRxInputTable_commit_head; ptr != NULL; ptr = ptr->next) {
		count ++;
	}

	if (count == 0){
		return 0;
	}

	req_RxInput = (snmp_RxInput_t *)malloc(sizeof(snmp_RxInput_t) * count);

	if (req_RxInput == NULL){
		DBG_ASSERT(0, "malloc(%d)", sizeof(snmp_RxInput_t) * count);
		return 0;
	}

	memset(req_RxInput, 0, sizeof(snmp_RxInput_t) * count);

	sa = &g_RxInputInfo;
	count = 0;
	for ( ptr = opRxInputTable_commit_head; ptr != NULL; ptr = ptr->next) {

		if (!opRxInputTable_checkEntry(ptr)){
			DBG_ASSERT(0, "opRxInputTable values disorder");
		}
		/*
		sa->InputIndex = ptr->dorInputIndex;
		strncpy(sa->InputPower, ptr->dorInputPower, sizeof(sa->InputPower));
		sa->InputStatus = ptr->dorInputStatus;
		sa->InputWavelengthControl = ptr->dorInputWavelengthControl;
		*/
		sa ++;
		count ++;
	}
	#if 0
	if (count){
		ret = ipc_snmp_alarm_set(&agent, req_RxIput, count);
	}
	#endif
	if (req_RxInput) free(req_RxInput);

	HC_IPC_ASSERT(ret);
	return ret;
}



void opRxInputTable_commit(unsigned int regNo, void *clientargs)
{
	netsnmp_cache  *cache = clientargs;
	
	opRxInputTable_commitChange();	
	
	opRxInputTable_removeAllCommitEntry();
	
	COMMIT_CLEAR_PENDING(); 	

	if (cache){
		cache->valid = 0;
	}
}



