#include "dagutil.h"
#include "dagapi.h"
#include "../include/attribute.h"
#include "../include/util/set.h"
#include "../include/card.h"
#include "../include/cards/card_initialization.h"
#include "../include/component.h"
#include "../include/util/utility.h"
#include "../include/cards/common_dagx_constants.h"
#include "../include/util/enum_string_table.h"
#include "../include/cards/dag71s_impl.h"
#include "../include/attribute_factory.h"
#include "../include/create_attribute.h"
#include "../include/components/scratch_pad_component.h"
#include "../include/dag_attribute_codes.h"
#include "../include/attribute_types.h"

static dag_err_t scratch_pad_update_register_base(ComponentPtr component);
static int scratch_pad_post_initialize(ComponentPtr component);
static void scratch_pad_default(ComponentPtr component);
static void scratch_pad_dispose(ComponentPtr component);
static void scratch_pad_reset(ComponentPtr component);

static void* attribute_available_bytes_get_value(AttributePtr attribute);
void scratch_pad_address_set_value(AttributePtr attribute,void *value,int length);
void* scratch_pad_address_get_value(AttributePtr attribute);

typedef enum
{
	kStatusAndAddress  = 0x0000,
	kData              = 0x0004,
}scratch_pad_register_offset_t;

Attribute_t scratch_pad_attr[]=
{
    {
        /* Name */                 "available_bytes",
        /* Attribute Code */       kUint32AttributeAvailableBytes,
        /* Attribute Type */       kAttributeUint32,
        /* Description */          "This field defines the depth of the scratch pad in bytes.",
        /* Config-Status */        kDagAttrStatus,
        /* Index in register */    0,
        /* Register Address */     DAG_REG_SCRATCH_PAD,
        /* Offset */               kStatusAndAddress,
        /* Size/length */          1,
        /* Read */                 grw_iom_read,
        /* Write */                grw_iom_write,
        /* Mask */                 BIT24 | BIT25 | BIT26 | BIT27 | BIT28 | BIT29 | BIT30 | BIT31,
        /* Default Value */        0,
        /* SetValue */             NULL,
	/* GetValue */             attribute_available_bytes_get_value,
	/* SetToString */          attribute_uint32_to_string,
	/* SetFromString */        attribute_uint32_from_string,
	/* Dispose */              attribute_dispose,
	/* PostInit */             attribute_post_initialize,
    },
    {
        /* Name */                 "scratch_pad_address",
        /* Attribute Code */       kUint32AttributeScratchPadAddress,
        /* Attribute Type */       kAttributeUint32,
        /* Description */          "This field addresses the scratch pad ram.",
        /* Config-Status */        kDagAttrConfig,
        /* Index in register */    0,
        /* Register Address */     DAG_REG_SCRATCH_PAD,
        /* Offset */               kStatusAndAddress,
        /* Size/length */          1,
        /* Read */                 grw_iom_read,
        /* Write */                grw_iom_write,
        /* Mask */                 0x7ffff,
        /* Default Value */        0,
        /* SetValue */             scratch_pad_address_set_value,
	/* GetValue */             scratch_pad_address_get_value,
	/* SetToString */          attribute_uint32_to_string,
	/* SetFromString */        attribute_uint32_from_string,
	/* Dispose */              attribute_dispose,
	/* PostInit */             attribute_post_initialize,
    },
    {
        /* Name */                 "scratch_pad_data",
        /* Attribute Code */       kUint32AttributeScratchPadData,
        /* Attribute Type */       kAttributeUint32,
        /* Description */          "The scratch pad data register.",
        /* Config-Status */        kDagAttrConfig,
        /* Index in register */    0,
        /* Register Address */     DAG_REG_SCRATCH_PAD,
        /* Offset */               kData,
        /* Size/length */          1,
        /* Read */                 grw_iom_read,
        /* Write */                grw_iom_write,
        /* Mask */                 0xffffffff,
        /* Default Value */        0,
        /* SetValue */             attribute_uint32_set_value,
	/* GetValue */             attribute_uint32_get_value,
	/* SetToString */          attribute_uint32_to_string,
	/* SetFromString */        attribute_uint32_from_string,
	/* Dispose */              attribute_dispose,
	/* PostInit */             attribute_post_initialize,
    },
};

#define NB_ELEM (sizeof(scratch_pad_attr) / sizeof(Attribute_t))

