/*
 * Copyright (c) 2005 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.
 *
 * $Id: dagconfig.c 12992 2010-07-16 04:00:11Z sfd $
 */

/* Endace headers */
#include "dag_config_api.h"
#include "dag_platform.h"
#include "dagtoken.h"

/* Project headers. */
#include "process_cmdline.h"
#include "configuration_printing.h"
#include "token_processing.h"
#include "statistics_printing.h"
#include "counter_printing.h"
#include "extended_statistics_printing.h"


#define LINE_SIZE 1024

/* CVS Header. */
static const char* const kCvsHeader __attribute__ ((unused)) = "$Id: dagconfig.c 12992 2010-07-16 04:00:11Z sfd $";
static const char* const kRevisionString = "$Revision: 12992 $";

static void parse_configuration_line(dag_card_ref_t card_ref, const char** argv, int argc, int port_select);
static void create_connections(dag_card_ref_t card_ref, const dagconfigure_options_t* options);
static void delete_connections(dag_card_ref_t card_ref);
/* to check whether to use universal counters in place of counters */
static uint8_t replace_counters_with_univ_counters(dag_card_ref_t card);
/* These are externally defined via some lex magic */
extern void dagopt_scan_string(const char *);
extern int dagoptlex(void);
extern char *dagopttext;
extern int dagoptlval;
extern double dagoptlvalfl;

static void
delete_connections(dag_card_ref_t card_ref)
{
    /* delete the connections on the 7.1s */

    dag_component_t mapper = 0;
    dag_component_t demapper = 0;
    dag_component_t root = 0;
    attr_uuid_t attr = 0;

    root = dag_config_get_root_component(card_ref);
    demapper = dag_component_get_subcomponent(root, kComponentDemapper, 0);
    if (demapper)
    {
        attr = dag_component_get_attribute_uuid(demapper, kUint32AttributeSonetType);
        if (dag_config_get_uint32_attribute(card_ref, attr) == kSonetTypeChannelized)
        {
             attr = dag_component_get_attribute_uuid(demapper, kNullAttributeClearConnections);
             dag_config_set_null_attribute(card_ref, attr);
	}
    }
    mapper = dag_component_get_subcomponent(root, kComponentMapper, 0);
    if (mapper)
    {
        attr = dag_component_get_attribute_uuid(mapper, kUint32AttributeSonetType);
        if (dag_config_get_uint32_attribute(card_ref, attr) == kSonetTypeChannelized)
        {
            attr = dag_component_get_attribute_uuid(mapper, kNullAttributeClearConnections);
            dag_config_set_null_attribute(card_ref, attr);
        }
    }
}

