#ifndef IDD_TYPES_H_
#define IDD_TYPES_H_

#include <limits.h>
#include <stdint.h>
#include <stddef.h>

#define idd_codec_volatile	volatile

#ifdef __GNUC__
#ifndef B1553_IDD_NO_OVERRIDE_OPT
#pragma GCC optimize("-O1")
#endif
//#pragma GCC warning "optimization force to -O1"
#endif

namespace idd_codec
{


#define IDD_VERSION_STRUCT_(name_, model_, major_, minor_)\
struct name_ ## _vinfo_t {\
  enum { major=major_};\
  enum { minor=minor_};\
  const char* name;\
  const char* model;\
  const char* pn;\
  const char* req;\
};\
extern const name_ ## _vinfo_t name_ ## _vinfo

#define IDD_VINFO(name_)  (name_ ## _vinfo)
#define IDD_MODEL_ID(name_)  (*reinterpret_cast<unsigned long* const>(const_cast<char*>(IDD_VINFO(name_).model)))

#ifndef IDD_IMPLEMENTATION
#define IDD_VERSION(name_, model_, major_, minor_, pn_, req_) IDD_VERSION_STRUCT_(name_, model_, major_, minor_)
#else
#define IDD_VERSION(name_, model_, major_, minor_, pn_, req_)\
  IDD_VERSION_STRUCT_(name_, model_, major_, minor_);\
  const name_ ## _vinfo_t name_ ## _vinfo=\
  {\
    #name_,\
    model_,\
    pn_,\
    req_,\
  };
#endif

//IDD Data types:

template<unsigned int N_> struct idd_makemask
{
  enum { reset_mask= (~0U)<<N_};
  enum { set_mask= ~reset_mask};
};

template<unsigned int P_, unsigned int L_> struct idd_bitfield_trait
{
  enum { start_bit=P_};
  enum { len=L_};
  enum { reset_mask=idd_makemask<L_>::reset_mask};
  enum { set_mask=idd_makemask<L_>::set_mask};

  enum { raw_reset_mask=(idd_makemask<P_>::set_mask)|(idd_makemask<L_>::reset_mask)<<P_};
  enum { raw_set_mask=(idd_makemask<L_>::set_mask)<<P_};
};

template<unsigned int P_, unsigned int L_, typename T_, typename RT_=unsigned int> struct idd_bitfield_t
{
  typedef idd_bitfield_trait<P_, L_> trait_t;

  enum { start_bit=trait_t::start_bit};
  enum { len=trait_t::len};
  enum { reset_mask=trait_t::reset_mask};
  enum { set_mask=trait_t::set_mask};
  enum { raw_reset_mask=trait_t::raw_reset_mask};
  enum { raw_set_mask=trait_t::raw_set_mask};

  typedef RT_ raw_type_t;
  typedef T_ type_t;
  typedef idd_bitfield_t<P_, L_, T_, RT_> encoded_type_t;

  static int lsb() { return 1;}

  type_t get() const
  {
    btcv_t tmp;
    tmp.field=(_value>>start_bit);
    return static_cast<type_t>(tmp.field);
  }

  void set(type_t v)
  {
    raw_type_t tmp=static_cast<raw_type_t>(_value & raw_reset_mask);
    tmp|= static_cast<raw_type_t>((static_cast<raw_type_t>(v) & set_mask)<<start_bit);
    _value=tmp;
  }

  void set_raw(raw_type_t v) { _value=v;}
  raw_type_t get_raw() const { return _value;}

  bool operator==(type_t v) const { return get()==v;}
  operator type_t() const { return get();}
  //void operator=(type_t v) { set(v);}

  //static double lsb() { return 1;}

protected:
  idd_codec_volatile raw_type_t _value;

  struct btcv_t
  {
    RT_ field: L_;
  };

private:
};


template<unsigned int P_, unsigned int L_, typename T_> struct idd_bitfield_u16_t: public idd_bitfield_t<P_, L_, T_, uint16_t>
{
};

template<unsigned int P_, unsigned int L_, typename T_> struct idd_bitfield_i16_t: public idd_bitfield_t<P_, L_, T_, int16_t>
{
};

