/*
 *  * Copyright (c) 2007 Endace Technology Ltd, Hamilton, New Zealand.
 ** All rights reserved.
 **
 ** This source code is proprietary to Endace Technology Limited and no part
 ** of it may be redistributed, published or disclosed except as outlined in
 ** the written contract supplied with this product.
 **
 ** 
 **/

/*headers */
#include "dag_config_api.h"
#include "dag_platform.h"
#include "dag_romutil.h"

char *read_write_table[4] = {"Unknown","Status","Config","ConfigStatus"};
#include <string.h>

#define MAX_LEN 256
#define SEP "/"

/* Macros */
#define DAGNAME "dag0"
#define NO_OF_CONNECTIONS 11


/* tokens initializtions */
static char dag_name[64]="dag0";
static direction_t cur_direction = kDirectionReceive;
static  int mode_value = -1;
static int term_value = -1;
static bool is_eql = false;
static bool is_fcl = false;
static bool enable_eql = false;
static bool enable_fcl = false;
static bool is_display_attributes = true;
static bool delete_all = false;
static bool print_tree = false;
static bool create_connections = false;
static int no_of_connections = 1;
static  int link_value = 16;/* 16 to represent all the ports 0 - 15*/
static bool clear_framer = false;
static bool reset_framer = false;
static bool set_default = false;
static int mem_stream1 = 0;
static int mem_stream2 = 0;

/* funtion declarations */
void print_subtree(dag_card_ref_t card_ref, dag_component_t cur_comp, int depth,char *leader, bool is_attr, attr_uuid_t in_attr);
bool add_connection(dag_card_ref_t card_ref);/* hardcorderd values as per the connections in the ERF file */
bool delete_all_connections(dag_card_ref_t card_ref);/* delete alll the connection on the card_ref */
bool set_mode_term(dag_card_ref_t card_ref);
bool set_fcl_eql( dag_card_ref_t card_ref );
bool reset_clear_framer (dag_card_ref_t card_ref);
bool set_linetype_E1( dag_card_ref_t card_ref );
bool set_memory_partition( dag_card_ref_t card_ref );

char* tx_or_rc( direction_t dir)
{ 
        return (dir == kDirectionReceive ) ? "rx" : "tx" ;
}

int get_from_string( char *in_string )
{
    char *int_string = NULL ;
    char *result = NULL;
    result = strtok ( in_string,"=");
    while ( NULL != result )  
    {
        int_string = result;
        result= strtok(NULL, "=" );
    }
    if (  int_string )
        return atoi( int_string);
    else 
        return  -1;
         
}
/*bool get_mem_from_string( char *in_string, int *mem1, int *mem2)
{
}*/