/* Create connections for the 7.1s based on the connection configuration file if it exists */
static void
create_connections(dag_card_ref_t card_ref, const dagconfigure_options_t* options)
{
    FILE* file = NULL;
    char line[LINE_SIZE];
    int sscanf_count = 0;
    int tu = 0;
    int tug2 = 0;
    int tug3 = 0;
    int vc = 0;
    int port = 0;
    int chan_num = 0;
    char conn_type[128];
    char payload[128];
    char scrambling[128];
    char hec[128];
    char idle[128];
    int line_count = 0;
    int transmit = 0;
    attr_uuid_t attr = 0;
    dag_component_t root = 0;
    dag_component_t demapper = 0;
    dag_component_t mapper = 0;
    connection_description_t cd;

    file = fopen(options_get_connection_config_filename(options), "r");
    if (NULL == file)
    {
        dagutil_error("Invalid channel configuration file \"%s\", all channels have been deleted.\n", options_get_connection_config_filename(options));
        return;
    }

    /* Check that the card is a 7.1s */
    if (dag_config_get_card_type(card_ref) != kDag71s)
    {
        printf("Configuration file is only valid for a 7.1s - ignoring connection configuration file.\n");
        return;
    }
    root = dag_config_get_root_component(card_ref);
    demapper = dag_component_get_subcomponent(root, kComponentDemapper, 0);
    mapper = dag_component_get_subcomponent(root, kComponentMapper, 0);
    if (demapper != NULL || mapper != NULL)
    {
        /* check that it's channelized */
        if ( demapper )    attr = dag_component_get_attribute_uuid(demapper, kUint32AttributeSonetType);
        else               attr = dag_component_get_attribute_uuid(mapper, kUint32AttributeSonetType);
        if (dag_config_get_uint32_attribute(card_ref, attr) != kSonetTypeChannelized)
        {
            printf("Channelized firmware not loaded\n");
            return;
        }

        while (fgets(line, LINE_SIZE, file))
        {
            line_count++;
            if (line[0] == '#' || isspace(line[0]))
                continue;

            /* check if the keyword is "receive" or "transmit" */
            if (strncmp(line, "receive", 7) == 0)
            {
                transmit = 0;
                continue;
            }
            else if (strncmp(line, "transmit", 8) == 0)
            {
                transmit = 1;
                continue;
            }
            
            if (strncmp(line, "delete", 6) == 0)
            {
                sscanf(line, "delete %d", &chan_num);

                /* get the delete connnection attribute for the demapper or mapper */
                if (transmit == 0)
                {
                    if ( demapper == NULL )
                    {
                        dagutil_warning("No channelized demapper, skipping channel deletion %d.\n", chan_num);
                        continue;
                    }
                    attr = dag_component_get_config_attribute_uuid(demapper, kUint32AttributeDeleteConnection);
                }
                else
                {
                    if ( mapper == NULL )
                    {
                        dagutil_warning("No channelized mapper, skipping channel deletion %d.\n", chan_num);
                        continue;
                    }
                    attr = dag_component_get_config_attribute_uuid(mapper, kUint32AttributeDeleteConnection);
                }

                dag_config_set_uint32_attribute(card_ref, attr, chan_num);
                continue;           
            }
           

            /* otherwise scan the line for configuration information */
            sscanf_count = sscanf(line, "%d %d %d %d %d %s %s %s %s %s",
                    &tu, &tug2, &tug3, &vc, &port, conn_type, payload, scrambling, hec, idle);
            if (10 != sscanf_count)
            {
                printf("Invalid line %d - skipping it.\n", line_count);
                continue;
            }


            /* get the add connnection attribute for the demapper or mapper */
            if (transmit == 0)
            {
                if ( demapper == NULL )
                {
                    dagutil_warning("No channelized demapper, skipping channel configuration line %d.\n", line_count);
                    continue;
                }
                attr = dag_component_get_config_attribute_uuid(demapper, kStructAttributeAddConnection);
            }
            else
            {
                if ( mapper == NULL )
                {
                    dagutil_warning("No channelized mapper, skipping channel configuration line %d.\n", line_count);
                    continue;
                }
                attr = dag_component_get_config_attribute_uuid(mapper, kStructAttributeAddConnection);
            }


            cd.mTUG3_ID = tug3;
            cd.mTUG2_ID = tug2;
            cd.mVC_ID = vc;
            cd.mTU_ID = tu;
            cd.mPortNumber = port;
            if (strcmp("PCM31", conn_type) == 0)
            {
                cd.mConnectionType = kConnectionTypePCM31;
            }
            else if (strcmp("PCM30", conn_type) == 0)
            {
                cd.mConnectionType = kConnectionTypePCM30;
            }
            else if (strcmp("PCM24", conn_type) == 0)
            {
                cd.mConnectionType = kConnectionTypePCM24;
            }
            else if (strstr(conn_type, "0x") != 0)
            {
                /* Assume a timeslot mask is given */
                cd.mTimeslotMask = strtoul(conn_type, NULL, 16);
                cd.mConnectionType = kConnectionTypeUseTimeslotConfig;
            }
            if (strcmp("ATM", payload) == 0)
            {
                cd.mPayloadType = kPayloadTypeATM;
            }
            else if (strcmp("HDLC", payload) == 0)
            {
                cd.mPayloadType = kPayloadTypeHDLC;
            }
            else if (strcmp("RAW", payload) == 0)
            {
                cd.mPayloadType = kPayloadTypeRAW;
            }
            cd.mScramble = (strcmp(scrambling, "on") == 0 ? 1:0);
            cd.mHECCorrection = (strcmp(hec, "on") == 0 ? 1:0);
            cd.mIdleCellMode = (strcmp(idle, "on") == 0 ? 1:0);
            dag_config_set_struct_attribute(card_ref, attr, (void*)&cd);
        }
    }
}

/*
Function used to provide backwards compatibility by providing cmdline configuration support.
*/