template<unsigned int P_, unsigned int L_, typename T_, typename RT_=unsigned int> struct idd_bitfield_gap_low_t
{
  typedef idd_bitfield_trait<P_, L_> trait_t;

  enum { start_bit=trait_t::start_bit};
  enum { len=trait_t::len};
  enum { reset_mask=trait_t::reset_mask};
  enum { set_mask=trait_t::set_mask};
  enum { raw_reset_mask=trait_t::raw_reset_mask};
  enum { raw_set_mask=trait_t::raw_set_mask};

  typedef RT_ raw_type_t;
  typedef T_ type_t;
  typedef idd_bitfield_t<P_, L_, T_, RT_> encoded_type_t;

  static int lsb() { return 1;}

  type_t get() const
  {
    btcv_t tmp;
    tmp.field=(_value>>start_bit);
    return static_cast<type_t>(tmp.field);
  }

  void set(type_t v)
  {
    raw_type_t tmp=static_cast<raw_type_t>(_value & raw_reset_mask);
    tmp|= static_cast<raw_type_t>((static_cast<raw_type_t>(v) & set_mask)<<start_bit);
    _value=tmp;
  }

  void set_raw(raw_type_t v) { _value=v;}
  raw_type_t get_raw() const { return _value;}

  bool operator==(type_t v) const { return get()==v;}
  operator type_t() const { return get();}
  //void operator=(type_t v) { set(v);}

  void set_gap(raw_type_t v) { _gap=v;}
  raw_type_t get_gap() const { return _gap;}

protected:
  idd_codec_volatile raw_type_t _gap;
  idd_codec_volatile raw_type_t _value;

  struct btcv_t
  {
    RT_ field: L_;
  };

private:
};

template<unsigned int P_, unsigned int L_, typename T_> struct idd_bitfield_u32_t
{
	  typedef idd_bitfield_trait<P_, L_> trait_t;

	  enum { start_bit=trait_t::start_bit};
	  enum { len=trait_t::len};
	  enum { reset_mask=trait_t::reset_mask};
	  enum { set_mask=trait_t::set_mask};
	  enum { raw_reset_mask=trait_t::raw_reset_mask};
	  enum { raw_set_mask=trait_t::raw_set_mask};

	  typedef uint32_t raw_type_t;
	  typedef uint16_t _hidden_t;
	  typedef T_ type_t;
	  //typedef idd_bitfield_t<P_, L_, uint32_t> encoded_type_t;

	  static int lsb() { return 1;}

	  type_t get() const
	  {
		  raw_type_t v=get_raw();
		  v=v>>start_bit;
		  v=v & set_mask;
		  return static_cast<type_t>(v);
	  }

	  void set(type_t v)
	  {
	    raw_type_t tmp=get_raw() & raw_reset_mask;
	    tmp|= static_cast<raw_type_t>((static_cast<raw_type_t>(v) & set_mask)<<start_bit);
	    set_raw(tmp);
	  }

	  void set_raw(raw_type_t v)
	  {
		  _value[0]=v>>16;
		  _value[1]=v & 0x0FFFF;
	  }
	  raw_type_t get_raw() const
	  {
		  raw_type_t v=(static_cast<raw_type_t>(_value[0])<<16)|(_value[1]);
		  return v;
	  }

	  bool operator==(type_t v) const { return get()==v;}
	  operator type_t() const { return get();}
	  //void operator=(type_t v) { set(v);}

	  //static double lsb() { return 1;}

	protected:
	  idd_codec_volatile _hidden_t _value[2];

	private:
};

#if 0
template<unsigned int P_, unsigned int L_, typename T_> struct idd_bitfield_i32_t: public idd_bitfield_t<P_, L_, T_, int32_t>
{
};
#endif

template<unsigned int P_, typename T_> struct idd_boolfield_u16_t: public idd_bitfield_t<P_, 1, T_, uint16_t>
{
    bool getbool() const
    {
      return idd_bitfield_t<P_, 1, T_, uint16_t>::get();
    }
    void set(bool v)
    {
    	idd_bitfield_t<P_, 1, T_, uint16_t>::set(static_cast<T_>(v));
    }
};

template<unsigned int MIN_, unsigned int MAX_, unsigned int P_, unsigned int L_, typename T_, typename RT_> struct idd_range_bitfield_t:
		public idd_bitfield_t<P_, L_, T_, RT_>
{
	typedef idd_bitfield_t<P_, L_, T_, unsigned int> basetype_t;
	typedef typename idd_range_bitfield_t::type_t type_t;

	enum {min=MIN_, max=MAX_};

	bool in_range() const
	{
		type_t v=basetype_t::get();
		unsigned int x=static_cast<unsigned int>(v);
		return (x>=static_cast<unsigned int>(min)) && (x<=static_cast<unsigned int>(max));
	}
	type_t getLimited() const
	{
		type_t v=basetype_t::get();
		unsigned int x=static_cast<unsigned int>(v);
		if (x<static_cast<unsigned int>(min))
			return static_cast<unsigned int>(min);
		if (x>static_cast<unsigned int>(max))
			return static_cast<unsigned int>(max);
		return v;
	}
};