int main( int argc, char **argv)
{
    dag_card_ref_t card_ref;
    dag_component_t root_component = 0;

    /* process the input paramters to the program */
    if ( argc > 1 )
    {
        int index = 1;
        for ( ; index < argc; index++)
        {
            if ( !strcmp("--help" , argv[index] ) )
                            {
                            printf("Usage: %s dag=<dag0/dag1> <create> dir=<tx/rx> <deleteall> <printtree> <link=> <mode=> <term=> <mem1=> <mem2=> <[no]fcl> <[no>eql> \n",argv[0]);
                            return 1;
                            }
            else if ( ! strcmp("deleteall",argv[index] ))
            {
                    delete_all = true;
                    create_connections = false;
            }
            else if ( ! strcmp("printtree",argv[index] ))
            {
                    create_connections = false;
                    print_tree = true;
            }
            else if ( !strcmp(argv[index],"noattrib"))
            {
                is_display_attributes = false;                    
            }
            else if ( !strcmp(argv[index], "create")) 
            {
                    create_connections =true;
            }

            else if ( !strcmp("dag=dag0",argv[index]) )
                   /* if (!strcmp("dag1", argv[index]))*/ strcpy (dag_name,"dag0");
            else if ( !strcmp("dag=dag1",argv[index]) )
                   /* if (!strcmp("dag1", argv[index]))*/ strcpy (dag_name,"dag1");
            else if ( !strcmp("dir=tx",argv[index]) )
                   /* if ( !strcmp("tx",argv[index])) */  cur_direction = kDirectionTransmit; 
            else if ( strstr( argv[index], "link=" ))
                link_value = get_from_string( argv[index]);
            else if ( strstr( argv[index], "mode=")  )
                mode_value = get_from_string( argv[index]);
            else if ( strstr( argv[index],  "term=" ) )
                term_value = get_from_string(argv[index] );
            else if ( ! strcmp (argv[index] , "eql" ))
            {
                    is_eql = true;
                    enable_eql = true;
            }
            else if ( ! strcmp( argv[index], "fcl" ))
            {
                    is_fcl = true;
                    enable_fcl = true;
            }
            else if ( ! strcmp (argv[index] , "noeql" ))
            {
                    is_eql = true;
                    enable_eql = false;
            }
            else if ( ! strcmp( argv[index], "nofcl" ))
            {
                    is_fcl = true;
                    enable_fcl = false;
            }
            else if( !strcmp(argv[index], "clear" ))
            {
                clear_framer = true;
            }
            else if( !strcmp(argv[index], "reset" ))
            {
                reset_framer = true;
            }
            else if ( !strcmp( argv[index],"default" ))
            {
                set_default = true;
            }
            else if( strstr( argv[index],"mem1=") )
            {
               mem_stream1 = get_from_string( argv[index]);
            } 
            else if( strstr( argv[index],"mem2=") )
            {
               mem_stream2 = get_from_string( argv[index]);
            }
            else if ( strstr (argv[index] ,"connections=" ) )
            {
                no_of_connections = get_from_string(argv[index]);
            }
            else 
            {
                printf("Invalid option %s. No space please.. Please try --help\n",argv[index]);
                return 1;
            }
        }

    }
    else
    {
            printf ("Use %s --help \n", argv[0]);
            return 1;
    }

    card_ref = dag_config_init(dag_name);
    if (card_ref == NULL)
    {
        printf("No card\n");
        return EXIT_FAILURE;
    }
    printf("*************** DAG : %s ********************\n",dag_name);

    if ( set_default )
    {
        printf("Setting default config....\n");
        set_linetype_E1(card_ref);
        mode_value = 0;
        term_value = 1;
        set_mode_term(card_ref);
        enable_fcl = false;
        enable_eql = false;
        is_fcl = true;
        is_eql  = true;
        set_fcl_eql(card_ref);
        mem_stream1 = 112;
        mem_stream2 = 16;
        set_memory_partition(card_ref);
        return 1;
    }
    if ( mem_stream1 && mem_stream2 )
    {
        printf("Memory %d %d \n", mem_stream1, mem_stream2);
        printf( "Setting up Memory ...\n");
        set_memory_partition(card_ref );
    }
    if ( -1 != mode_value || -1 != term_value )
    {
        printf(" Setting mode and term\n");            
        set_mode_term(card_ref);
    }

    if ( is_fcl || is_eql )
    {
        set_fcl_eql( card_ref );
    }

    if ( reset_framer || clear_framer )
    {
        reset_clear_framer( card_ref );
    }
    if ( delete_all )
    {
            delete_all_connections( card_ref) ;
            return 0;
    }

    /* to create connections - as per the ERF file - creates the required number of connections */
   if ( create_connections )
   {
           printf("Adding connections ...\n");
           add_connection(card_ref);
   }

   if ( print_tree ) 
   {
	    dag_component_t current_component;
        root_component = dag_config_get_root_component(card_ref);
        current_component = dag_component_get_subcomponent(root_component, kComponentConnectionSetup, 0);
        if ( NULL == current_component )
        {
        printf("dag_config_get_subcomponent failed for kComponentConnectionSetup\n");
        }

        print_subtree( card_ref, root_component, 0, " ",false,0); 
   }
    return 0;   
}