static void
parse_configuration_line(dag_card_ref_t card_ref, const char** argv, int argc, int port_select)
{
    int tok = 0;
    int opt = 0;
    char buffer[LINE_SIZE];

    memset(buffer, 0, LINE_SIZE);
    for (opt = 0 ; opt < argc; opt++)
    {
        if (strlen(buffer)+strlen(argv[opt]) > LINE_SIZE)
        {
            printf("Too many options!\n");
            break;
        }
        strcat(buffer, argv[opt]);
        strcat(buffer, " ");
    }

    dagopt_scan_string(buffer);
    while ((tok = dagoptlex()) != 0)
    {
        switch (dag_config_get_card_type(card_ref))
        {
            case kDag71s:
                dag71s_process_token_routine(card_ref, tok, buffer, dagoptlval, port_select);
                break;
            case kDag70ge:
                dag70ge_process_token_routine(card_ref, tok, buffer, dagoptlval, port_select);
                break;
            case kDag62:
                dag62se_process_token_routine(card_ref, tok, buffer, dagoptlval, port_select);
                break;
	    case kDag37d:
                dag37d_process_token_routine(card_ref, tok, buffer, dagoptlval, port_select);
                break;
            case kDag452e:
            case kDag454e:
            case kDag452gf:
            case kDag452cf:
            case kDag452z:
            case kDag452z8:
	    case kDag50s:
	    case kDag50z:
	    case kDag50dup:
	    case kDag50sg2a:
	    case kDag50sg2adup:

	    case kDag52x:
            case kDag82x:
            case kDag82x2:
            case kDag82z:
                dagx_process_token_routine(card_ref, tok, buffer, dagoptlval, port_select);
                break;
            
            //case kDag52x:
            //case kDag82x:
            //case kDag82x2:
            //case kDag82z:
            //    dag82x_process_token_routine(card_ref, tok, buffer, dagoptlval, port_select);
            //   break;

            default:
                dagx_process_token_routine(card_ref, tok, buffer, dagoptlval, port_select);
                break;
        }
    }
}

void
print_temperatures_header(dag_card_ref_t ref)
{
	dag_component_t  hmon;
	dag_component_t  root;
	int              temperature_count;
	int              i;
	attr_uuid_t      attr_uuid;

	root = dag_config_get_root_component(ref);

	hmon = dag_component_get_subcomponent(root, kComponentHardwareMonitor, 0);
	if (!hmon)
	{
		printf("No hardware monitor\n");
		return;
	}
	

	temperature_count = dag_component_get_attribute_count_of_type (hmon, kUint32AttributeTemperature);
	if ( temperature_count == 0 )
	{
		printf("No temperatures monitored\n");
		return;
	}
	
	printf ("Temperatures (in degrees C):");
	for (i=0; i<temperature_count; i++)
	{
		attr_uuid = dag_component_get_indexed_attribute_uuid_of_type (hmon, kUint32AttributeTemperature, i);
		if ( attr_uuid == kNullAttributeUuid )
			continue;
					
		printf ("   T%d  ", i );
	}
	printf ("\n");
}

void
print_temperatures(dag_card_ref_t ref)
{
	dag_component_t hmon;
	dag_component_t root;
	int             temperature_count;
	int             i;
	attr_uuid_t     attr_uuid;

	root = dag_config_get_root_component(ref);

	hmon = dag_component_get_subcomponent(root, kComponentHardwareMonitor, 0);
	if (!hmon)
	{
		printf("No hardware monitor\n");
		return;
	}
	

	temperature_count = dag_component_get_attribute_count_of_type (hmon, kUint32AttributeTemperature);
	if ( temperature_count == 0 )
	{
		printf("No temperatures monitored\n");
		return;
	}
	
	printf ("                            ");
	for (i=0; i<temperature_count; i++)
	{
		attr_uuid = dag_component_get_indexed_attribute_uuid_of_type (hmon, kUint32AttributeTemperature, i);
		if ( attr_uuid == kNullAttributeUuid )
			continue;
					
		printf ("  %3d  ", dag_config_get_uint32_attribute(ref, attr_uuid) );
	}
	printf ("\n");
}


/**
 * Prints out any voltages read via the LM93 sensor on some cards. Unlike
 * the other print outs, this one outputs the strings horizontally, this
 * is because there are usually too many voltages to spread across the 
 * terminal.
 *
 * @param[in]  ref       Reference to the card to read from.
 *
 */