#define IDD_REVBIT(pos_, type_)  (((sizeof(type_)*CHAR_BIT)-1)-pos_)
#define IDD_REVBIT16(pos_)   IDD_REVBIT(pos_, uint16_t)
#define IDD_REVBIT32(pos_)   IDD_REVBIT(pos_, uint32_t)

template<int P_, typename T_=unsigned int> struct idd_reversebitindex
{
  enum { bit_index=IDD_REVBIT(P_, T_)};
  enum { bit_index_not_reversed=P_};
};


#define IDD_INT_TRAIT_DECLARATION(name_, T_, min_, max_)\
struct name_\
{\
  typedef T_ lsb_type_t;\
  enum { lsb=1};\
  enum { min=min_};\
  enum { max=max_};\
  enum { precision=1};\
  enum { resolution=1};\
}

template<typename T_, typename RT_, unsigned int SCALE_> struct idd_scaled_integer
{
  typedef RT_ raw_type_t;
  typedef T_ type_t;

  enum { start_bit=0};
  enum { set_mask=-1};

  enum scale_v { scale=SCALE_};

  static unsigned int lsb() { return scale;}

  type_t get_raw() const
  {
    return static_cast<type_t>(_value);
  }

  void set_raw(type_t v)
  {
    raw_type_t tmp=static_cast<raw_type_t>(v);
    _value=tmp;
  }

  type_t get() const
  {
    return static_cast<type_t>(_value)*scale;
  }

  void set(type_t v)
  {
    raw_type_t tmp=static_cast<raw_type_t>(v/scale);
    _value=tmp;
  }


  template<typename C_> C_ cvOut()
  {
	  C_ tmp=_value;
	  tmp*=scale;
	  return tmp;
  }

  template<typename C_> void cvIn(C_ v)
  {
	v=v/scale;
	_value=static_cast<raw_type_t>(v);
  }

  bool operator==(type_t v) const { return get()==v;}
  operator type_t() const { return get();}

protected:
  idd_codec_volatile raw_type_t _value;

};

#define IDD_FIXEDPOINT_TRAIT_DECLARATION_(name_, T_)\
struct name_\
{\
  typedef T_ lsb_type_t;\
  static const T_ lsb;\
  static const T_ min;\
  static const T_ max;\
  static const T_ precision;\
  static const T_ resolution;\
}

#ifndef IDD_IMPLEMENTATION

#define IDD_FIXEDPOINT_TRAIT_DECLARATION(unique_name_, T_, lsb_, min_, max_, prec_, res_)\
IDD_FIXEDPOINT_TRAIT_DECLARATION_(unique_name_, T_)

#else

#define IDD_FIXEDPOINT_TRAIT_DECLARATION(unique_name_, T_, lsb_, min_, max_, prec_, res_)\
IDD_FIXEDPOINT_TRAIT_DECLARATION_(unique_name_, T_);\
const T_ unique_name_::lsb=lsb_;\
const T_ unique_name_::min=min_;\
const T_ unique_name_::max=max_;\
const T_ unique_name_::precision=prec_;\
const T_ unique_name_::resolution=res_;

#endif

#define IDD_FIXEDPOINT_TRAIT_LSB_DECLARATION(name_, T_, lsb_) IDD_FIXEDPOINT_TRAIT_DECLARATION(name_, T_, lsb_, -1, 1, 1, 1)

template<typename T_, typename RT_, class LSB_> struct idd_fixedpoint
{
  typedef LSB_ lsb_type_t;
  typedef RT_ raw_type_t;
  typedef T_ type_t;

  enum { start_bit=0};
  enum { set_mask=0xFFFF};

  type_t get() const { return type_t(_value)*LSB_::lsb;}
  void set(type_t v) { _value=raw_type_t(v/LSB_::lsb);}

  void set_raw(raw_type_t v) { _value=v;}
  raw_type_t get_raw() const { return _value;}

  static type_t lsb() { return LSB_::lsb;}
  static type_t min() { return LSB_::min;}
  static type_t max() { return LSB_::min;}
  static type_t precision() { return LSB_::precision;}
  static type_t resolution() { return LSB_::resolution;}

private:
  idd_codec_volatile raw_type_t _value;
};