bool set_memory_partition( dag_card_ref_t card_ref )
{

    dag_component_t root_component = 0;
    dag_component_t current_component = 0;
    attr_uuid_t current_attribute = 0;
    int stream_count = 0;
	root_component = dag_config_get_root_component(card_ref);

    stream_count = dag_component_get_subcomponent_count_of_type(root_component, kComponentStream);
    printf( "Stream count is %d\n", stream_count );
    //for( ; i < stream_count ; i++ )
    current_component = dag_component_get_subcomponent(root_component, kComponentStream, 0);
    if ( NULL == current_component )
    {
        printf("dag_config_get_subcomponent failed for kComponentStream \n");
        return false;
    }
    current_attribute = dag_component_get_attribute_uuid( current_component, kUint32AttributeMem);
    if( kNullAttributeUuid != current_attribute)
    {
        if ( kDagErrNone != dag_config_set_uint32_attribute( card_ref, current_attribute, mem_stream1)  )
        {
            printf("Setting memeory attribute is  failing....\n");
        }
    }
    current_component = 0;
    current_attribute = 0;

    current_component = dag_component_get_subcomponent(root_component, kComponentStream, 1);
    if ( NULL == current_component )
    {
        printf("dag_config_get_subcomponent failed for kComponentStream \n");
        return false;
    }
    current_attribute = dag_component_get_attribute_uuid( current_component, kUint32AttributeMem);
    if( kNullAttributeUuid != current_attribute)
    {
        if ( kDagErrNone != dag_config_set_uint32_attribute( card_ref, current_attribute, mem_stream2)  )
        {
            printf("Setting memeory attribute is  failing....\n");
        }
    }
    return true;
}

/* to set the default - all port ot E1 */
bool set_linetype_E1( dag_card_ref_t card_ref )
{
    dag_component_t root_component = 0;
    dag_component_t current_component = 0;
    attr_uuid_t current_attribute = 0;
    int port_count = 0;
    int i = 0;
	root_component = dag_config_get_root_component(card_ref);

    port_count =  dag_component_get_subcomponent_count_of_type(root_component, kComponentPort);
    for ( ; i < port_count; i++)
    {
        current_component = dag_component_get_subcomponent(root_component, kComponentPort, i);
        if ( NULL == current_component )
        {
            printf("dag_config_get_subcomponent failed for kComponentPort\n");
            return false;
        }
        current_attribute = dag_component_get_attribute_uuid( current_component, kUint32AttributeLineType);
        if( kNullAttributeUuid != current_attribute)
        {
            if ( kDagErrNone != dag_config_set_uint32_attribute( card_ref, current_attribute, kLineTypeE1)  )
            {
                printf("Setting Line attribute to E1 failing....\n");
            }
        }
    }
    return true;
}
/* function to set the clear and reset attributes of the framer component */
bool reset_clear_framer (dag_card_ref_t card_ref)
{
    dag_component_t root_component = 0;
    dag_component_t current_component = 0;
    attr_uuid_t current_attribute = 0;
    root_component = dag_config_get_root_component(card_ref);

    current_component = dag_component_get_subcomponent(root_component, kComponentFramer, 0);
    if ( NULL == current_component )
    {
        printf("dag_config_get_subcomponent failed for kComponentFramer\n");
        return false;
    }
    if ( reset_framer) 
    {
        printf("Resetting framer.....\n");
        current_attribute = dag_component_get_attribute_uuid( current_component, kBooleanAttributeReset);
        if( kNullAttributeUuid != current_attribute)
        {
            if ( kDagErrNone != dag_config_set_boolean_attribute( card_ref, current_attribute, reset_framer)  )
            {
                printf("Resetting framer  is failing....\n");
            }
        }
    }
    current_attribute = 0;

    if ( clear_framer )
    {
        printf("Clearing framer.....\n");
        current_attribute = dag_component_get_attribute_uuid( current_component, kBooleanAttributeClear);
        if( kNullAttributeUuid != current_attribute)
        {
            if ( kDagErrNone != dag_config_set_boolean_attribute( card_ref, current_attribute,clear_framer)  )
            {
                printf("Clearing framer is failing....\n");
            }
        }
    }
    return true;
}