void
print_voltages(dag_card_ref_t ref)
{
	dag_component_t hmon;
	dag_component_t root;
	int             voltage_count;
	int             i;
	attr_uuid_t     attr_uuid;
	dag_err_t       err;
	float           voltage, lowerr, lowwarn, highwarn, higherr;

	root = dag_config_get_root_component(ref);

	hmon = dag_component_get_subcomponent(root, kComponentHardwareMonitor, 0);
	if (!hmon)
	{
		printf("No hardware monitor\n");
		return;
	}
	

	voltage_count = dag_component_get_attribute_count_of_type (hmon, kFloatAttributeVoltage);
	if ( voltage_count == 0 )
	{
		printf("No voltages monitored\n");
		return;
	}
	
	printf ("Voltages (in Volts)\n");
	printf ("-------------------\n");

	for (i=0; i<voltage_count; i++)
	{
		attr_uuid = dag_component_get_indexed_attribute_uuid_of_type (hmon, kFloatAttributeVoltage, i);
		if ( attr_uuid == kNullAttributeUuid )
			continue;
					
		printf ("%-24s: ", dag_config_get_attribute_name(attr_uuid) );
		
		voltage = dag_config_get_float_attribute(ref, attr_uuid);
		if ( (err = dag_config_get_last_error(ref)) != kDagErrNone )
			printf ("Error reading voltage (%d)\n", err);
		else {
			printf ("%5.02fV", voltage);
			//FIXME loop here!
			lowerr = 0.0f;
			lowwarn = 0.0f;
			highwarn = 0.0f;
			higherr = 0.0f;

			attr_uuid = dag_component_get_indexed_attribute_uuid_of_type (hmon, kFloatAttributeVoltageErrorLow, i);
			if ( attr_uuid == kNullAttributeUuid )
			{
				printf( " low error null\n");
				continue;
			}
			lowerr = dag_config_get_float_attribute(ref, attr_uuid);

			attr_uuid = dag_component_get_indexed_attribute_uuid_of_type (hmon, kFloatAttributeVoltageWarningLow, i);
			if ( attr_uuid == kNullAttributeUuid )
			{
				printf( " low warning null\n");
				continue;
			}
			lowwarn = dag_config_get_float_attribute(ref, attr_uuid);

			attr_uuid = dag_component_get_indexed_attribute_uuid_of_type (hmon, kFloatAttributeVoltageWarningHigh, i);
			if ( attr_uuid == kNullAttributeUuid )
			{
				printf( " high warning null\n");
				continue;
			}
			highwarn = dag_config_get_float_attribute(ref, attr_uuid);

			attr_uuid = dag_component_get_indexed_attribute_uuid_of_type (hmon, kFloatAttributeVoltageErrorHigh, i);
			if ( attr_uuid == kNullAttributeUuid )
			{
				printf( " high error null\n");
				continue;
			}
			higherr = dag_config_get_float_attribute(ref, attr_uuid);

			// Check whether the voltage level is lower than the low warning and error levels
			if( lowerr > 0.0f && lowerr < 256.0f && voltage < lowerr )
				printf( " ! UnderVolt Error" );
			else if( lowwarn > 0.0f && lowwarn < 256.0f && voltage < lowwarn )
				printf( " ! UnderVolt Warning" );

			// Check whether the voltage level is higher than the high warning and error levels
			if( higherr > 0.0f && higherr < 256.0f && voltage > higherr )
				printf( " ! OverVolt Error" );
			else if( highwarn > 0.0f && highwarn < 256.0f && voltage > highwarn )
				printf( " ! OverVolt Warning" );

			printf( "\n" );

			
		}
	}
}


void 
print_information_headers(dag_card_ref_t card_ref, int info)
{
    int mask = 0;
    
    printf("Port  ");
    if(dag_config_get_card_type(card_ref) == kDag71s)
        printf("VC  ");
    for(mask = INFO_FIRST; mask < INFO_LAST; mask <<=1)
    {
        switch(info&mask)
        {
            case INFO_STATS:
                print_statistics_header(card_ref);
                break;
            case INFO_EXT_STATS:
                print_extended_statistics_header(card_ref, EXTENDED_CURRENT);
                break;
            case INFO_EXT_LO_STATS:
                print_extended_statistics_header(card_ref, EXTENDED_LO);
                break;
            case INFO_EXT_HI_STATS:
                print_extended_statistics_header(card_ref, EXTENDED_HI);
                break;
            case INFO_COUNTERS:
                print_counters_header(card_ref);
                break;
            case INFO_TX_STATISTICS:
                print_tx_statistics_header(card_ref);
                break;
        }
    }
    printf("\n");
}

void
activate_mini_mac_latches(dag_card_ref_t card_ref, int port)
{
    dag_component_t root;
    dag_component_t mm = NULL;
    dag_component_t mm_stats = NULL;
    attr_uuid_t any_attribute = kNullAttributeUuid;

    root = dag_config_get_root_component(card_ref);
    mm = dag_component_get_subcomponent(root, kComponentPort, port);
    if ( NULL == mm)
    {
        dagutil_verbose_level(3, "The card does not have mini-mac component\n");
        return;
    }
    mm_stats = dag_component_get_subcomponent(mm, kComponentMiniMacStatistics, 0);
    if ( NULL == mm_stats)
    {
        dagutil_verbose_level(3, "The card does not have mini-mac statistics\n");
        return;
    }

    /* Refresh the cache first, because latching the counters below destroys the values in hardware */
    any_attribute = dag_component_get_attribute_uuid(mm_stats, kBooleanAttributeRefreshCache);
    if( kNullAttributeUuid == any_attribute)
    {
        dagutil_verbose_level(3, "%s does not have extended statistics counter latch\n",dag_config_get_component_name(mm_stats));
    }
    else
    {
        dag_config_set_boolean_attribute(card_ref, any_attribute, 1);
    }

    /* Latch the counters */
    any_attribute = dag_component_get_attribute_uuid(mm_stats, kBooleanAttributeCounterLatch);
    if( kNullAttributeUuid == any_attribute)
    {
        dagutil_verbose_level(3, "%s does not have statistics counter latch\n",dag_config_get_component_name(mm_stats));
    }
    else
    {
        dag_config_set_boolean_attribute(card_ref, any_attribute, 1);
    }
}

