#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/agent/hardware/memory.h>
#include <net-snmp/net-snmp-features.h>
#include "hw_mem.h"

netsnmp_feature_child_of(hardware_memory, netsnmp_unused);

netsnmp_feature_child_of(memory_get_cache, hardware_memory);

netsnmp_memory_info *_mem_head  = NULL;
netsnmp_cache       *_mem_cache = NULL;

#ifdef darwin
/* the code in memory_darwin.c is *very* expensive */
#define	MEMORY_CACHE_SECONDS	300
#else
#define	MEMORY_CACHE_SECONDS	5
#endif

void init_hw_mem( void ) {
    oid nsMemory[] = { 1, 3, 6, 1, 4, 1, 8072, 1, 31 };
    _mem_cache = netsnmp_cache_create( MEMORY_CACHE_SECONDS, netsnmp_mem_arch_load, NULL,
                                          nsMemory, OID_LENGTH(nsMemory));
}



netsnmp_memory_info *netsnmp_memory_get_first( int type ) {
    netsnmp_memory_info *mem;

    for ( mem=_mem_head; mem; mem=mem->next )
        if (mem->type == type)    /* Or treat as bits? */
            return mem;
    return NULL;
}

netsnmp_memory_info *netsnmp_memory_get_next( netsnmp_memory_info *this_ptr, int type ) {
    netsnmp_memory_info *mem;

    if (this_ptr)
        for ( mem=this_ptr->next; mem; mem=mem->next )
            if (mem->type == type)    /* Or treat as bits? */
                return mem;
    return NULL;
}

    /*
     * Work with a list of Memory entries, indexed numerically
     */
netsnmp_memory_info *netsnmp_memory_get_byIdx(  int idx, int create ) {
    netsnmp_memory_info *mem, *mem2;

        /*
         * Find the specified Memory entry
         */
    for ( mem=_mem_head; mem; mem=mem->next ) {
        if ( mem->idx == idx )
            return mem;
    }
    if (!create)
        return NULL;

        /*
         * Create a new memory entry, and insert it into the list....
         */
    mem = SNMP_MALLOC_TYPEDEF( netsnmp_memory_info );
    if (!mem)
        return NULL;
    mem->idx = idx;
        /* ... either as the first (or only) entry....  */
    if ( !_mem_head || _mem_head->idx > idx ) {
        mem->next = _mem_head;
        _mem_head = mem;
        return mem;
    }
        /* ... or in the appropriate position  */
    for ( mem2=_mem_head; mem2; mem2=mem2->next ) {
        if ( !mem2->next || mem2->next->idx > idx ) {
            mem->next  = mem2->next;
            mem2->next = mem;
            return mem;
        }
    }
    SNMP_FREE(mem);
    return NULL;  /* Shouldn't happen! */
}

netsnmp_memory_info *netsnmp_memory_get_next_byIdx( int idx, int type ) {
    netsnmp_memory_info *mem;

    for ( mem=_mem_head; mem; mem=mem->next )
        if (mem->type == type && mem->idx > idx)    /* Or treat as bits? */
            return mem;
    return NULL;
}



#ifndef NETSNMP_FEATURE_REMOVE_MEMORY_GET_CACHE
netsnmp_cache *netsnmp_memory_get_cache( void ) {
    return _mem_cache;
}
#endif /* NETSNMP_FEATURE_REMOVE_MEMORY_GET_CACHE */

int netsnmp_memory_load( void ) {
     return netsnmp_cache_check_and_reload( _mem_cache );
}