/* fucntion to set the fcl and eql of port component */
bool set_fcl_eql ( dag_card_ref_t card_ref )
{
    dag_component_t root_component = 0;
    dag_component_t current_component = 0;
    attr_uuid_t current_attribute = 0;
    int port_count = 0;
    int i = 0;
    root_component = dag_config_get_root_component(card_ref);

    if ( link_value <  16 )/* for 0 - 15 only do it for the specif port */
    {       
        current_component = dag_component_get_subcomponent(root_component, kComponentPort, link_value);
        if ( NULL == current_component )
        {
            printf("dag_config_get_subcomponent failed for kComponentPort\n");
            return false;
        }
        if ( is_fcl ) 
        {
            printf("Changing fcl on ifc %d...\n",link_value);
            current_attribute = dag_component_get_attribute_uuid( current_component, kBooleanAttributeFacilityLoopback);
            if( kNullAttributeUuid != current_attribute)
            {
                if ( kDagErrNone != dag_config_set_boolean_attribute( card_ref, current_attribute, enable_fcl)  )
                {
                    printf("Setting fcl is failing....\n");
                }
            }
        }
        current_attribute = 0;

        if ( is_eql )
        {
            printf("Changing eql on ifc %d...\n",link_value );
            current_attribute = dag_component_get_attribute_uuid( current_component, kBooleanAttributeEquipmentLoopback);
            if( kNullAttributeUuid != current_attribute)
            {
                if ( kDagErrNone != dag_config_set_boolean_attribute( card_ref, current_attribute, enable_eql)  )
                {
                    printf("Setting eql  is failing....\n");
                }
            }
        }
    }
    else    /* if link_value > 15 , do for all the ports */
    {
        port_count =  dag_component_get_subcomponent_count_of_type(root_component, kComponentPort);
        for ( ; i < port_count; i++)
        {
            current_component = dag_component_get_subcomponent(root_component, kComponentPort, i);
            if ( NULL == current_component )
            {
                printf("dag_config_get_subcomponent failed for kComponentPort\n");
                return false;
            }
            if ( is_fcl ) 
            {        
                printf("Changing  fcl on ifc %d...\n",i);
                current_attribute = dag_component_get_attribute_uuid( current_component, kBooleanAttributeFacilityLoopback);
                if( kNullAttributeUuid != current_attribute)
                {
                    if ( kDagErrNone != dag_config_set_boolean_attribute( card_ref, current_attribute, enable_fcl)  )
                    {
                        printf("Setting fcl is failing....\n");
                    }
                }
            }
            current_attribute = 0;

            if ( is_eql )
            {
                printf("Changing eql on ifc %d...\n",i);
                current_attribute = dag_component_get_attribute_uuid( current_component, kBooleanAttributeEquipmentLoopback);
                if( kNullAttributeUuid != current_attribute)
                {
                    if ( kDagErrNone != dag_config_set_boolean_attribute( card_ref, current_attribute, enable_eql)  )
                    {
                        printf("Setting eql  is failing....\n");
                    }
                }
            }
        }
    }
    return true;
}