void
activate_xgmii_stats_latches(dag_card_ref_t card_ref, int port)
{
    dag_component_t root;
    dag_component_t xgmii = NULL;
    dag_component_t xgmii_stats = NULL;
    attr_uuid_t any_attribute = kNullAttributeUuid;

    root = dag_config_get_root_component(card_ref);
    xgmii = dag_component_get_subcomponent(root, kComponentXGMII, 0);
    if ( NULL == xgmii)
    {
        dagutil_verbose_level(3, "The card does not have XGMII component\n");
        return;
    }
    xgmii_stats = dag_component_get_subcomponent(xgmii, kComponentXGMIIStatistics, 0);
    if ( NULL == xgmii_stats)
    {
        dagutil_verbose_level(3, "The card does not have XGMII Statistics component\n");
        return;
    }
    any_attribute = dag_component_get_attribute_uuid(xgmii_stats, kBooleanAttributeCounterLatch);
	if( kNullAttributeUuid == any_attribute)
    {
        dagutil_verbose_level(3, "%s does not have statistics counter latch\n",dag_config_get_component_name(xgmii_stats));
    }
    else
    {
         dag_config_set_boolean_attribute(card_ref, any_attribute, 1);
    }
}

void
activate_sonic_status_latches(dag_card_ref_t card_ref, int port)
{
	dag_component_t root;
	dag_component_t sonic = NULL;
	attr_uuid_t attr = kNullAttributeUuid;

	root = dag_config_get_root_component(card_ref);
	sonic = dag_component_get_subcomponent(root, kComponentSonic, port);
    if ( NULL == sonic)
    {
        dagutil_verbose_level(3, "The card does not have sonic component\n");
        return;
    }
	attr = dag_component_get_attribute_uuid(sonic, kBooleanAttributeRefreshCache);
	if( kNullAttributeUuid == attr)
    {
        dagutil_verbose_level(3, "%s does not have extended statistics counter latch\n",dag_config_get_component_name(sonic));
    }
    else
    {
         dag_config_set_boolean_attribute(card_ref, attr, 1);
    }
}

void
activate_sonic_v1_latches(dag_card_ref_t card_ref, int port)
{
    dag_component_t root;
    dag_component_t sonic_v1 = NULL;
    attr_uuid_t attr = kNullAttributeUuid;

    root = dag_config_get_root_component(card_ref);
    sonic_v1 = dag_component_get_subcomponent(root, kComponentPort, port);
    if (NULL == sonic_v1)
    {
        dagutil_verbose_level(3, "The card does not have sonic v1 component\n");
        return;
    }

    attr = dag_component_get_attribute_uuid(sonic_v1, kBooleanAttributeCounterLatch);
    if( kNullAttributeUuid == attr)
    {
        dagutil_verbose_level(3, "%s does not have extended statistics counter latch\n",dag_config_get_component_name(sonic_v1));
    }
    else
    {
         dag_config_set_boolean_attribute(card_ref, attr, 0);
    }
}

void
activate_sonic_e1t1_latches(dag_card_ref_t card_ref, int port)
{
    dag_component_t root;
    dag_component_t sonic_e1t1 = NULL;
    attr_uuid_t attr = kNullAttributeUuid;

    root = dag_config_get_root_component(card_ref);
    sonic_e1t1 = dag_component_get_subcomponent(root, kComponentPort, port);
    if (NULL == sonic_e1t1)
    {
        dagutil_verbose_level(3, "The card does not have sonic e1/t1 component\n");
        return;
    }

    attr = dag_component_get_attribute_uuid(sonic_e1t1, kBooleanAttributeCounterLatch);
    if( kNullAttributeUuid == attr)
    {
        dagutil_verbose_level(3, "%s does not have extended statistics counter latch\n",dag_config_get_component_name(sonic_e1t1));
    }
    else
    {
        dag_config_set_boolean_attribute(card_ref, attr, 1);
    }

}


