#if HAVE_CONFIG_H
#include <ntm_conf.h>
#endif

#include <stdlib.h>
#include <stdio.h>
#include <memory.h>                 /* memset() */
#include "../types/types.h"
#include "../integrat/readbgp.h"
#include "../integrat/subnet.h"
#include "../wattcp/tcp.h"          /* inet_addr() inet_ntoa() */
#include "../dpmi32/flat.h"
#include "../intel/byteswap.h"      /* ntohl() htonl() */



#define MAX_ADDRESS_LENGTH         1000
#define MAX_AS                     65535



Bit32 *exit_as_subnets;
Bit32 *src_as_subnets;



/* called by WalkSubnetsRecurse twice per routing,
 * once before recursion and once after
 *
 * returns TRUE if successful, FALSE if failure
 * (FALSE causes recursion to stop)
 *
 * never fails because it doesn't use up any resource
 * (wouldn't get called if arrays couldn't be allocated)
 *
 * uses global variables instead of the argument pointer
 * that PrintSubnetsHelper() in SUBNET.C uses
 */
#pragma warn -par
static boolean accumulate_as_helper( boolean is_before, Subnet *external, void *unused_args )
{
    /* only do add up the array once per routing table line
     */
    if( !is_before )
    {
        exit_as_subnets[ external->exit_as ]++;
        src_as_subnets[ external->src_as ]++;
    }

    return TRUE;
}
#pragma warn .par



void accumulate_as_stats( void )
{
    boolean result;
    Bit32 count;
    Bit32 used;

    /* allocate the arrays
     */
    exit_as_subnets = (Bit32 *) flat_alloc( sizeof(Bit32)*MAX_AS );
    if( !exit_as_subnets )
    {
        fprintf( stderr, "cannot allocate exit AS counters\n" );
        return;
    }

    src_as_subnets = (Bit32 *) flat_alloc( sizeof(Bit32)*MAX_AS );
    if( !src_as_subnets )
    {
        fprintf( stderr, "cannot allocate exit AS counters\n" );
        flat_free( exit_as_subnets );
        return;
    }

    /* initialize all counters to zero
     */
    memset( exit_as_subnets, 0, sizeof(Bit32)*MAX_AS );
    memset( src_as_subnets, 0, sizeof(Bit32)*MAX_AS );

    /* walk the radix trie and fill in both arrays
     */
    result = WalkSubnets( accumulate_as_helper, NULL );
    if( !result )
    {
        fprintf( stderr, "couldn't walk radix trie\n" );
        flat_free( src_as_subnets );
        flat_free( exit_as_subnets );
        return;
    }

    /* print out the counts of routing table lines per exit AS
     */
    fprintf( stdout, "\nexit AS : count of preferred subnets\n" );
    used = 0;
    for( count=0; count<MAX_AS; count++ )
        if( exit_as_subnets[ count ] )
        {
            fprintf( stdout, "e:%u:%u\n", count, exit_as_subnets[count] );
            used++;
        }
    fprintf( stdout, "total: %u exit AS's\n", used );

    /* print out the counts of routing table lines per source AS
     */
    fprintf( stdout, "\nsource AS : count of preferred subnets\n" );
    used = 0;
    for( count=0; count<MAX_AS; count++ )
        if( src_as_subnets[ count ] )
        {
            fprintf( stdout, "s:%u:%u\n", count, src_as_subnets[count] );
            used++;
        }
    fprintf( stdout, "total: %u source AS's\n", used );

    /* clean up
     */
    flat_free( src_as_subnets );
    flat_free( exit_as_subnets );
}



int main( int argc, char *argv[] )
{
    int result;
    Subnet *my_subnet;
    Bit32 my_address;
    char my_address_string[ MAX_ADDRESS_LENGTH + 1 ];
    char temp[ 20 ];

    /* check args */
    if( argc!=2 || argv[1][0]==0 )
    {
        printf( "usage: %s bgp-file-from-router\n", argv[0] );
        return ERROR_READBGP_BAD_PARMS;
    }

    /* initialize access to flat memory
     */
    flat_init( TRUE );

    /* initialize the subnet module
     */
    InitSubnet();

    result = read_bgp_file( argv[1] );
    if( result )
        return result;

    //    accumulate_as_stats();

    //    ShowSubnetStatistics();

    /* read an IP address in dotted decimal from stdin
     * until we hit EOF
     */
    while( fgets( my_address_string, MAX_ADDRESS_LENGTH, stdin ) )
    {
        /* convert the dotted-decimal string into binary
         */
        my_address = inet_addr( my_address_string );

        /* find the subnet record that corresponds to the IP address
         */
        my_subnet = FindSubnet( htonl( my_address ) );
        if( !my_subnet )
        {
            fprintf( stdout, "IP=%s not found in routing table\n", inet_ntoa(temp,my_address) );
            continue;
        }

        /* fprintf( stdout, "IP=%s ", inet_ntoa(temp,my_address) ); */
        /* fprintf( stdout, "line=%d ", my_subnet->line); */
        fprintf( stdout, "net=%s/%d ", inet_ntoa(temp,ntohl(my_subnet->addr)), bits_in_mask(my_subnet->mask) );
        /* fprintf( stdout, "mask=%s ", inet_ntoa(temp,ntohl(my_subnet->mask)) ); */
        fprintf( stdout, "nexthop_ip=%s ", inet_ntoa(temp,my_subnet->nexthop_addr) );
        /* fprintf( stdout, "exit_as=%d source_as=%d ", my_subnet->exit_as, my_subnet->src_as ); */
        fprintf( stdout, "AS_path='%s' IP=%s", 
#if !NF_OCX_BGP
        my_subnet->as_path,
#else
        "<<path>>",
#endif
        my_address_string );
    }

    return 0;
}