/* function to set the mode and term attributes for the ports*/ 
bool set_mode_term( dag_card_ref_t card_ref )
{
    dag_component_t root_component = 0;
    dag_component_t current_component = 0;
    attr_uuid_t current_attribute = 0;
    int port_count = 0;
    int i = 0;
    root_component = dag_config_get_root_component(card_ref);

    if ( link_value <  16 )/* for 0 - 15 only do it for the specif port */
    {       
        current_component = dag_component_get_subcomponent(root_component, kComponentPort, link_value);
        if ( NULL == current_component )
        {
            printf("dag_config_get_subcomponent failed for kComponentPort\n");
            return false;
        }
        if ( -1 != mode_value )
        {        
            current_attribute = dag_component_get_attribute_uuid( current_component, kUint32AttributeMode);
            if( kNullAttributeUuid != current_attribute)
            {
                if ( kDagErrNone != dag_config_set_uint32_attribute ( card_ref, current_attribute, mode_value)  )
                {
                    printf("Setting mode is failing....\n");
                }
            }
        }
        current_attribute = 0;

        if ( -1 != term_value)
        {        
            current_attribute = dag_component_get_attribute_uuid( current_component, kUint32AttributeTermination);
            if( kNullAttributeUuid != current_attribute)
            {
                if ( kDagErrNone != dag_config_set_uint32_attribute ( card_ref, current_attribute, term_value)  )
                {
                    printf("Setting termination is failing....\n");
                }
            }
        }
    }
    else    /* if link_value > 15 , do for all the ports */
    {
        port_count =  dag_component_get_subcomponent_count_of_type(root_component, kComponentPort);
        for ( ; i < port_count; i++)
        {
            current_component = dag_component_get_subcomponent(root_component, kComponentPort, i);
            if ( NULL == current_component )
            {
                printf("dag_config_get_subcomponent failed for kComponentPort\n");
                return false;
            }
            if ( -1 != mode_value )
            {        
                current_attribute = dag_component_get_attribute_uuid( current_component, kUint32AttributeMode);
                if( kNullAttributeUuid != current_attribute)
                {
                    if ( kDagErrNone != dag_config_set_uint32_attribute ( card_ref, current_attribute, mode_value)  )
                    {
                        printf("Setting mode is failing....\n");
                    }
                }
            }
            current_attribute = 0;

            if ( -1 != term_value)
            {        
                current_attribute = dag_component_get_attribute_uuid( current_component, kUint32AttributeTermination);
                if( kNullAttributeUuid != current_attribute)
                {
                    if ( kDagErrNone != dag_config_set_uint32_attribute ( card_ref, current_attribute, term_value)  )
                    {
                        printf("Setting termination is failing....\n");
                    }
                }
            }

        }
    }
    
    return true;
}

/* function to delete all the existing connections in the card */
bool delete_all_connections ( dag_card_ref_t card_ref )
{
    dag_component_t root_component = 0;
    dag_component_t current_component = 0;
    attr_uuid_t current_attribute = 0;
     printf("Deleting connection ...\n");

     /* get root */
    root_component = dag_config_get_root_component(card_ref);
    current_component = dag_component_get_subcomponent(root_component, kComponentConnectionSetup, 0);
    if ( NULL == current_component )
    {
        printf("dag_config_get_subcomponent failed for kComponentConnectionSetup\n");
    }
    /*clear all connections*/
    current_attribute = dag_component_get_attribute_uuid( current_component, kNullAttributeClearConnections);
    if( kNullAttributeUuid != current_attribute)
    {
        if ( kDagErrNone != dag_config_set_null_attribute(card_ref, current_attribute) )
        {
            printf("Clearing all connections failed..\n");
        }
    }
    return true;
}
/* function to add 11 connections */
bool add_connection( dag_card_ref_t card_ref)
{
    dag_component_t root_component = 0;
    dag_component_t current_component = 0;
    connection_description_37t_t connection;
    attr_uuid_t current_attribute = 0;
    int i = 0;

 /* get root */
    root_component = dag_config_get_root_component(card_ref);


    current_component = dag_component_get_subcomponent(root_component, kComponentConnectionSetup, 0);
    if ( NULL == current_component )
    {
        printf("dag_config_get_subcomponent failed for kComponentConnectionSetup\n");
    }

    current_attribute = dag_component_get_attribute_uuid( current_component, kNullAttributeClearConnections);
    if( kNullAttributeUuid != current_attribute)
    {
        if ( kDagErrNone != dag_config_set_null_attribute(card_ref, current_attribute) )
        {
                printf("Clearing all connections failed..\n");
        }
    }

    current_attribute = 0;
    printf("\n\n     Configuring %s for %s\n\n",dag_name,tx_or_rc(cur_direction));

    for (; i < no_of_connections; i++)
    {
        connection.mPayloadType = kPayloadTypeATM;
        connection.mDirection   = cur_direction;
        connection.mTimeslot    =   1  ;
        connection.mConnectionType = kConnectionTypeChan;
        connection.mline        = i; //which i/f i want to use ??
        current_attribute = dag_component_get_config_attribute_uuid( current_component, kStructAttributeAddConnection);
        if ( kDagErrNone != dag_config_set_struct_attribute(card_ref, current_attribute, (void*)&connection))
        {
            printf("Setting kStructAttributeAddConnection failed @ connection %d\n", i+1);
        }

        current_attribute = 0;
        current_attribute =  dag_component_get_attribute_uuid( current_component, kUint32AttributeGetLastConnectionNumber );
        if ( kNullAttributeUuid == current_attribute)
        {
            printf("Getting UUID kUint32AttributeGetLastConnectionNumber failed\n");
        }
        else
        {
            uint32_t  last_connection_num = dag_config_get_uint32_attribute( card_ref, current_attribute );
            printf("kUint32AttributeGetLastConnectionNumber is %d \n", last_connection_num);
        }
        current_attribute = 0;
    }

   return true;
}