template<typename T_, typename RT_, class LSB_> struct idd_fixedpoint16x
{
  typedef LSB_ lsb_type_t;
  typedef RT_ raw_type_t;
  typedef T_ type_t;

  enum { start_bit=0};
  enum { set_mask=-1};

  type_t get() const { return type_t(get_raw())*LSB_::lsb;}
  void set(type_t v) { set_raw(raw_type_t(v/LSB_::lsb));}

  void set_raw(raw_type_t v) { uint32_t u=static_cast<uint32_t>(v);_value[0]=static_cast<uint16_t>(u>>16); _value[1]=static_cast<uint16_t>(u);}

  raw_type_t get_raw() const { return static_cast<raw_type_t>((_value[0]<<16)|_value[1]);}

  static type_t lsb() { return LSB_::lsb;}
  static type_t min() { return LSB_::min;}
  static type_t max() { return LSB_::min;}
  static type_t precision() { return LSB_::precision;}
  static type_t resolution() { return LSB_::resolution;}

public:
  idd_codec_volatile uint16_t _value[sizeof(RT_)/sizeof(uint16_t)];
};

typedef idd_bitfield_i16_t<IDD_REVBIT16(7), 8, int16_t> call_sign_character1_msw_t;

template<unsigned int P_, unsigned int L_, typename T_, typename RT_, class LSB_> struct idd_fixedpoint_bitfield: public idd_bitfield_u16_t<P_, L_, RT_>
{
  typedef idd_bitfield_u16_t<P_, L_, RT_> base_class_t;
  typedef LSB_ lsb_type_t;
  typedef RT_ raw_type_t;
  typedef T_ type_t;

  //enum { start_bit=0};
  //enum { set_mask=0xFFFF};

  type_t get() const { return base_class_t::get()*LSB_::lsb;}
  void set(type_t v) { base_class_t::set(raw_type_t(v/LSB_::lsb));}

  void set_raw(raw_type_t v) { base_class_t::set_raw(v);}
  raw_type_t get_raw() const { return base_class_t::get_raw(); }

  static type_t lsb() { return LSB_::lsb;}
  static type_t min() { return LSB_::min;}
  static type_t max() { return LSB_::min;}
  static type_t precision() { return LSB_::precision;}
  static type_t resolution() { return LSB_::resolution;}
};

template<unsigned int P_, unsigned int L_, class LSB_> struct idd_fixedpoint32_bitfield: public idd_bitfield_u32_t<P_, L_, uint32_t>
{
  typedef idd_bitfield_u32_t<P_, L_, uint32_t> base_class_t;
  typedef LSB_ lsb_type_t;
  typedef int32_t raw_type_t;
  typedef float type_t;

  //enum { start_bit=0};
  //enum { set_mask=base_class_t::set_mask};

  type_t get() const { return static_cast<raw_type_t>(base_class_t::get())*LSB_::lsb;}
  void set(type_t v) { base_class_t::set(static_cast<raw_type_t>(v/LSB_::lsb));}

  void set_raw(raw_type_t v) { base_class_t::set_raw(v);}
  raw_type_t get_raw() const { return base_class_t::get_raw(); }

  static type_t lsb() { return LSB_::lsb;}
  static type_t min() { return LSB_::min;}
  static type_t max() { return LSB_::min;}
  static type_t precision() { return LSB_::precision;}
  static type_t resolution() { return LSB_::resolution;}
};

//Stattic checks and other usefull macros:


#define IDD_STATIC_CHECK_SIZE__(type_, expected_size_)\
struct type_ ## _static_size_checker_t_ {\
  unsigned char check_too_small_ ## type_ [((expected_size_)>sizeof(type_)) ? -1 : 1];\
  unsigned char check_too_big__ ## type_ [((expected_size_)<sizeof(type_)) ? -1 : 1];\
  /*unsigned char check_ ## type_ [((expected_size_)==sizeof(type_)) ? 1 : -1];*/\
}

#ifdef IDD_IMPLEMENTATION
#define IDD_STATIC_CHECK_SIZE(type_, expected_size_)\
IDD_STATIC_CHECK_SIZE__(type_, expected_size_)

//static type_ ## _static_size_checker_t_ type_ ## _static_size_checker_t_inst_

#else
#define IDD_STATIC_CHECK_SIZE(type_, expected_size_) IDD_STATIC_CHECK_SIZE__(type_, expected_size_)
#endif

//#define IDD_OFFSETOF(s_, f_)  (((unsigned int)&(((s_*)0x10)->f_))-0x10)
#define IDD_OFFSETOF(s_, f_) offsetof(s_, f_)

#define IDD_STATIC_CHECK_OFFSET(struct_, member_, offset_)\
struct struct_ ## member_ ## _static_offset_checker_t_ {\
  unsigned char check_ ## struct_ ## member_[IDD_OFFSETOF(struct_, member_)==(offset_) ? 1 : -1];\
}


}//namespace idd_codec

#endif /*IDD_TYPES_H_*/