void
activate_43_port_latches(dag_card_ref_t card_ref, int port)
{
    dag_component_t root;
    dag_component_t port_component= NULL;
    attr_uuid_t any_attribute = kNullAttributeUuid;

    root = dag_config_get_root_component(card_ref);
    port_component = dag_component_get_subcomponent(root, kComponentPort, port);
    if ( NULL == port_component)
    {   
        dagutil_verbose_level(3, "The card does not have port component\n");
        return;
    }   
    /* Latch the counters */
    any_attribute = dag_component_get_attribute_uuid(port_component, kBooleanAttributeCounterLatch);
    if( kNullAttributeUuid == any_attribute)
    {   
        dagutil_verbose_level(3, "%s does not have statistics counter latch\n",dag_config_get_component_name(port_component));
    }   
    else
    {   
        dag_config_set_boolean_attribute(card_ref, any_attribute, 1); 
    }   
}

/**
 * Works with all demapper components, i.e. oc48_deframer, oc192_deframer
 */
void
activate_oc48_deframer_latches(dag_card_ref_t card_ref, int port)
{
	dag_component_t root;
	dag_component_t deframer;
	attr_uuid_t attr = kNullAttributeUuid;

	root = dag_config_get_root_component(card_ref);
	//TODO: TEMP FIX for the new cards thsi has to be changed to the new functionality 
	//by component tuype 
	deframer = dag_component_get_subcomponent(root, kComponentDemapper, port);
	if(deframer == NULL )
	{
		deframer = dag_component_get_subcomponent(root, kComponentSonetPP, port);
	}
	if(deframer != NULL)
	{		
		attr = dag_component_get_attribute_uuid(deframer, kBooleanAttributeCounterLatch);
		if( kNullAttributeUuid == attr)
        {
            dagutil_verbose_level(3, "%s does not have statistics counter latch\n",dag_config_get_component_name(deframer));
        }
        else
        {
            dag_config_set_boolean_attribute(card_ref, attr, 1);
        }
		attr = dag_component_get_attribute_uuid(deframer, kBooleanAttributeRefreshCache);
		if( kNullAttributeUuid == attr)
        {
            dagutil_verbose_level(3, "%s does not have extended statistics counter latch\n",dag_config_get_component_name(deframer));
        }
        else
        {
            dag_config_set_boolean_attribute(card_ref, attr, 1);
        }
	} else {
#ifndef NDEBUG
		dagutil_verbose_level(3,"This LATCH is only for SONET not for Ethernet(GIGI)\n");
#endif
	}
}


void
activate_ds3182_latches(dag_card_ref_t card_ref, int port)
{
    dag_component_t root;
    dag_component_t framer;
    attr_uuid_t attr;

    root = dag_config_get_root_component(card_ref);
    framer = dag_component_get_subcomponent(root, kComponentPort, port);
    if (NULL == framer)
    {
        dagutil_verbose_level(3, "The card does not have DS3182 component\n");
        return;
    }

    attr = dag_component_get_attribute_uuid(framer, kBooleanAttributeCounterLatch);
    if( kNullAttributeUuid == attr)
    {
        dagutil_verbose_level(3, "%s does not have statistics counter latch\n",dag_config_get_component_name(framer));
    }
    else
    {
        dag_config_set_boolean_attribute(card_ref, attr, 1);
    }
}

void
activate_latches(dag_card_ref_t card_ref, int port)
{
    dag_card_t card_type;

//FIXME: the latches for the 5.0s and 5.2sxa in Gigi mode will not work
//addd code to check the mode and handle the latches properly 
    card_type = dag_config_get_card_type(card_ref);
    switch (card_type)
    {
        case kDag37d:
            activate_ds3182_latches(card_ref, port);
            break;

        case kDag38:
            activate_sonic_v1_latches(card_ref, port);
            break;

        case kDag452e:
        case kDag454e:
        case kDag452gf:
        case kDag452cf:
        case kDag452z:
        case kDag452z8:
            activate_mini_mac_latches(card_ref, port);
            break; 
        /* commenting out because they have been moved to default: case */
        /*
        case kDag50s:
        case kDag50dup:
        case kDag50sg2a:
        case kDag50sg2adup:
        case kDag52sxa:
            activate_oc48_deframer_latches(card_ref, port);
            break; 
        case kDag52x:
        case kDag82x:
        case kDag82z:
        case kDag810:
            activate_xgmii_stats_latches(card_ref, port);
			break;
        */

        case kDag71s:
            activate_sonic_status_latches(card_ref, port);
            break;

        case kDag43ge:
        case kDag43s:
            activate_43_port_latches(card_ref, port);
            break;


        default:
            activate_mini_mac_latches(card_ref, port);
            activate_oc48_deframer_latches(card_ref, port);
            activate_xgmii_stats_latches(card_ref, port);
            break;
    }
}