void print_subtree(dag_card_ref_t card_ref, dag_component_t cur_comp, int depth, char *leader,bool is_attr, attr_uuid_t in_attr)
{
    char str[MAX_LEN]; /* gen. purpose string */
    char path[MAX_LEN];    /* */
    char *cp, *cp2;
    const char *cp3;
    char cur_comp_name[MAX_LEN];
    char cur_comp_code[MAX_LEN];
    dag_component_t sub_comp = 0;
	int comp_count;
    int index;

    strcpy(cur_comp_name, dag_config_get_component_name(cur_comp) );
    sprintf(cur_comp_code, "[%s]",dag_config_get_component_code_as_string(cur_comp));
    strcat(cur_comp_name, cur_comp_code);
    fputs(leader, stdout);  /* print line leader string */
    if ( ! is_attr )
    {
        if(depth) {
            fputs("  +---", stdout);
            cp3 = cur_comp_name + strlen(cur_comp_name);
            while(cp3 != cur_comp_name && strncmp(cp3, SEP, 1))
                cp3--;
        } else
            cp3 = cur_comp_name;

        fputs(cp3, stdout);

        fputc('\n', stdout);
        strncpy(str, leader, MAX_LEN);
        strncpy(path, cur_comp_name, MAX_LEN);
        strncat(path, SEP, MAX_LEN);
        cp = path + strlen(path);
        cp2 = str + strlen(str);
        if ( is_display_attributes )
        {
            /* get the attributes */
            int attr_count = dag_component_get_attribute_count(cur_comp);
            int attr_index = 0;

            for ( ; attr_index < attr_count && is_display_attributes; attr_index++)
            {
                attr_uuid_t attr_uuid = dag_component_get_indexed_attribute_uuid(cur_comp, attr_index);
                if (kNullAttributeUuid != attr_uuid )
                {
                      if(depth)
                      {
                      strncpy(cp2, "  |   ", MAX_LEN - (cp2-str));
                      }
                    //  strncpy(cp, dag_config_get_component_name(sub_comp), MAX_LEN - (cp-path));

                    print_subtree(card_ref, cur_comp,depth +1 ,str, true,attr_uuid);
                }
            }
       }
       comp_count = dag_component_get_subcomponent_count(cur_comp) ;

        for (index = 0; index < comp_count; index++)
        {
            sub_comp = dag_component_get_indexed_subcomponent(cur_comp, index);
            if(depth)
            {
                strncpy(cp2, "  |   ", MAX_LEN - (cp2-str));
            }
            strncpy(cp, dag_config_get_component_name(sub_comp), MAX_LEN - (cp-path));
            print_subtree( card_ref, sub_comp,depth +1 ,str,false, 0);
        }
    }
    else
    {
        char attrib_string[MAX_LEN]= {0};
        const char *attr_name = dag_config_get_attribute_name(in_attr);
        const char *attr_type_string = dag_config_get_attribute_code_as_string(in_attr);//dag_config_get_attribute_valuetype_to_string(in_attr);
        const char *attr_value_string = dag_config_get_attribute_to_string( card_ref, in_attr);
        sprintf( attrib_string, "%s [%s,%s,%s]",attr_name,attr_value_string, attr_type_string,read_write_table[dag_config_get_attribute_config_status(in_attr)]);
         if (depth)
         {
        fputs("  @---", stdout);
        cp3 = attrib_string + strlen(attrib_string);
        while(cp3 != attrib_string&& strncmp(cp3, SEP, 1))
        cp3--;
         }
         else
                 cp3= attrib_string;
        fputs(cp3, stdout); /* print our directory name */
        fputc('\n', stdout);
    }
}

