//!;;Rpy::+
//!;;Rpy::ModelElement: idd_blob
//!;;Rpy::
//!;;Rpy::Component: IDDComponent 
//!;;Rpy::Configuration: IDDConfig
//!;;Rpy::Project: IDD
//!;;Rpy::
//!;;Rpy::FilePath: idd_blob.h
//!;;Rpy::Tag: $Tag
//!;;Rpy::
//!;;Rpy::Copyright: Leonardocompany - COMPANY RESTRICTED
//!;;Rpy::
//!;;Rpy::Generated by Rhapsody: 7.5.3 
//!;;Rpy::-


#ifndef idd_blob_H
#define idd_blob_H

//## dependency IddIFParameter
#include "IddIFParameter.h"
//## dependency stdint
#include <stdint.h>
namespace idd_blob
{
    //## package idd_blob
    
    
    //#[ type chunk_types
    struct ChunkHeader
    {
      typedef unsigned int raw_field_t;
    
      raw_field_t marker;
      raw_field_t len;
      raw_field_t update_cookie;
      raw_field_t spare;
    
      enum { k_record_marker=0xFFFFU, k_record_marker_shift=16U,k_record_id_mask=0x0FFFFU, k_record_size_mask=0x0FFFFU, k_record_size_round=0x3U};
    
      unsigned int recordMarker() const { return marker>>k_record_marker_shift;}
      unsigned int recordId() const { return marker & k_record_id_mask;}
      unsigned int recordSize() const { return len & k_record_size_mask;}
    
      bool isRecordMarkerValid() const { return recordMarker()==k_record_marker;}
      bool isRecordSizeValid() const { return (recordSize() & (~k_record_size_round))==recordSize();}
    
      unsigned int updateCounter() const { return update_cookie;}
    
      void updated() { ++update_cookie;}
    
      ChunkHeader()
      {
        initialize(0, 0);
      }
    
      ChunkHeader(unsigned int size, unsigned int id)
      {
        initialize(size, id);
      }
      void initialize(unsigned int size, unsigned int id)
      {
        marker=(static_cast<raw_field_t>(k_record_marker)<<static_cast<raw_field_t>(k_record_marker_shift))|id;
        len=size;
        update_cookie=0;
        spare=0;
      }
      void setId(unsigned int id)
      {
        marker=(static_cast<raw_field_t>(k_record_marker)<<static_cast<raw_field_t>(k_record_marker_shift))|id;
      }
      void setSize(unsigned int size)
      {
        len=size;
      }
    };
    
    template<typename T_> struct ChunkType
    {
    public:
      typedef T_ value_t;
    
      ChunkHeader _header;
      value_t _data;
    
      ChunkHeader& header() { return _header;}
    
      const value_t& constData() const { return _data;}
      value_t& data() { return _data;}
      void setData(const value_t src) { _data=src;}
    };
    
    template<typename T_> struct ChunkWriter: public ChunkType<T_>
    {
    	ChunkWriter()
    	{
    		ChunkType<T_>::header().initialize(sizeof(T_), 0);
    	}
    	void setId(unsigned int id)
    	{
    		ChunkType<T_>::header().initialize(sizeof(T_), id);
    	}
    };
    
    //Specialization
    template<typename T_> struct GlobalChunkType: public ChunkType<T_>
    {
    public:
      void** globalPointer;
    
      GlobalChunkType(void** global_pointer) //:globalPointer(global_pointer) {}
      {
    	  globalPointer=global_pointer;
      }
    
      void setData(const T_ src)
      {
    	  ChunkType<T_>::setData(src);
    	  void* tmp=const_cast<void*>(src);
    	  *globalPointer=tmp;
      }
    };
    
    typedef GlobalChunkType<void*> ChunkOpaqueReference;
    typedef GlobalChunkType<const void*> ChunkOpaqueConstReference;
    
    /*
    template<typename T_> class IddIFParameter
    {
    public:
    	static T_* data;
    };
    */
    
    template<typename T_> T_* IddIFParameter<T_>::data;
    
    template<typename T_> class ChunkOpaqueReaderReference: public ChunkOpaqueConstReference
    {
    public:
      ChunkOpaqueReaderReference():
    	  ChunkOpaqueConstReference(reinterpret_cast<void**>(&IddIFParameter<T_>::data))
      {
        _header.setSize(sizeof(T_));
        _data=0;
      }
      const T_& constData() const { return *reinterpret_cast<const T_*>(_data);}
      
      static T_* staticDataPointer() { return IddIFParameter<T_>::data;}
    };
    
    //#]
    
    //#[ type chunk_codec
    class InputBlobDecoderBase
    {
    public:
    
      static void blobDecode(idd_blob::ChunkOpaqueConstReference* cr, unsigned int items, const void* src, unsigned int src_size)
      {
        unsigned int sindex=0;
        const unsigned char* s=reinterpret_cast<const unsigned char*>(src);
        for(unsigned int i=0; i<items; ++i)
        {
          if (sindex>src_size)
          {
             break; //TODO: too short, add log and fix-up
          }
          const idd_blob::ChunkHeader& h=*reinterpret_cast<const idd_blob::ChunkHeader*>(&s[sindex]);
          if (h.isRecordMarkerValid())
          {
            if (h.recordId()==i)
            {
              idd_blob::ChunkOpaqueConstReference& c=cr[i];
              if (c.header().recordSize()>=h.recordSize())
              {
                c.header()=h;
                c.setData(reinterpret_cast<const void*>(&s[sindex+(sizeof h)]));//c.data()=reinterpret_cast<const void*>(&s[sindex+(sizeof h)]);
              }
            }
            if (!h.isRecordSizeValid())
            {
              break;//TODO: add error log and fix-up
            }
            sindex+=(sizeof(h)+h.recordSize());
          }
        }
      }
    };
    
    class  InputBlobDecoder
    {
    public:
      template<class T_> bool decode(T_& dst, const void* raw, unsigned int size)
      {
    	idd_blob::ChunkOpaqueConstReference& dref=dst.structIdentifier;
    	unsigned int items=sizeof(dst)/sizeof(dref);//unsigned int items=sizeof(dst)/sizeof(dst.structIdentifier);
        InputBlobDecoderBase::blobDecode(&dref, items, raw, size);
        return true;
      }
    };
    
    class  OutputBlobEncoder
    {
    public:
      template<class T_> bool prepareId(T_& dst)
      {
        unsigned char* s=reinterpret_cast<unsigned char*>(&dst);
    	
    	unsigned int size=sizeof(dst);
    	unsigned int id=0;
    	for(unsigned int i=0; i<size; ++id)
    	{
    	    idd_blob::ChunkHeader& dref=*reinterpret_cast<idd_blob::ChunkHeader*>(&s[i]);
    		dref.setId(id);
    		i+=(sizeof(dref)+dref.recordSize());
    	}
        return true;
      }
    };
    
    //#]
}

#endif
//;;Rpy:: end