uint8_t replace_counters_with_univ_counters(dag_card_ref_t card)
{
    switch (dag_config_get_card_type(card))
    {
        case kDag37d:
        case kDag452e:
        case kDag454e:
        case kDag452gf:
        case kDag452cf:
        case kDag452z:
        case kDag452z8:
            return 0;
        default:
        if((dag_config_get_number_block(card) >  0))
        {
            return 1;
        }
    }
    return 0;
}

void 
print_information(dag_card_ref_t card_ref, int info, int port_select)
{
    int mask = 0;
    int i = 0;
    int count = 0;
    dag_component_t root_component;
    dag_component_t sonic_component;
    attr_uuid_t any_attribute;
    int vc_max_index = 0;
    int vc_index = 0;
    int ext_stats_selected = 0;
    dag_card_t card_type;
    uint8_t is_ucsi_latched = 0;
    uint32_t univ_counter_count = 0;
    dag_counter_value_t *counters=NULL;
    
    card_type = dag_config_get_card_type(card_ref);
    root_component = dag_config_get_root_component(card_ref);
    /* Read Port information */
    //Work around for the sonet PP and GIGI on some cards the PHY is port component 
    // on others it is the minimac is the port component 
    // to sove this we assume that 5.0 cards the PHY is PHY and the minimac is Port as the 4.5
    // and if no port compomnents found the it will use the sonetPP component 
    // on the 5.2 and 8.1 and 8.2 the PHY is Port component and XGMII is just a XGMII component 
     
    count = dag_component_get_subcomponent_count_of_type(root_component, kComponentPort);
    if(count == 0) 
    	count = dag_component_get_subcomponent_count_of_type(root_component, kComponentSonetPP);
    if(count == 0 )
        count = dag_config_get_interface_count(card_ref); 
    
    // Activate global latch for all ports, port number is irrelevant, just use 0
    if (card_type == kDag37t || card_type == kDag37t4)
        activate_sonic_e1t1_latches(card_ref, 0);

	for(i = 0; i < count; i++)
    {
        if((port_select & (1 << i)) == (1 << i))
        {
            /* latch counters - this function will latch counters if card and subcomponents require it. */
            activate_latches(card_ref, i);

            printf("%4c ", 'A' + i);    
            /* check to see the type of card */
            if(card_type == kDag71s)
            {
                sonic_component = dag_component_get_subcomponent(root_component, kComponentSonic, i);
                /* Get the VC index */
                any_attribute = dag_component_get_attribute_uuid(sonic_component, kUint32AttributeVCMaxIndex);
                vc_max_index = dag_config_get_uint32_attribute(card_ref, any_attribute);
            }
            else 
            {
                /* This will loop the statistics once for all other cards */
                vc_max_index = 1; 
            }
            for(vc_index = 0; vc_index < vc_max_index; vc_index++)
            {
                if(card_type == kDag71s)
                {
                    if(vc_index != 0)
                        printf("%4c  ", ' ');
                    printf("%2u  ", vc_index);                
                }

                for(mask = INFO_FIRST; mask < INFO_LAST; mask <<=1)
                {
		   
                    switch(info&mask)
                    {
                        case INFO_STATS:
                            print_statistics(card_ref, i, vc_index);
                            break;
                        case INFO_EXT_STATS:
                            print_extended_statistics(card_ref,i, EXTENDED_CURRENT, vc_index);
							ext_stats_selected = 1;
                            break;
                        case INFO_EXT_LO_STATS:
                            print_extended_statistics(card_ref, i, EXTENDED_LO, vc_index);
                            break;
                        case INFO_EXT_HI_STATS:
                            print_extended_statistics(card_ref, i, EXTENDED_HI, vc_index);
                            break;
                        case INFO_COUNTERS:
                            /* Check whether to use univ counters in place of counters */
                            if ( replace_counters_with_univ_counters(card_ref) )
                            {
                                /* latch and clear only once for all ports */
                                if (! is_ucsi_latched )
                                {
                                    univ_counter_count = dag_config_get_number_all_counters(card_ref);
                                    counters =  (dag_counter_value_t*)malloc(univ_counter_count*sizeof(dag_counter_value_t));
                                    dag_config_read_all_counters(card_ref, counters, univ_counter_count, 1);
                                    is_ucsi_latched = 1;
                                }
                                dagx_print_ucsi_counters(counters, univ_counter_count,i );
                            }
                            else
                            {
                                print_counters(card_ref, i);
                            }
                            break;
//not this was removed from here due not port specific but counter block specific 
// the counter block it self may contain more then one port information nut that is part of the UCSI 
//                        case INFO_UNIV_COUNTERS:
//                            print_univ_counters(card_ref, i);
//                           break;
                        case INFO_TX_STATISTICS:
                            print_tx_statistics(card_ref, i);
                            break;
                    }
                }

				if ((card_type == kDag38) && ext_stats_selected == 1)
					continue;
				else 
					printf("\n");
	
            }
        }
    }
    if (NULL != counters)
    {
        free(counters);
    }
		printf("\n");
}