ComponentPtr
scratch_pad_get_new_component(DagCardPtr card, uint32_t index)
{
	scratch_pad_state_t* state = NULL;
	ComponentPtr result = component_init(kComponentScratchPad, card);
	if (NULL != result)
	{
		component_set_dispose_routine(result, scratch_pad_dispose);
		component_set_post_initialize_routine(result, scratch_pad_post_initialize);
		component_set_reset_routine(result, scratch_pad_reset);
		component_set_default_routine(result, scratch_pad_default);
		component_set_update_register_base_routine(result, scratch_pad_update_register_base);
		component_set_name(result, "Scratch Pad");
		component_set_description(result, "The Scratch Pad register.");
		state = (scratch_pad_state_t*)malloc(sizeof(scratch_pad_state_t));
		state->mIndex = index;
		state->mScratchPadBase = (uint32_t*)(card_get_iom_address(card) + card_get_register_address(card, DAG_REG_SCRATCH_PAD, state->mIndex));
		component_set_private_state(result, state);
	}
	return result;
}

static
dag_err_t scratch_pad_update_register_base(ComponentPtr component)
{
	if (1 == valid_component(component))
	{
		scratch_pad_state_t* state = NULL;
		DagCardPtr card;
		state = component_get_private_state(component);
		card = component_get_card(component);
		NULL_RETURN_WV(state, kDagErrGeneral);
		state->mScratchPadBase = (uint32_t*)(card_get_iom_address(card) + card_get_register_address(card, DAG_REG_SCRATCH_PAD, state->mIndex)); 
		return kDagErrNone;
	}
	return kDagErrInvalidParameter;
}
static
int scratch_pad_post_initialize(ComponentPtr component)
{
	if (1 == valid_component(component))
	{
		DagCardPtr card = NULL;
		scratch_pad_state_t* state = NULL;
		/* Get card reference */
		card = component_get_card(component);
		/* Get counter state structure */
		state = component_get_private_state(component);
		/*the base address*/
		state->mScratchPadBase = (uint32_t*)(card_get_iom_address(card) + card_get_register_address(card, DAG_REG_SCRATCH_PAD, state->mIndex));
		/* Add attribute of counter */
		read_attr_array(component, scratch_pad_attr, NB_ELEM, state->mIndex);
		/*Need to add the kSturctAttributeRawCATEntry Info here*/
		
		return 1;
	}
	return kDagErrInvalidParameter;
}
static  
void scratch_pad_default(ComponentPtr component)
{
	if (1 == valid_component(component))
	{
		DagCardPtr card = NULL;
		/* Get card reference */
		card = component_get_card(component);
	}
}
static
void scratch_pad_dispose(ComponentPtr component)
{
  
}
static
void scratch_pad_reset(ComponentPtr component)
{
  
}


void* attribute_available_bytes_get_value(AttributePtr attribute)
{
   if (1 == valid_attribute(attribute))
    {
	  DagCardPtr card = NULL;
	  ComponentPtr component = NULL;
	  GenericReadWritePtr grw = NULL; 
	  uint32_t register_value = 0;
	  
	  component = attribute_get_component(attribute);
	  
	  grw = attribute_get_generic_read_write_object(attribute);  
	  card = attribute_get_card(attribute);
	  register_value = grw_read(grw);
	  
	  register_value = (1 << register_value);
	  
	  attribute_set_value_array(attribute,&register_value, sizeof(uint64_t));
	  return (void *)attribute_get_value_array(attribute);
    
    }
    return NULL;
}

void* scratch_pad_address_get_value(AttributePtr attribute)
{
   if (1 == valid_attribute(attribute))
    {
          DagCardPtr card = NULL;
          ComponentPtr component = NULL;
          GenericReadWritePtr grw = NULL;
          uint32_t register_value = 0;

          component = attribute_get_component(attribute);

          grw = attribute_get_generic_read_write_object(attribute);
          card = attribute_get_card(attribute);
          register_value = grw_read(grw);

          register_value = (register_value >> 2);

          attribute_set_value_array(attribute,&register_value, sizeof(uint64_t));
          return (void *)attribute_get_value_array(attribute);

    }
    return NULL;
}

void scratch_pad_address_set_value(AttributePtr attribute,void *value,int length)
{
   if (1 == valid_attribute(attribute))
    {
          DagCardPtr card = NULL;
          ComponentPtr component = NULL;
          GenericReadWritePtr grw = NULL;
          uint32_t register_value = 0;

          component = attribute_get_component(attribute);

          grw = attribute_get_generic_read_write_object(attribute);
          card = attribute_get_card(attribute);
          register_value = *(uint32_t*)value;

          register_value = (register_value << 2);
	 
          grw_write(grw,register_value);

     }
}