void
do_information_printing(dag_card_ref_t card_ref, int info, int repeat_interval, int port_select)
{
    int count = 0;
    do
    {
        if(count == 0)
        {
            if ( info & INFO_TEMPERATURE )
            {
                print_temperatures_header(card_ref);
            }
			else if ( (info & INFO_VOLTAGE) == 0 )
            {
                print_information_headers(card_ref, info);
            }
        }

        if ( info & INFO_TEMPERATURE )
        {
            print_temperatures(card_ref);
        }
        else if ( info & INFO_VOLTAGE )
        {
            print_voltages(card_ref);
        }
        else
        {
            print_information(card_ref, info, port_select);
        }

        fflush(stdout);
        sleep(repeat_interval);
        count++;
        if(count > 9)
        {
            count = 0;
        }
    }while(repeat_interval);
}

int
dagconfig_main(int argc, char* argv[])
{
    const char* dagname = NULL;
    dag_card_ref_t card_ref = NULL;
    dag_component_t root_component = NULL;
    dagconfigure_options_t* options = NULL;
    FILE* input_file = NULL;
    int repeat_interval;
    int func = 0;
    int info = 0;
    int mask = 0;
    int commandline_result = -1;
    const char** configure_string;
    int configure_count = 0;
    int port_select = 0;

    options = dagconfigure_options_init(argc, (const char** const)argv);
    dagconfigure_add_cmdline_options(options);
    dagutil_set_progname("dagconfig");
    commandline_result = process_cmdline_options(options, argc, (const char** const)argv);
    if (-1 != commandline_result)
    {
        return commandline_result;
    }
    
    if (options_get_verbose(options) == 1)
    {
        dagutil_set_verbosity(options_get_verbosity_level(options));
    }
    dagname = get_dagname();
    card_ref = dag_config_init(dagname);
    if (card_ref == NULL)
    {
        printf("No card\n");
        return EXIT_FAILURE;
    }
    root_component = dag_config_get_root_component(card_ref);
    /* For the 7.1s */
    if ((dag_config_get_card_type(card_ref) == kDag71s) &&
        (options_get_connection_config_filename(options)[0] != '\0'))
    {
        delete_connections(card_ref);
        create_connections(card_ref, options);
    }

    func = options_get_func(options);
    if(func != FUNC_DEFAULT)
        func &= ~FUNC_DEFAULT;
    
    configure_string = options_get_configure_string(options);
    configure_count = options_get_configure_string_count(options);

    if(configure_count > 0)
        func = (FUNC_DO_CONFIG | FUNC_PRINT_CONFIG);
    
    info = options_get_info(options);
    port_select = options_get_port_select(options);
    repeat_interval = options_get_repeat_interval(options);

    /* Parse and Print Configuration if required */
    for(mask = FUNC_FIRST; mask < FUNC_LAST; mask <<= 1)
    {
        switch(func&mask)
        {
            case FUNC_NONE:
                continue;
            case FUNC_DO_CONFIG:
                parse_configuration_line(card_ref, configure_string, configure_count, port_select);
                break;
            case FUNC_PRINT_CONFIG:
                print_configuration(card_ref);
                break;
            case FUNC_PRINT_INFO:
                /* Print tree information specified in the command line */
		if(info & INFO_TREE)
		{
                	print_card_tree(card_ref, 1, 1);
			break;
		};
		if(info & INFO_UNIV_COUNTERS)
		{
			print_univ_counters(card_ref);
			break;
		};
                /* Print information specified in the command line */
                do_information_printing(card_ref, info, repeat_interval, port_select);
                break;
        }
    }

    if (input_file && input_file != stdin)
    {
        fclose(input_file);
        input_file = NULL;
    }

	dagconfigure_options_dispose(options);
    dag_config_dispose(card_ref);
    
    return EXIT_SUCCESS;
}


#ifndef ENDACE_UNIT_TEST
int
main(int argc, const char* const * argv)
{
    return dagconfig_main(argc, (char**) argv);
}
#endif /* ENDACE_UNIT_TEST */
