///
/// \file    transpose.h
/// \author  Jan Chrin, PSI
/// \date    Release: February 2015
/// \version CAFE 1.0.0
///

#ifndef TRANSPOSE_H
#define TRANSPOSE_H

#include <cadef.h>
#include <global.h>
#include <statusCodes.h>
#include <handleHelper.h>

using namespace std;

/**
 * Transpose Template \n
 * CTYPE is the type of data to be rendered to/from the client \n
 * method get() will receive data transmitted by CA with dataTypeRequest \n
 *              and then convert to CTYPE
 * method getString() will receive data transmitted by CA with dataTypeRequest \n
 *              and then convert to a string
 * method put() will convert data of type CTYPE to the native type  \n
 *              and then transmit to CA
 * method putString() will convert a string type to the native type  \n
 *              and then transmit to CA
 */
template <class CTYPE> class Transpose {

public:
    Transpose (){};
    ~Transpose (){};

	HandleHelper handleHelper;

    int  put(const unsigned int  _handle, const CTYPE * val,  const chtype cdt);
    int  put(const unsigned int  _handle, CAFE_DATATYPE_UNION_SEQ val, CAFE_DATATYPE cdt);
    int  putString (const unsigned int  _handle, dbr_string_t * val);

    int  get(
             const unsigned int  _handle, CTYPE * val,
              dbr_short_t & alarmStatus,  dbr_short_t &alarmSeverity, epicsTimeStamp &ts, bool isCacheRequest);


    int  get( //union db_access_val * PVDataL,
             //ChannelRequestMetaDataClient    channelRequestMetaDataClient,
             //ChannelRepositoryMetaData       channelRepositoryMetaData,
             const unsigned int  _handle, CTYPE * val,
              dbr_short_t & alarmStatus,  dbr_short_t &alarmSeverity, bool isCacheRequest) {

        epicsTimeStamp ts;
        alarmStatus    =0;
        alarmSeverity  =0;

        return get (//PVDataL,
                    //channelRequestMetaDataClient,
                    //channelRepositoryMetaData,
                    _handle, val, alarmStatus, alarmSeverity, ts, isCacheRequest);
    };


    int  get( //union db_access_val * PVDataL,
             //ChannelRequestMetaDataClient    channelRequestMetaDataClient,
             //ChannelRepositoryMetaData       channelRepositoryMetaData,
            const unsigned int  _handle, CTYPE * val,  bool isCacheRequest) {
        epicsTimeStamp ts;
        dbr_short_t alarmStatus;
        dbr_short_t alarmSeverity;

        ts.secPastEpoch=0;
        ts.nsec        =0;
        alarmStatus    =0;
        alarmSeverity  =0;

        return  get(//PVDataL,
                    //channelRequestMetaDataClient,
                    //channelRepositoryMetaData,
                    _handle, val, alarmStatus, alarmSeverity, ts, isCacheRequest);
    };


    int  getCtrl ( //const CAFEConduit &cc, union db_access_val * PVDataL,
                  //ChannelRequestMetaDataClient    channelRequestMetaDataClient,
                  //ChannelRepositoryMetaData       channelRepositoryMetaData,

                  const unsigned int  _handle, CTYPE * val,
        dbr_short_t &alarmStatus,  dbr_short_t &alarmSeverity, dbr_short_t &precision,
        CTYPE   &RISC_pad,
        CTYPE   &upperDispLimit,    CTYPE  &lowerDispLimit,
        CTYPE   &upperAlarmLimit,   CTYPE  &upperWarningLimit,
        CTYPE   &lowerWarningLimit, CTYPE  &lowerAlarmLimit,
        CTYPE   &upperCtrlLimit,    CTYPE  &lowerCtrlLimit,
        char units[MAX_UNITS_SIZE], short &noStr, char strs [MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE], bool isCacheRequest);



private:
  CTYPE * val;
  int  status;
  CAFEStatus   cafeStatus;
  CAFEDataTypeCode cafeDataTypeCode;
  union db_access_val * PVDataL;
  unsigned int   nelem;
  unsigned int   offset;
  chtype dbrTypeRequest_DataBuffer;
  chtype dbrTypeRequest_CtrlBuffer;
  chtype _dataTypeClient;
  char stig [MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE];

};


//////////////////////////////////////////////////////////////////////////////////////////////////////////////


/**
 * Transpose Template Specialization for dbr_string_t char[40]\n
 */
template <> class Transpose <dbr_string_t> {
    //dbr_string_t * val;
public:
    Transpose (){};
    ~Transpose (){};
  int  putString (const unsigned int  _handle, dbr_string_t * val);
  int  putString (const unsigned int  _handle, CAFE_DATATYPE_UNION_SEQ val); //dbr_string_t * val);

  int  get(//union db_access_val * PVDataL,
           //ChannelRequestMetaDataClient    channelRequestMetaDataClient,
           //ChannelRepositoryMetaData       channelRepositoryMetaData,
           const unsigned int  _handle, dbr_string_t * val,
           dbr_short_t & alarmStatus,  dbr_short_t &alarmSeverity, epicsTimeStamp &ts, bool isCacheRequest );


  int  get(//union db_access_val * PVDataL,
           //ChannelRequestMetaDataClient    channelRequestMetaDataClient,
           //ChannelRepositoryMetaData       channelRepositoryMetaData,
          const unsigned int  _handle, dbr_string_t * val,
            dbr_short_t & alarmStatus,  dbr_short_t &alarmSeverity, bool isCacheRequest ) {

      epicsTimeStamp ts;
      alarmStatus    =0;
      alarmSeverity  =0;

      return get (//PVDataL,
                  //channelRequestMetaDataClient,
                  //channelRepositoryMetaData,
                 _handle, val, alarmStatus, alarmSeverity, ts,  isCacheRequest);
  };


  int  get(//union db_access_val * PVDataL,
           //ChannelRequestMetaDataClient    channelRequestMetaDataClient,
           //ChannelRepositoryMetaData       channelRepositoryMetaData,
          const unsigned int  _handle, dbr_string_t * val, bool isCacheRequest) {
      epicsTimeStamp ts;
      dbr_short_t alarmStatus;
      dbr_short_t alarmSeverity;

      ts.secPastEpoch=0;
      ts.nsec        =0;
      alarmStatus    =0;
      alarmSeverity  =0;

      return get ( //PVDataL,
                   //channelRequestMetaDataClient,
                   //channelRepositoryMetaData,
                    _handle, val, alarmStatus, alarmSeverity, ts, isCacheRequest );
  };


  int  getCtrl(//const CAFEConduit & cc,
               const unsigned int  _handle, dbr_string_t * val,
           dbr_short_t & alarmStatus,  dbr_short_t &alarmSeverity, bool isCacheRequest );

private:
  int  status;
  CAFEStatus   cafeStatus;
  union db_access_val * PVDataL;
  unsigned int   nelem;
  unsigned int   offset;
  chtype dbrTypeRequest_DataBuffer;
  chtype dbrTypeRequest_CtrlBuffer;
  chtype _dataTypeClient;
  char stig [MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE];
};




//////////////////////////////////////////////////////////////////////////////////////////////////////////////



/**
 * Transpose Template Specialization for CAFE_DATATYPE_UNION_SEQ\n
 */
template <> class Transpose <CAFE_DATATYPE_UNION> {
   // CAFE_DATATYPE_UNION_SEQ val;
public:
    Transpose (){};
    ~Transpose (){};

    //long put(const unsigned int  _handle, CAFE_DATATYPE_UNION_SEQ val, CAFE_DATATYPE cdt);
    //long putString (const unsigned int  _handle, dbr_string_t * val) { return ICAFE_NORMAL;}


    int  get(//const CAFEConduit & cc,
          const unsigned int  _handle, CAFE_DATATYPE_UNION_SEQ val,
           dbr_short_t & alarmStatus,  dbr_short_t &alarmSeverity, epicsTimeStamp &ts, bool isCacheRequest);

    int  get(//const CAFEConduit & cc,
          const unsigned int  _handle, CAFE_DATATYPE_UNION_SEQ val,
           dbr_short_t & alarmStatus,  dbr_short_t &alarmSeverity, bool isCacheRequest) {

      epicsTimeStamp ts;
      alarmStatus    =0;
      alarmSeverity  =0;

      return get (_handle, val, alarmStatus, alarmSeverity, ts, isCacheRequest);
    };


    int  get(//const CAFEConduit & cc,
           const unsigned int  _handle,  CAFE_DATATYPE_UNION_SEQ val, bool isCacheRequest) {
      epicsTimeStamp ts;
      dbr_short_t alarmStatus;
      dbr_short_t alarmSeverity;

      ts.secPastEpoch=0;
      ts.nsec        =0;
      alarmStatus    =0;
      alarmSeverity  =0;

      return get (_handle, val, alarmStatus, alarmSeverity, ts, isCacheRequest);
    };

private:
    int  status;
    CAFEStatus   cafeStatus;
    union db_access_val * PVDataL;
    unsigned int   nelem;
    unsigned int   offset;
    chtype dbrTypeRequest_DataBuffer;
    chtype _dataTypeClient;
    char stig [MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE];
};


/**
 * \brief Transforms data from CTYPE * val to PutBuffer
 * \param  _handle  input: Conduit object
 * \param  val input: CTYPE datatype
 * \param _dbrType input: chtype
 * \return ICAFE_NORMAL as local data conversion should not incur an error
 */
template <class CTYPE> int  Transpose<CTYPE>::put(const unsigned int  _handle,
                                                   const CTYPE * val, const  chtype _dbrType)
{
#define __METHOD__ "Transpose<CTYPE>::put(_handle,  CTYPE * val, const chtype cdt)"

    status=ICAFE_NORMAL;

    cafeConduit_set_by_handle & handle_index = cs.get<by_handle> ();
    cafeConduit_set_by_handle::iterator it_handle;


    it_handle = handle_index.find(_handle);

    if (it_handle != handle_index.end()) {


        PVDataL  = (*it_handle).getPutBuffer  ();
        nelem    = (*it_handle).getChannelRequestMetaPrimitive().getNelem();


        dbrTypeRequest_DataBuffer = (*it_handle).getChannelRequestMetaPrimitive().getDbrDataType();

        //dbrTypeRequest_DataBuffer is the chtype used in ca_get
        //Only ever fille the Union with the native type as

        //Need to first check if this is really an enum!?


        if (dbrTypeRequest_DataBuffer==DBR_ENUM) {

            dbr_ctrl_enum * dataEnum  =  (dbr_ctrl_enum *)  (*it_handle).getCtrlBuffer();
            dbr_short_t noStrings     =  ((struct dbr_ctrl_enum *) dataEnum)->no_str;

            if(noStrings >0) {

                for (unsigned int  i=0; i<nelem; ++i) {

                    if ( (dbr_enum_t) val[i] >= noStrings ) {

                        memcpy( stig,  &(((struct dbr_ctrl_enum *) dataEnum)->strs),  sizeof(stig  )) ;


                        cout << __FILE__ << "//" << __LINE__ << "//" <<__METHOD__ << endl;
                        cafeStatus.report(ECAFE_INVALID_ENUM_INDEX);
                        cout << val[i] << " is not a a valid enum index " << endl;
                        cout << "VALID STRING [ENUM] OPTIONS ARE: " << endl;
                        for (dbr_short_t ij=0; ij<noStrings; ++ij) {
                            cout << "'" << stig[ij] << "' " << "[" << ij << "]" << "; ";
                        }
                        cout << endl;
                        return ECAFE_INVALID_ENUM_INDEX;
                    } //if
                }//for
            }//if noStrings>0

        }//if

        switch (dbrTypeRequest_DataBuffer)
        {
        case DBR_STRING: // 0
            switch(_dbrType){
            case CAFE_SHORT:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ),
                        "%d",  *reinterpret_cast<const short*>(&val[i]));
                }
                break;
            case CAFE_FLOAT:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ) ,
                        "%f",  *reinterpret_cast<const float*>(&val[i]));
                }
                break;
            case CAFE_ENUM:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ) ,
                        "%u",  *reinterpret_cast<const unsigned short*>(&val[i]));
                }
                break;
            case CAFE_CHAR:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ) ,
                        "%u",  *reinterpret_cast<const char*>(&val[i]));
                }
                break;
            case CAFE_LONG:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ) ,
                        "%d", *reinterpret_cast<const int*>(&val[i]));
                }
                break;
            case CAFE_DOUBLE:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ) ,
                        "%.15f", *reinterpret_cast<const double*>(&val[i]));
                }
                break;
            case CAFE_STRING:
                memcpy( PVDataL, val, sizeof(dbr_string_t)*nelem);

                break;
            default:
                cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
                cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
                cout << "SWITCH STATMENT NOT MEANT FOR CAFE DATATYPE=" << _dbrType <<endl;
                cout << cafeDataTypeCode.message(_dbrType) << endl;
                cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
                cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;
                //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
                return ECAFE_INVALID_SWITCH_CASE;
                break;
            }

            break;

        case DBR_SHORT:  // 1
            switch(_dbrType) {
            case DBR_SHORT:
                memcpy( PVDataL, val, sizeof(dbr_short_t)*nelem);

                break;
            case DBR_FLOAT: //2
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_short_t *) (PVDataL) + i )  =   (dbr_short_t)   val[i] ;
                }
                break;
            case DBR_ENUM:  //3
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_short_t *) (PVDataL) + i )   =   (dbr_short_t)   val[i] ;
                }
                break;
            case DBR_CHAR:  //4
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_short_t *) (PVDataL) + i )   =   (dbr_short_t)   val[i] ;
                }
                break;
            case DBR_LONG: //5
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_short_t *) (PVDataL) + i )   =   (dbr_short_t)   val[i] ;
                }
                break;
            case DBR_DOUBLE:  //6
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_short_t *) (PVDataL) + i ) =   (dbr_short_t)   val[i] ;
                }
                break;
            case DBR_STRING:  //0
                 status=putString(_handle, (dbr_string_t *) val);

                break;
            default:
                cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
                cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
                cout << "SWITCH STATMENT NOT MEANT FOR CAFE DATATYPE=" << _dbrType <<endl;
                cout << cafeDataTypeCode.message(_dbrType) << endl;
                cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
                cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;
                //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
                return ECAFE_INVALID_SWITCH_CASE;
                break;
            }
            break;
        case DBR_FLOAT:  // 2
            switch(_dbrType) {
            case DBR_SHORT:
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_float_t *) (PVDataL) + i )  =   (dbr_float_t)   val[i] ;
                }
                break;
            case DBR_FLOAT: //2
                memcpy( PVDataL, val, sizeof(dbr_float_t)*nelem);

                break;
            case DBR_ENUM:  //3
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_float_t *) (PVDataL) + i )   =   (dbr_float_t)   val[i] ;
                }
                break;
            case DBR_CHAR:  //4
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_float_t *) (PVDataL) + i )   =   (dbr_float_t)   val[i] ;
                }
                break;
            case DBR_LONG: //5
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_float_t *) (PVDataL) + i )   =   (dbr_float_t)   val[i] ;
                }
                break;
            case DBR_DOUBLE:  //6
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_float_t *) (PVDataL) + i ) =   (dbr_float_t)   val[i] ;
                }
                break;
            case DBR_STRING:  //0
                status=putString(_handle, (dbr_string_t *) val);

                break;
            default:
                cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
                cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
                cout << "SWITCH STATMENT NOT MEANT FOR CAFE DATATYPE=" << _dbrType <<endl;
                cout << cafeDataTypeCode.message(_dbrType) << endl;
                cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
                cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;
                //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
                return ECAFE_INVALID_SWITCH_CASE;
                break;
            }
            break;
        case DBR_ENUM:   // 3


            switch(_dbrType) {
            case DBR_SHORT:
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_enum_t *) (PVDataL) + i )  =   (dbr_enum_t)   val[i] ;
                }
                break;
            case DBR_FLOAT: //2
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_enum_t *) (PVDataL) + i )  =   (dbr_enum_t)   val[i] ;
                }
                break;
            case DBR_ENUM:  //3
                memcpy( PVDataL, val, sizeof(dbr_enum_t)*nelem);

                break;
            case DBR_CHAR:  //4
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_enum_t *) (PVDataL) + i )   =   (dbr_enum_t)   val[i] ;
                }
                break;
            case DBR_LONG: //5
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_enum_t *) (PVDataL) + i )   =   (dbr_enum_t)   val[i] ;
                }
                break;
            case DBR_DOUBLE:  //6
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_enum_t *) (PVDataL) + i ) =   (dbr_enum_t)   val[i] ;
                }
                break;
            case DBR_STRING:  //0
                status=putString(_handle, (dbr_string_t *) val);

                break;
            default:
                cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
                cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
                cout << "SWITCH STATMENT NOT MEANT FOR CAFE DATATYPE=" << _dbrType <<endl;
                cout << cafeDataTypeCode.message(_dbrType) << endl;
                cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
                cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;
                //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
                return ECAFE_INVALID_SWITCH_CASE;
                break;
            }

            break;

        case DBR_CHAR:   // 4
            switch(_dbrType) {
            case DBR_SHORT:
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_char_t *) (PVDataL) + i )  =   (dbr_char_t)   val[i] ;
                }
                break;
            case DBR_FLOAT: //2
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_char_t *) (PVDataL) + i )  =   (dbr_char_t)   val[i] ;
                }
                break;
            case DBR_ENUM:  //3
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_char_t *) (PVDataL) + i )   =   (dbr_char_t)   val[i] ;
                }
                break;
            case DBR_CHAR:  //4
                memcpy( PVDataL, val, sizeof(dbr_char_t)*nelem);

                break;
            case DBR_LONG: //5
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_char_t *) (PVDataL) + i )   =   (dbr_char_t)   val[i] ;
                }
                break;
            case DBR_DOUBLE:  //6
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_char_t *) (PVDataL) + i ) =   (dbr_char_t)   val[i] ;
                }
                break;
            case DBR_STRING:  //0
                status=putString(_handle, (dbr_string_t *) val);

                break;
            default:
                cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
                cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
                cout << "SWITCH STATMENT NOT MEANT FOR CAFE DATATYPE=" << _dbrType <<endl;
                cout << cafeDataTypeCode.message(_dbrType) << endl;
                cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
                cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;
                //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
                return ECAFE_INVALID_SWITCH_CASE;
                break;
            }
            break;

        case DBR_LONG:   // 5
            switch(_dbrType) {
            case DBR_SHORT:
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_long_t *) (PVDataL) + i )  =   (dbr_long_t)   val[i] ;
                }
                break;
            case DBR_FLOAT: //2
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_long_t *) (PVDataL) + i )  =   (dbr_long_t)   val[i] ;
                }
                break;
            case DBR_ENUM:  //3
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_long_t *) (PVDataL) + i )   =   (dbr_long_t)   val[i] ;
                }
                break;
            case DBR_CHAR:  //4
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_long_t *) (PVDataL) + i )   =   (dbr_long_t)   val[i] ;
                }
                break;
            case DBR_LONG: //5
                memcpy( PVDataL, val, sizeof(dbr_long_t)*nelem);

                break;
            case DBR_DOUBLE:  //6
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_long_t *) (PVDataL) + i ) =   (dbr_long_t)   val[i] ;
                }
                break;
            case DBR_STRING:  //0
                status=putString(_handle, (dbr_string_t *) val);

                break;
            default:
                cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
                cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
                cout << "SWITCH STATMENT NOT MEANT FOR CAFE DATATYPE=" << _dbrType <<endl;
                cout << cafeDataTypeCode.message(_dbrType) << endl;
                cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
                cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;
                //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
                return ECAFE_INVALID_SWITCH_CASE;
                break;
            }
            break;


        case DBR_DOUBLE: // 6



            switch(_dbrType) {

            case DBR_SHORT:
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_double_t *) (PVDataL) + i )  =   (dbr_double_t)   val[i] ;
                }

                break;

            case DBR_FLOAT: //2
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_double_t *) (PVDataL) + i )  =   (dbr_double_t)   val[i] ;
                }


                break;
            case DBR_ENUM:  //3
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_double_t *) (PVDataL) + i )   =   (dbr_double_t)   val[i] ;
                }
                break;
            case DBR_CHAR:  //4
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_double_t *) (PVDataL) + i )   =   (dbr_double_t)   val[i] ;
                }
                break;
            case DBR_LONG: //5
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((dbr_double_t *) (PVDataL) + i )   =   (dbr_double_t)   val[i] ;
                }
                break;
            case DBR_DOUBLE:  //6

                memcpy( PVDataL, val, sizeof(dbr_double_t)*nelem);



                break;
            case DBR_STRING:  //0
                status=putString(_handle, (dbr_string_t *) val);

                break;

            default:
                cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
                cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
                cout << "SWITCH STATMENT NOT MEANT FOR CAFE DATATYPE=" << _dbrType <<endl;
                cout << cafeDataTypeCode.message(_dbrType) << endl;
                cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
                cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;
                //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
                return ECAFE_INVALID_SWITCH_CASE;
                break;
            }
            break;
        default:
            cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
            cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
            cout << "SWITCH STATMENT NOT MEANT FOR DATATYPE=" << dbrTypeRequest_DataBuffer <<endl;
            cout << cafeDataTypeCode.message(dbrTypeRequest_DataBuffer) << endl;
            cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
            cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;
            //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
            return ECAFE_INVALID_SWITCH_CASE;
            break;
        }
    }
    else {
        cafeStatus.report(ECAFE_INVALID_HANDLE);
        return ECAFE_INVALID_HANDLE;
    }



    return status;

#undef __METHOD__
};




/**
 * Transforms data from CAFE_DATATYPE_UNION_SEQ to PutBuffer
 * \param  _handle  input: Conduit object
 * \param  val input: CAFE_DATATYPE_UNION_SEQ
 * \param  cdt input:  CAFE_DATATYPE
 * \return ICAFE_NORMAL as local data conversion should not incur an error
 */
//long Transpose<CAFE_DATATYPE_UNION>::put( const unsigned int  _handle,
 //                                         CAFE_DATATYPE_UNION_SEQ val, CAFE_DATATYPE cdt)

template <class CTYPE> int  Transpose<CTYPE>::put( const unsigned int  _handle,
                                                     CAFE_DATATYPE_UNION_SEQ val, CAFE_DATATYPE cdt)
{
#define __METHOD__ "Transpose<CTYPE>::put()"

    status=ICAFE_NORMAL;

    cafeConduit_set_by_handle & handle_index=cs.get<by_handle>();
    cafeConduit_set_by_handle::iterator it_handle;
    it_handle = handle_index.find(_handle);

    if (it_handle != handle_index.end()) {

        PVDataL  = (*it_handle).getPutBuffer  ();
        nelem    = (*it_handle).getChannelRequestMetaPrimitive().getNelem();


        dbrTypeRequest_DataBuffer = (*it_handle).getChannelRequestMetaPrimitive().getDbrDataType();

        //dbrTypeRequest_DataBuffer is the chtype used in ca_get
        //Only ever fille the Union with the native type as

        dbr_ctrl_enum *  dataEnum; 
        dbr_short_t noStrings =0;


        switch (dbrTypeRequest_DataBuffer)
        {
        case DBR_STRING: // 0
            switch(cdt){
            case CAFE_SHORT:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ),
                        "%d",  *reinterpret_cast<const short*>(&val[i].s));
                }
                break;
            case CAFE_FLOAT:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ) ,
                        "%f",  *reinterpret_cast<const float*>(&val[i].f));
                }
                break;
            case CAFE_ENUM:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ) ,
                        "%u",  *reinterpret_cast<const unsigned short*>(&val[i].us));
                }
                break;
            case CAFE_CHAR:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ) ,
                        "%u",  *reinterpret_cast<const char*>(&val[i].ch));
                }
                break;
            case CAFE_LONG:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ) ,
                        "%d", *reinterpret_cast<const int*>(&val[i].l));
                }
                break;
            case CAFE_DOUBLE:
                for (unsigned int  i=0; i<nelem; ++i) {
                    sprintf(*((dbr_string_t *) (PVDataL) + i ) ,
                        "%.15lf", *reinterpret_cast<const double*>(&val[i].d));
                }
                break;
            case CAFE_STRING:
                for (unsigned int  i=0; i<nelem; ++i) {
                   // cout << "before " << val[i].str << endl;
                    sprintf(*((dbr_string_t *) (PVDataL) + i ) ,
                        "%s", *reinterpret_cast<char * const *>(&val[i].str));
                    //cout << "after " << *((dbr_string_t *) (PVDataL) + i) << endl;
                }
                break;
            default:
                cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
                cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
                cout << "SWITCH STATMENT NOT MEANT FOR CAFE DATATYPE=" << cdt <<endl;
                cout << cafeDataTypeCode.message(cdt) << endl;
                cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
                cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;
                //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
                return ECAFE_INVALID_SWITCH_CASE;
                break;
            }

            break;
        case DBR_ENUM:   // 3


            // CHANGE THE STRING TO CORRESPONDING ENUM!
            dataEnum  =   (dbr_ctrl_enum *)  (*it_handle).getCtrlBuffer();
           

            noStrings           = ((struct dbr_ctrl_enum *) dataEnum)->no_str;

            memcpy( stig,  &(((struct dbr_ctrl_enum *) dataEnum)->strs),  sizeof(stig  )) ;


                switch(cdt) {

                case CAFE_SHORT:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        *((CTYPE *) (PVDataL) + i )  =   (CTYPE)   val[i].s ;
                        if (  val[i].s < 0 || (dbr_enum_t) val[i].s >= (dbr_enum_t) noStrings) {
                            status=ECAFE_INVALID_ENUM_INDEX;
                        }
                    }

                    break;

                case CAFE_FLOAT: //2
                    for (unsigned int  i=0; i<nelem; ++i) {
                        *((CTYPE *) (PVDataL) + i )  =   (CTYPE)   val[i].f ;
                        if (  val[i].f < 0 ||  (dbr_enum_t) val[i].f >= (dbr_enum_t) noStrings) {
                            status=ECAFE_INVALID_ENUM_INDEX;
                        }
                    }


                    break;
                case CAFE_ENUM:  //3
                    for (unsigned int  i=0; i<nelem; ++i) {
                        *((CTYPE *) (PVDataL) + i )   =   (CTYPE)   val[i].us ;
                        if ( (dbr_enum_t) val[i].us >= (dbr_enum_t) noStrings) {
                            status=ECAFE_INVALID_ENUM_INDEX;
                        }
                    }
                    break;
                case CAFE_CHAR:  //4
                    for (unsigned int  i=0; i<nelem; ++i) {
                        *((CTYPE *) (PVDataL) + i )   =   (CTYPE)   val[i].ch ;
                        if ( (dbr_enum_t) val[i].ch >= (dbr_enum_t) noStrings) {
                            status=ECAFE_INVALID_ENUM_INDEX;
                        }
                    }
                    break;
                case CAFE_LONG: //5
                    for (unsigned int  i=0; i<nelem; ++i) {
                        *((CTYPE *) (PVDataL) + i )   =   (CTYPE)   val[i].l ;
                        if (  val[i].l < 0 || (dbr_enum_t) val[i].l >= (dbr_enum_t)noStrings) {
                            status=ECAFE_INVALID_ENUM_INDEX;
                        }
                    }
                    break;
                case CAFE_DOUBLE:  //6
                    for (unsigned int  i=0; i<nelem; ++i) {
                        *((CTYPE *) (PVDataL) + i ) =   (CTYPE)   val[i].d ;
                        if (  val[i].d < 0 || (dbr_enum_t) val[i].d >= (dbr_enum_t)noStrings) {
                            status=ECAFE_INVALID_ENUM_INDEX;
                        }
                    }


                    break;
                case CAFE_STRING:  //0
                    status=putString(_handle, (dbr_string_t *) val);

                    break;

                default:
                    cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
                    cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
                    cout << "SWITCH STATMENT NOT MEANT FOR CAFE DATATYPE=" << cdt <<endl;
                    cout << cafeDataTypeCode.message(cdt) << endl;
                    cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
                    cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;
                    //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
                    return ECAFE_INVALID_SWITCH_CASE;
                    break;
                }


                break;

        case DBR_SHORT:  // 1
        case DBR_FLOAT:  // 2


        case DBR_CHAR:   // 4
        case DBR_LONG:   // 5
        case DBR_DOUBLE: // 6

            switch(cdt) {

            case CAFE_SHORT:
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((CTYPE *) (PVDataL) + i )  =   (CTYPE)   val[i].s ;
                }

                break;

            case CAFE_FLOAT: //2
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((CTYPE *) (PVDataL) + i )  =   (CTYPE)   val[i].f ;
                }


                break;
            case CAFE_ENUM:  //3
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((CTYPE *) (PVDataL) + i )   =   (CTYPE)   val[i].us ;
                }
                break;
            case CAFE_CHAR:  //4
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((CTYPE *) (PVDataL) + i )   =   (CTYPE)   val[i].ch ;
                }
                break;
            case CAFE_LONG: //5
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((CTYPE *) (PVDataL) + i )   =   (CTYPE)   val[i].l ;
                }
                break;
            case CAFE_DOUBLE:  //6
                for (unsigned int  i=0; i<nelem; ++i) {
                    *((CTYPE *) (PVDataL) + i ) =   (CTYPE)   val[i].d ;
                }

                break;
            case CAFE_STRING:  //0
                status=putString(_handle, (dbr_string_t *) val);

                break;

            default:
                cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
                cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
                cout << "SWITCH STATMENT NOT MEANT FOR CAFE DATATYPE=" << cdt <<endl;
                cout << cafeDataTypeCode.message(cdt) << endl;
                cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
                cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;
                //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
                return ECAFE_INVALID_SWITCH_CASE;
                break;
            }
            break;
        default:
            cout << "ERROR: " << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
            cafeStatus.report(ECAFE_INVALID_SWITCH_CASE);
            cout << "SWITCH STATMENT NOT MEANT FOR DATATYPE=" << dbrTypeRequest_DataBuffer <<endl;
            cout << cafeDataTypeCode.message(dbrTypeRequest_DataBuffer) << endl;
            cout << "ABORTING DATA CONVERTION TO LOCAL putBuffer" << endl;
            cout << "LIKELY THAT THE DATA_TYPE WAS NOT MADE KNOWN IN THE INPUT PARAMETERS" << endl;

            //cout << "CAFE INTERNAL FUNNY: THIS LINE SHOULD NOT APPEAR" << endl;
            return ECAFE_INVALID_SWITCH_CASE;
            break;
        }
    }
    else {
        cafeStatus.report(ECAFE_INVALID_HANDLE);
        return ECAFE_INVALID_HANDLE;
    }

    return status;
#undef __METHOD__
};





/**
 * Converts data from CTYPE to native type
 * in preparation for transmission to CA Server
 * \param  _handle  input: handel to Conduit object
 * \param val  input: Array of values of datatype dbr_string_t
 * \return ICAFE_NORMAL else ECAFE_NO_CONVERT
 */
template <class CTYPE> int  Transpose<CTYPE>::putString
        (const unsigned int  _handle, dbr_string_t * val)
{
#define __METHOD__ "Transpose<CTYPE>::putString"

    cafeConduit_set_by_handle & handle_index=cs.get<by_handle>();
    cafeConduit_set_by_handle::iterator it_handle;
    it_handle = handle_index.find(_handle);

    if (it_handle != handle_index.end()) {

        PVDataL  = (*it_handle).getPutBuffer  ();
        nelem    = (*it_handle).getChannelRequestMetaPrimitive().getNelem();

        dbrTypeRequest_DataBuffer = (*it_handle).getChannelRequestMetaPrimitive().getDbrDataType();

        dbr_ctrl_enum *  dataEnum; 
        dbr_short_t noStrings =0;

        bool allStringsAreValid=true;
        // Client is String
        // Native type is one of the following

        istringstream ss;

        switch(dbrTypeRequest_DataBuffer) {

        case DBR_STRING://0


            for (unsigned int  i=0; i<nelem; ++i)  {
                strcpy( *((dbr_string_t *) (PVDataL) +i), val[i]);
            }
            break;

        case DBR_SHORT://1
            for (unsigned int  i=0; i<nelem; ++i)  {
                dbr_short_t s=0;
                ss.clear();
                ss.str(val[i]);
                ss>>s;

                if ( !ss.fail()) {
                    *((dbr_short_t *) (PVDataL) + i ) = s;
                }
                else {
                    cout << __METHOD__ << __LINE__ << endl;
                    cout << "***WARNING*** NO STRING TO DBR_SHORT CONVERSION for ELEMENT " << i
                            << " of " << nelem << " !! " << endl;
                    cout << "***WARNING*** COULD NOT CONVERT: ";
                    cout << val[i];
                    cout << " TO SHORT; PUT REQUEST NOT MADE!" << endl;
                    //AT THE MERCY OF THE CA SERVER!" << endl; //NOT MADE!" << endl;
                    allStringsAreValid=false;
                }
            }
            break;

        case DBR_FLOAT://2
            for (unsigned int  i=0; i<nelem; ++i)  {
                dbr_float_t f=0;
                ss.clear();
                ss.str(val[i]);
                ss>>f;

                if ( !ss.fail()) {
                    *((dbr_float_t *) (PVDataL) + i ) = f;
                }
                else {
                    cout << __METHOD__ << __LINE__ << endl;
                    cout << "***WARNING*** NO STRING TO DBR_FLOAT CONVERSION for ELEMENT " << i << " of " << nelem << " !! " << endl;
                    cout << "***WARNING*** COULD NOT CONVERT: ";
                    cout << val[i];
                    cout << " TO FLOAT; PUT REQUEST NOT MADE!" << endl; //AT THE MERCY OF THE CA SERVER!" << endl; //NOT MADE! " << endl;
                    allStringsAreValid=false;
                }
            }
            break;

        case DBR_ENUM: //3
            // CHANGE THE STRING TO CORRESPONDING ENUM!
            dataEnum  =   (dbr_ctrl_enum *)  (*it_handle).getCtrlBuffer();


            noStrings           = ((struct dbr_ctrl_enum *) dataEnum)->no_str;

            memcpy( stig,  &(((struct dbr_ctrl_enum *) dataEnum)->strs),  sizeof(stig  )) ;


            for (unsigned int  i=0; i<nelem; ++i) {
                dbr_string_t a;

                //sprintf(a, "%s", val[i]);

                char *b = (char *)  val[i];
                char *c;
                // Remove leading blanks
                c = b;
                while (c != '\0' && *c == ' ') {
                    c++;
                }
                b = c;

                // Remove trailing blanks
                c = b + strlen (b) - 1;
                while (c >= b)
                    {
                    if (*c == ' ') {
                        *c = '\0';
                        // This was reported at www.programmingforums.org/thread35790.html to cause a bus error!?
                    }
                    else {
                        break;
                    }
                    c--;
                }

                sprintf(a, "%s", b);

                bool isValidString=false;
                for (int j=0; j<noStrings; ++j) {

                    if (strcmp((char *)a, stig[j] ) ==0) {

                        dbr_enum_t us= (unsigned short) j;
                        *((dbr_enum_t *) (PVDataL) + i ) = us;
                        isValidString=true;
                        //cout << "setting value " << j << " " << stig[j] << endl;
                        break;
                    }
                }

                // Check for ENUM values given in "string" form

                if (!isValidString) {

                    bool isValidStringAnew=false;

                    dbr_enum_t us=0;
                    ss.clear();
                    ss.str(a);
                    ss>>us;

                    // Is this a valid number?
                    if ( !ss.fail()) {
                        if (us==0 || (us>0 && us <noStrings)) {
                            *((dbr_enum_t *) (PVDataL) + i ) = us;
                            isValidStringAnew=true;
                        }
                        else {
                            status=ECAFE_INVALID_ENUM_INDEX;
                        }
                    }

                    if (!isValidStringAnew) {

                        cout << __METHOD__ << __LINE__ << endl;
                        cout << "***WARNING*** NO STRING TO DBR_ENUM MATCHING for ELEMENT " << i << " of " << nelem << " !! " << endl;
                        cout << "***WARNING*** COULD NOT CONVERT: '";
                        cout << a; //val[i];
                        cout << "' TO A VALID ENUM; PUT REQUEST NOT MADE!" << endl; //AT THE MERCY OF THE CA SERVER!" << endl;
                        cout << "VALID STRING [ENUM] OPTIONS ARE: " << endl;


                        for (dbr_short_t ij=0; ij<noStrings; ++ij) {
                            cout << "'" << stig[ij] << "' " << "[" << ij << "]" << "; ";
                        }
                        cout << endl;


                        allStringsAreValid=false;
                    }

                }

            } //nelem for loop



            break;

        case DBR_CHAR: //4
            for (unsigned int  i=0; i<nelem; ++i)  {
                dbr_char_t ch=0;
                ss.clear();
                ss.str(val[i]);
                ss>>ch;

								char *b = (char *)  val[i];
          

                if ( !ss.fail()) {
                    *((dbr_char_t *) (PVDataL) + i ) = ch;
                }
								
								else if (b != '\0') {
								
										*((dbr_char_t *) (PVDataL) + i ) =  *b;	
								
								}
                else {
                    cout << __FILE__ << "//" << __METHOD__ << "//" << __LINE__ << endl;
                    cout << "***WARNING*** NO STRING TO DBR_CHAR CONVERSION for ELEMENT index " << i << " in array of length " << nelem;
										cout <<	", i.e., with index range [0-"	<< (nelem-1) << "] "	<<  " !! " << endl;
                    cout << "***WARNING*** COULD NOT CONVERT: ";
                    cout << val[i];
                    cout << " TO UNSIGNED CHAR; PUT REQUEST NOT MADE!" << endl; //AT THE MERCY OF THE CA SERVER!" << endl; //NOT MADE!" << endl;
                     allStringsAreValid=false;
                }

            }
            break;

        case DBR_LONG: //5
            for (unsigned int  i=0; i<nelem; ++i)  {
                dbr_long_t l=0;
                ss.clear();
                ss.str(val[i]);
                ss>>l;

                if ( !ss.fail()) {
                    *((dbr_long_t *) (PVDataL) + i ) = l;
                }
                else {
                    cout << __METHOD__ << __LINE__ << endl;
                    cout << "***WARNING*** NO STRING TO DBR_LONG CONVERSION for ELEMENT " << i << " of " << nelem << " !! " << endl;
                    cout << "***WARNING*** COULD NOT CONVERT: ";
                    cout << val[i];
                    cout << " TO LONG; PUT REQUEST NOT MADE!" << endl; //AT THE MERCY OF THE CA SERVER!" << endl; //NOT MADE!" << endl;

                    allStringsAreValid=false;
                }
            }
            break;

        case DBR_DOUBLE: //6
            for (unsigned int  i=0; i<nelem; ++i)  {
                dbr_double_t d=0;
                ss.clear();
                ss.str(val[i]);
                ss>>d;

                if ( !ss.fail()) {
                    *((dbr_double_t *) (PVDataL) + i ) = d;
                }
                else {
                    cout << __METHOD__ << __LINE__ << endl;
                    cout << "***WARNING*** NO STRING TO DBR_DOUBLE CONVERSION for ELEMENT " << i << " of " << nelem << " !! " << endl;
                    cout << "***WARNING*** COULD NOT CONVERT: ";
                    cout << val[i];
                    cout << " TO DOUBLE; PUT REQUEST NOT MADE!" << endl; //AT THE MERCY OF THE CA SERVER!" << endl;  //PUT REQUEST NOT MADE!" << endl;

                    allStringsAreValid=false;
                }

            }//for
            break;
        } //switch


        if(!allStringsAreValid) {
            if (status==ECAFE_INVALID_ENUM_INDEX) {return status;}
            return ECAFE_NO_CONVERT;}
        else {return ICAFE_NORMAL;}

    }
    else {
        cafeStatus.report(ECAFE_INVALID_HANDLE);
        return ECAFE_INVALID_HANDLE;
    }
    return ICAFE_NORMAL;

#undef __METHOD__
}



/**
 * \brief Retrieves data transmitted by CA with dbrTypeRequest_DataBuffer
 * and then converts to CTYPE i.e.  _dataTypeClient
 * \param  _handle  input: handle to Conduit object
 * \param val output: CTYPE datatype
 * \param  alarmStatus   output: dbr_short_t
 * \param  alarmSeverity output: dbr_short_t
 * \param  ts output: epicsTimeStamp
 * \param isCacheRequest input: bool
 * \return ICAFE_NORMAL as local data conversion should not incur an error
**/
template <class CTYPE> int  Transpose<CTYPE>::get(
                        const unsigned int  _handle, CTYPE * val,
          dbr_short_t &alarmStatus, dbr_short_t &alarmSeverity, epicsTimeStamp &ts, bool isCacheRequest)
{
#define __METHOD__ "Transpose<CTYPE>::get()"

    cafeConduit_set_by_handle & handle_index=cs.get<by_handle>();
    cafeConduit_set_by_handle::iterator it_handle;
    it_handle = handle_index.find(_handle);

    if (it_handle != handle_index.end()) {

        PVDataL  = (*it_handle).getDataBuffer();
        offset   = (*it_handle).getChannelRequestMetaDataClient().getOffset();
				//cout << "offset client " << offset << endl;
				//cout << "offset client too...... " << handleHelper.getOffset(_handle) << endl;
				//cout << "offsetLast  ...... " << handleHelper.getOffsetLast(_handle) << endl;
				
				// Difference between using cache and not
				// when not cache offset is that requested by client..
				// when not cache nelem is no of elements requested by client plus the offset requested by client
				// when     cache offset is actual offset in last transaction 
				// when     cache nelem is no of elements from cache 
				
        if(isCacheRequest) {		
						
						offset = (*it_handle).getChannelRequestMetaData().getOffset( );   // equivalent to handleHelper.getOffsetLast(_handle);					
            nelem  = (*it_handle).getChannelRequestMetaData().getNelemCache();// + offset;  // not (*it_handle).getChannelRequestMetaData().getOffset()
						
						//Could be that the number of elements in the data buffer is actually less!   
						//cout << "nelem1 + data offset " << nelem << " " << (*it_handle).getChannelRequestMetaData().getNelemCache() << " + " << 
						//(*it_handle).getChannelRequestMetaData().getOffset() << endl; 
						//nelem  = min(nelem, (*it_handle).getChannelRequestMetaData().getNelemCache()+ offset);
						//cout << "nelem2 " << nelem << " " << (*it_handle).getChannelRequestMetaData().getNelemCache() << " + " << offset << endl; 			
						//cout << __METHOD__ << __LINE__ << endl;
						//cout << "nelem = " << (*it_handle).getChannelRequestMetaData().getNelem() << endl;
						//cout << "nelemCache = " << (*it_handle).getChannelRequestMetaData().getNelemCache() << endl;
						//cout << "offset = " << (*it_handle).getChannelRequestMetaData().getOffset() << endl;
						//cout << "offsetLast  ...... " << handleHelper.getOffsetLast(_handle) << endl;
						//cout << "nelem = " << nelem << endl;
						
        }
        else {
            nelem    = (*it_handle).getChannelRequestMetaData().getNelem()-offset;
						//cout << __METHOD__ << " nelem " << nelem << endl;
        		//cout <<  "getChannelRequestMetaData().getNelem()=" << (*it_handle).getChannelRequestMetaData().getNelem() << endl;
					  //cout <<  "getChannelRequestMetaDataClient().offset " << offset << endl;
												
				}
        //Something wrong, just read last element
        if (nelem <=0) {
            cout << __FILE__ << "//" << __LINE__ << "//" << __METHOD__ << endl;
            cout << "Something funny with the offset; hence will read last element only!"<< endl;
            cout << "Changing offset from=" << offset;

            offset = (*it_handle).getChannelRequestMetaData().getNelem()-1;
            if(isCacheRequest) {
						    //this does not mean much for cache
                nelem  = (*it_handle).getChannelRequestMetaData().getNelemCache(); //(*it_handle).getChannelRequestMetaData().getOffset(); //add offset for cache
            }
            else {
                nelem  = (*it_handle).getChannelRequestMetaData().getNelem()-offset;
            }

            cout << " to=" << offset << endl;
        }

    dbrTypeRequest_DataBuffer = (*it_handle).getChannelRequestMetaData().getDbrDataType();
    _dataTypeClient           = (*it_handle).getChannelRequestMetaDataClient().getDataType();

    //cout << "WHAT IS ON THE DATA BUFFER = " << dbrTypeRequest_DataBuffer  << endl;
    //cout << "WHAT THE CLIENT WANTS    = " << _dataTypeClient << endl;

    ts.secPastEpoch=0;
    ts.nsec        =0;
    alarmStatus    =-1;
    alarmSeverity  =-1;


    if (_dataTypeClient < DBR_STRING || _dataTypeClient > DBR_DOUBLE) {
        cout << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
        cout << "Datatype requested " << dbr_type_to_text(_dataTypeClient)
                << " is not within allowed range: " << endl;
        cout << "DBR_STRING <= dataType <= DBR_DOUBLE" << endl;
        cout << "CAFE ERROR: ECAFE_INVALID_SWITCH_CASE" << endl;
        return ECAFE_INVALID_SWITCH_CASE;
    }

    //dbrTypeRequest_DataBuffer is the chtype used in ca_get
    //_dataTypeCLient is the chtype requested by client

    switch (dbrTypeRequest_DataBuffer)
    {
        case DBR_CHAR:
            switch(_dataTypeClient)
            {
                case DBR_CHAR:
                    memcpy( val, &(&((PVDataL)->charval))[offset], sizeof(dbr_char_t)*nelem);
                    break;

            default:
                for (unsigned int  i=0; i<nelem; ++i) {
                    val[i] =  (CTYPE) (*(&((PVDataL)->charval)+i+offset));
                }
                break;
            }
            break;

        case DBR_FLOAT:
            switch(_dataTypeClient)
            {
                case DBR_FLOAT:
                    memcpy( val, &(&((PVDataL)->fltval))[offset], sizeof(dbr_float_t)*nelem);
                    break;
                default:
                    for (unsigned int  i=0; i<nelem; ++i){
                        val[i] =  (CTYPE) (*(&((PVDataL)->fltval)+i+offset));
                    }
                    break;
            }

            break;

        case DBR_DOUBLE:
            switch(_dataTypeClient)
            {
                case DBR_DOUBLE:
                    memcpy( val, &(&((PVDataL)->doubleval))[offset], sizeof(dbr_double_t)*nelem);
                    break;
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->doubleval)+i+offset));
                    }
                    break;
            }
            break;

        case DBR_SHORT:
            switch(_dataTypeClient)
            {
                case DBR_SHORT:
                    memcpy( val, &(&((PVDataL)->shrtval))[offset], sizeof(dbr_short_t)*nelem);
                    break;
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->shrtval)+i+offset));
                    }
                    break;
            }
            break;

        case DBR_LONG:
            switch(_dataTypeClient)
            {
                case DBR_LONG:
                    memcpy( val, &(&((PVDataL)->longval))[offset], sizeof(dbr_long_t)*nelem);
                    break;
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->longval)+i+offset));
                    }
                    break;
            }
            break;

        case DBR_ENUM:
            switch(_dataTypeClient)
            {
                case DBR_ENUM:
                    memcpy( val, &(&((PVDataL)->enmval))[offset], sizeof(dbr_enum_t)*nelem);
                    break;
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->enmval)+i+offset));
                    }
                    break;
            }
            break;

        case DBR_STRING:
            switch(_dataTypeClient)
            {
                case DBR_STRING:
                    memcpy( val, &(&((PVDataL)->strval))[offset], sizeof(dbr_string_t)*nelem);
                    break;

                case DBR_SHORT:
                case DBR_LONG:
                case DBR_ENUM:
                case DBR_CHAR:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i]=  (CTYPE) strtol(  (*(&((PVDataL)->strval)+i+offset)), NULL, 0);
                    }
                    break;
                case DBR_FLOAT:
                case DBR_DOUBLE:
                default:
                   // If no valid conversion could be performed, the function returns zero (0.0).
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i]=  (CTYPE) strtod(  (*(&((PVDataL)->strval)+i+offset)), NULL);
                    }
                    break;
            }
            break;

        case DBR_STS_CHAR:
            switch(_dataTypeClient)
            {
                case DBR_CHAR:
                    memcpy( val, &(&((PVDataL)->schrval.value))[offset],  sizeof(dbr_char_t)*nelem);
                    break;
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->schrval.value)+i+offset));
                    }
                    break;
            }
            alarmStatus   = ((struct dbr_sts_char *) PVDataL)->status;
            alarmSeverity = ((struct dbr_sts_char *) PVDataL)->severity;
            break;

        case DBR_STS_FLOAT:
            switch(_dataTypeClient)
            {
                case DBR_FLOAT:
                    memcpy( val, &(&((PVDataL)->sfltval.value))[offset], sizeof(dbr_float_t)*nelem);
                    break;
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->sfltval.value)+i+offset));
                    }
                    break;
                }
            alarmStatus   = ((struct dbr_sts_float *) PVDataL)->status;
            alarmSeverity = ((struct dbr_sts_float *) PVDataL)->severity;
            break;

        case DBR_STS_DOUBLE:
            switch(_dataTypeClient)
            {              
                case DBR_DOUBLE:
                    memcpy( val, &(&((PVDataL)->sdblval.value))[offset], sizeof(dbr_double_t)*nelem);
                    break;
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->sdblval.value)+i+offset));
                    }
                    break;
                }
            alarmStatus   = ((struct dbr_sts_double *) PVDataL)->status;
            alarmSeverity = ((struct dbr_sts_double *) PVDataL)->severity;
            break;

        case DBR_STS_SHORT:
            switch(_dataTypeClient)
            {
                case DBR_SHORT:
                    memcpy( val, &(&((PVDataL)->sshrtval.value))[offset], sizeof(dbr_short_t)*nelem);
                    break;
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->sshrtval.value)+i+offset));
                    }
                   break;
            }
            alarmStatus   = ((struct dbr_sts_short *) PVDataL)->status;
            alarmSeverity = ((struct dbr_sts_short *) PVDataL)->severity;
            break;

        case DBR_STS_LONG:
            switch(_dataTypeClient)
            {
                case DBR_LONG:
                    memcpy( val, &(&((PVDataL)->slngval.value))[offset], sizeof(dbr_long_t)*nelem);
                    break;
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->slngval.value)+i+offset));
                    }
                    break;
            }
            alarmStatus   = ((struct dbr_sts_long *) PVDataL)->status;
            alarmSeverity = ((struct dbr_sts_long *) PVDataL)->severity;
            break;

        case DBR_STS_ENUM:
            switch(_dataTypeClient)
            {
                case DBR_ENUM:
                    memcpy( val, &(&((PVDataL)->senmval.value))[offset], sizeof(dbr_enum_t)*nelem);
                    break;
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->senmval.value)+i+offset));
                    }
                    break;
            }
            alarmStatus   = ((struct dbr_sts_enum *) PVDataL)->status;
            alarmSeverity = ((struct dbr_sts_enum *) PVDataL)->severity;
            break;

        case DBR_STS_STRING:
            switch(_dataTypeClient)
            {
                case DBR_STRING:
                    memcpy( val, &(&((PVDataL)->sstrval.value))[offset], sizeof(dbr_string_t)*nelem);
                    break;
                case DBR_SHORT:
                case DBR_LONG:
                case DBR_ENUM:
                case DBR_CHAR:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) strtol(  (*(&((PVDataL)->sstrval.value)+i+offset)), NULL, 0);
                    }
                    break;
                case DBR_FLOAT:
                case DBR_DOUBLE:
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) strtod(  (*(&((PVDataL)->sstrval.value)+i+offset)), NULL);
                    }
                    break;
                }
            alarmStatus   = ((struct dbr_sts_string *) PVDataL)->status;
            alarmSeverity = ((struct dbr_sts_string *) PVDataL)->severity;
            break;

        case DBR_TIME_CHAR:
            switch(_dataTypeClient)
            {
                case DBR_CHAR:
                    memcpy( val, &(&((PVDataL)->tchrval.value))[offset], sizeof(dbr_char_t)*nelem);
                    break;
                case DBR_SHORT:
                case DBR_LONG:
                case DBR_ENUM:
                case DBR_FLOAT:
                case DBR_DOUBLE:
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->tchrval.value)+i+offset));
                    }
                    break;
                // strings are handled by getString - but are handled HERE when calling getCache()!!
                //case DBR_STRING:
                //	for (unsigned int  i=0; i<nelem; ++i) sprintf(val[i], "%u",   (dbr_char_t) (*(&((PVDataL)->tchrval.value)+i)));
            }
            ts            = ((struct dbr_time_char *) PVDataL)->stamp;
            alarmStatus   = ((struct dbr_time_char *) PVDataL)->status;
            alarmSeverity = ((struct dbr_time_char *) PVDataL)->severity;
            break;

        case DBR_TIME_FLOAT:
            switch(_dataTypeClient)
            {
                case DBR_FLOAT:
                    memcpy( val, &(&((PVDataL)->tfltval.value))[offset], sizeof(dbr_float_t)*nelem);
                    break;
                case DBR_SHORT:
                case DBR_LONG:
                case DBR_ENUM:
                case DBR_CHAR:
                case DBR_DOUBLE:
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->tfltval.value)+i+offset));
                     }
                    break;
            }
            ts            = ((struct dbr_time_float *) PVDataL)->stamp;
            alarmStatus   = ((struct dbr_time_float *) PVDataL)->status;
            alarmSeverity = ((struct dbr_time_float *) PVDataL)->severity;
            break;

        case DBR_TIME_DOUBLE:
            switch(_dataTypeClient)
            {
                case DBR_DOUBLE:
                    memcpy( val, &(&((PVDataL)->tdblval.value))[offset], sizeof(dbr_double_t)*nelem);
                    break;
                case DBR_SHORT:
                case DBR_LONG:
                case DBR_ENUM:
                case DBR_CHAR:
                case DBR_FLOAT:
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->tdblval.value)+i+offset));
                    }
                    break;
            }
            ts            = ((struct dbr_time_double *) PVDataL)->stamp;
            alarmStatus   = ((struct dbr_time_double *) PVDataL)->status;
            alarmSeverity = ((struct dbr_time_double *) PVDataL)->severity;

            break;

        case DBR_TIME_SHORT:
            switch(_dataTypeClient)
            {
                case DBR_SHORT:
                    memcpy( val, &(&((PVDataL)->tshrtval.value))[offset], sizeof(dbr_short_t)*nelem);
                    break;
                case DBR_DOUBLE:
                case DBR_LONG:
                case DBR_ENUM:
                case DBR_CHAR:
                case DBR_FLOAT:
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->tshrtval.value)+i+offset));
                    }
                    break;
                //case DBR_STRING:
                //	for (unsigned int  i=0; i<nelem; ++i) sprintf(val[i], "%d",(*(&((PVDataL)->tshrtval.value)+i)));
            }
            ts            = ((struct dbr_time_short *) PVDataL)->stamp;
            alarmStatus   = ((struct dbr_time_short *) PVDataL)->status;
            alarmSeverity = ((struct dbr_time_short *) PVDataL)->severity;
            break;

        case DBR_TIME_LONG:
            switch(_dataTypeClient){
                case DBR_LONG:
                    memcpy( val, &(&((PVDataL)->tlngval.value))[offset], sizeof(dbr_long_t)*nelem);
                    break;
                case DBR_DOUBLE:
                case DBR_SHORT:
                case DBR_ENUM:
                case DBR_CHAR:
                case DBR_FLOAT:
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->tlngval.value)+i+offset));
                    }
                    break;
                //case DBR_STRING:
                //	for (unsigned int  i=0; i<nelem; ++i) sprintf(val[i], "%ld", (*(&((PVDataL)->tlngval.value)+i)));
                //break;
            }
            ts            = ((struct dbr_time_long *) PVDataL)->stamp;
            alarmStatus   = ((struct dbr_time_long *) PVDataL)->status;
            alarmSeverity = ((struct dbr_time_long *) PVDataL)->severity;
            break;

        case DBR_TIME_ENUM:
            switch(_dataTypeClient)
            {
                case DBR_ENUM:
                    memcpy( val, &(&((PVDataL)->tenmval.value))[offset], sizeof(dbr_enum_t)*nelem);
                    break;
                case DBR_DOUBLE:
                case DBR_SHORT:
                case DBR_LONG:
                case DBR_CHAR:
                case DBR_FLOAT:
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i] =  (CTYPE) (*(&((PVDataL)->tenmval.value)+i+offset));
                    }
                    break;
                //case DBR_STRING:
                //	for (unsigned int  i=0; i<nelem; ++i) sprintf(val[i], "%d", (*(&((PVDataL)->tenmval.value)+i)));
                //break;
            }
            ts            = ((struct dbr_time_enum *) PVDataL)->stamp;
            alarmStatus   = ((struct dbr_time_enum *) PVDataL)->status;
            alarmSeverity = ((struct dbr_time_enum *) PVDataL)->severity;
            break;


        case DBR_TIME_STRING:
        default:
            switch(_dataTypeClient){
                case DBR_STRING:
                    memcpy( val, &(&((PVDataL)->strval))[offset], sizeof(dbr_string_t)*nelem);
                    break;
                case DBR_SHORT:
                case DBR_LONG:
                case DBR_ENUM:
                case DBR_CHAR:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i]=  (CTYPE) strtol(  (*(&((PVDataL)->tstrval.value)+i+offset)), NULL, 0);
                    }
                    break;
                case DBR_FLOAT:
                case DBR_DOUBLE:
                default:
                    for (unsigned int  i=0; i<nelem; ++i) {
                        val[i]=  (CTYPE) strtod(  (*(&((PVDataL)->tstrval.value)+i+offset)), NULL);
                    }
                    break;
            }
            ts            = ((struct dbr_time_string *) PVDataL)->stamp;
            alarmStatus   = ((struct dbr_time_string *) PVDataL)->status;
            alarmSeverity = ((struct dbr_time_string *) PVDataL)->severity;
            break;
        }
		//helper function to set TimeStamps!
		//cout <<__METHOD__ << endl;
		//cout << "_dbrType" << _dbrTypeRequest_DataBuffer<< endl;
		//cout << ts.secPastEpoch << " " << ts.nsec << endl;

		if(!isCacheRequest) {
			handleHelper.setSTS(_handle, alarmStatus, alarmSeverity, ts);
		}

    }
    else {
        cafeStatus.report(ECAFE_INVALID_HANDLE);
        return ECAFE_INVALID_HANDLE;
    }

    return ICAFE_NORMAL;


#undef __METHOD__
}


/**
 * \brief  Retrieves ctrl data from buffer
 * \param  _handle  input: handle to Conduit Object
 * \param  val output: CTYPE
 * \param  alarmStatus   output: dbr_short_t
 * \param  alarmSeverity output: dbr_short_t
 * \param  precision     output: dbr_short_t
 * \param  RISC_pad     deprecated!
 * \param  upperDispLimit  output
 * \param  lowerDispLimit  output
 * \param  upperAlarmLimit output
 * \param  upperWarningLimit output
 * \param  lowerWarningLimit output
 * \param  lowerAlarmLimit   output
 * \param  upperCtrlLimit    output
 * \param  lowerCtrlLimit    output
 * \param  units             output: units
 * \param  noStr             output: No of ENUM Choices
 * \param  strs              output: ENUM Choices
 * \param isCacheRequest     input:  bool true or false
 * \return ICAFE_NORMAL
 */
template <class CTYPE> int  Transpose<CTYPE>::getCtrl (
        //const CAFEConduit &cc, union db_access_val * PVDataL,
    //ChannelRequestMetaDataClient    channelRequestMetaDataClient,
    //ChannelRepositoryMetaData       channelRepositoryMetaData,
    const unsigned int  _handle, CTYPE * val,
    dbr_short_t &alarmStatus,  dbr_short_t &alarmSeverity, dbr_short_t &precision,
    CTYPE   &RISC_pad,
    CTYPE   &upperDispLimit,    CTYPE  &lowerDispLimit,
    CTYPE   &upperAlarmLimit,   CTYPE  &upperWarningLimit,
    CTYPE   &lowerWarningLimit, CTYPE  &lowerAlarmLimit,
    CTYPE   &upperCtrlLimit,    CTYPE  &lowerCtrlLimit,
    char units[MAX_UNITS_SIZE], short &noStr, char strs [MAX_ENUM_STATES][MAX_ENUM_STRING_SIZE],
    bool isCacheRequest)  {
#define __METHOD__ "Transpose<CTYPE>::getCtrl()"

    cafeConduit_set_by_handle & handle_index=cs.get<by_handle>();
    cafeConduit_set_by_handle::iterator it_handle;
    it_handle = handle_index.find(_handle);


    if (it_handle != handle_index.end()) {

    PVDataL  = (*it_handle).getCtrlBuffer  ();

    offset   = (*it_handle).getChannelRequestMetaCtrlClient().getOffset();
		
				
		
    if(isCacheRequest) {
		   	offset = (*it_handle).getChannelRequestMetaCtrl().getOffset( ); 
        nelem  = (*it_handle).getChannelRequestMetaCtrl().getNelemCache();; // + (*it_handle).getChannelRequestMetaCtrl().getOffset();
				//nelem  = min(nelem, (*it_handle).getChannelRequestMetaCtrl().getNelem() + offset);
				
    }
    else {
        nelem   = (*it_handle).getChannelRequestMetaCtrl().getNelem()-offset;
    }
    //Something wrong, just read last element
    if (nelem <=0) {
        cout << __FILE__ << "//" << __LINE__ << "//" << __METHOD__ << endl;
        cout << "Something funny with the offset; just read last element! " << endl;
        cout << "Changing offset from=" << offset;

        offset = (*it_handle).getChannelRequestMetaCtrl().getNelem()-1;
        if(isCacheRequest) {
            nelem  = (*it_handle).getChannelRequestMetaCtrl().getNelemCache(); // + (*it_handle).getChannelRequestMetaCtrl().getOffset();  //-offset;
        }
        else {
            nelem  = (*it_handle).getChannelRequestMetaCtrl().getNelem()-offset;
        }
        cout << " to=" << offset << endl;
    }


    dbrTypeRequest_CtrlBuffer = (*it_handle).getChannelRequestMetaCtrl().getDbrDataType();
    _dataTypeClient           = (*it_handle).getChannelRequestMetaDataClient().getDataType();


    alarmStatus     = -1;
    alarmSeverity   = -1;

    if (_dataTypeClient < DBR_STRING || _dataTypeClient > DBR_DOUBLE) {
        cout << __FILE__ << "/" << __LINE__ << "/" << __METHOD__ << endl;
        cout << "Datatype requested " << dbr_type_to_text(_dataTypeClient)
             << " is not within allowed range: " << endl;
        cout << "DBR_STRING <= dataType <= DBR_DOUBLE" << endl;
        cout << "CAFE ERROR: ECAFE_INVALID_SWITCH_CASE" << endl;
        return ECAFE_INVALID_SWITCH_CASE;
    }


    noStr=0;

    //cout << __METHOD__ << endl;
		//cout <<  " dbrTypeRequest_CtrlBuffer " << dbrTypeRequest_CtrlBuffer << endl;
		//cout <<  " _dataTypeClient " << _dataTypeClient << endl;


    switch (dbrTypeRequest_CtrlBuffer) {

    case DBR_CTRL_CHAR:

        switch(_dataTypeClient){
        case DBR_CHAR:
            memcpy(val, &(&((PVDataL)->cchrval.value))[offset], sizeof(dbr_char_t)*nelem);
            break;
        case DBR_DOUBLE:
        case DBR_SHORT:
        case DBR_ENUM:
        case DBR_LONG:
        case DBR_FLOAT:
            for (unsigned int  i=0; i<nelem; ++i) {
                val[i] =  (CTYPE) (*(&((PVDataL)->cchrval.value)+i+offset));
            }
            break;
            // strings are handled by a specialized template
        case DBR_STRING:
            default:
            break;
        }

        precision     = 0;  // struct dbr_ctrl_char does not have the precision member
        RISC_pad      = ((struct dbr_ctrl_char *) PVDataL)->RISC_pad;
        alarmStatus   = ((struct dbr_ctrl_char *) PVDataL)->status;
        alarmSeverity = ((struct dbr_ctrl_char *) PVDataL)->severity;

        memcpy(units, &(((struct dbr_ctrl_char *) PVDataL)->units), sizeof(char[MAX_UNITS_SIZE]));

        upperDispLimit    = (CTYPE) ((struct dbr_ctrl_char *) PVDataL)->upper_disp_limit;
        lowerDispLimit    = (CTYPE) ((struct dbr_ctrl_char *) PVDataL)->lower_disp_limit;
        upperAlarmLimit   = (CTYPE) ((struct dbr_ctrl_char *) PVDataL)->upper_alarm_limit;
        upperWarningLimit = (CTYPE) ((struct dbr_ctrl_char *) PVDataL)->upper_warning_limit;
        lowerWarningLimit = (CTYPE) ((struct dbr_ctrl_char *) PVDataL)->lower_warning_limit;
        lowerAlarmLimit   = (CTYPE) ((struct dbr_ctrl_char *) PVDataL)->lower_alarm_limit;
        upperCtrlLimit    = (CTYPE) ((struct dbr_ctrl_char *) PVDataL)->upper_ctrl_limit;
        lowerCtrlLimit    = (CTYPE) ((struct dbr_ctrl_char *) PVDataL)->lower_ctrl_limit;

        break;

    case DBR_CTRL_ENUM:
        switch(_dataTypeClient){
        case DBR_ENUM:
            memcpy(val, &(&((PVDataL)->cenmval.value))[offset], sizeof(dbr_enum_t)*nelem);
            //for (unsigned int  i=0; i<nelem; ++i) std::cout << val[i] << " /[" << i << "]/ "; 	cout << endl;
            break;
        case DBR_DOUBLE:
        case DBR_SHORT:
        case DBR_CHAR:
        case DBR_LONG:
        case DBR_FLOAT:
            for (unsigned int  i=0; i<nelem; ++i) {
                    val[i] =  (CTYPE) (*(&((PVDataL)->cenmval.value)+i));
            }
            break;
            // strings are handled by a specialized template
        case DBR_STRING:
        default:
            break;
        }

        precision     = 0;  // struct dbr_ctrl_enum does not have the precision member
        RISC_pad      = 0;  // struct dbr_ctrl_char does not have the RISC_pad member
        alarmStatus   = ((struct dbr_ctrl_enum *) PVDataL)->status;
        alarmSeverity = ((struct dbr_ctrl_enum *) PVDataL)->severity;
        noStr         = ((struct dbr_ctrl_enum *) PVDataL)->no_str;

        memcpy(strs , &(((struct dbr_ctrl_enum *) PVDataL)->strs),
                sizeof(char)*MAX_ENUM_STRING_SIZE*MAX_ENUM_STATES);

        //for (unsigned int  i=0; i<noStr; ++i)	cout << i << " " << strs[i] << endl;

        //no units
        memcpy(units,"",sizeof(char[MAX_UNITS_SIZE]));

        upperDispLimit    = (CTYPE)  0;
        lowerDispLimit    = (CTYPE)  0;
        upperAlarmLimit   = (CTYPE)  0;
        upperWarningLimit = (CTYPE)  0;
        lowerWarningLimit = (CTYPE)  0;
        lowerAlarmLimit   = (CTYPE)  0;
        upperCtrlLimit    = (CTYPE)  0;
        lowerCtrlLimit    = (CTYPE)  0;

    break;

    case DBR_CTRL_FLOAT:
        switch(_dataTypeClient){
        case DBR_FLOAT:
            memcpy(val, &(&((PVDataL)->cfltval.value))[offset], sizeof(dbr_float_t)*nelem);

            break;
        case DBR_SHORT:
        case DBR_LONG:
        case DBR_ENUM:
        case DBR_CHAR:
        case DBR_DOUBLE:
            for (unsigned int  i=0; i<nelem; ++i) {
                val[i] =  (CTYPE) (*(&((PVDataL)->cfltval.value)+i+offset)) ;
            }
            break;
        // strings are handled by a specialized template
        case DBR_STRING:
            default:
            break;
        }

        precision     = ((struct dbr_ctrl_float *) PVDataL)->precision;
        RISC_pad      = ((struct dbr_ctrl_float *) PVDataL)->RISC_pad;

        //std::cout << " RISC_PAD " << ((struct dbr_ctrl_float *) PVDataL)->RISC_pad << std::endl;
        //std::cout << " RISC_PAD " << (short) ((struct dbr_ctrl_float *) PVDataL)->RISC_pad << std::endl;

        alarmStatus   = ((struct dbr_ctrl_float *) PVDataL)->status;
        alarmSeverity = ((struct dbr_ctrl_float *) PVDataL)->severity;

        memcpy(units, &(((struct dbr_ctrl_float *) PVDataL)->units), sizeof(char[MAX_UNITS_SIZE]));

        upperDispLimit    = (CTYPE)  ((struct dbr_ctrl_float *) PVDataL)->upper_disp_limit;
        lowerDispLimit    = (CTYPE)  ((struct dbr_ctrl_float *) PVDataL)->lower_disp_limit;
        upperAlarmLimit   = (CTYPE)  ((struct dbr_ctrl_float *) PVDataL)->upper_alarm_limit;
        upperWarningLimit = (CTYPE)  ((struct dbr_ctrl_float *) PVDataL)->upper_warning_limit;
        lowerWarningLimit = (CTYPE)  ((struct dbr_ctrl_float *) PVDataL)->lower_warning_limit;
        lowerAlarmLimit   = (CTYPE)  ((struct dbr_ctrl_float *) PVDataL)->lower_alarm_limit;
        upperCtrlLimit    = (CTYPE)  ((struct dbr_ctrl_float *) PVDataL)->upper_ctrl_limit;
        lowerCtrlLimit    = (CTYPE)  ((struct dbr_ctrl_float *) PVDataL)->lower_ctrl_limit;

        //cout << "upperCtrlLimit= " << upperCtrlLimit << " upperDispLimit=" << upperDispLimit << endl;
        // cout << "value " << val[0] << endl;

        break;

    case DBR_CTRL_DOUBLE:
        switch(_dataTypeClient){
        case DBR_DOUBLE:
            memcpy(val, &(&((PVDataL)->cdblval.value))[offset], sizeof(dbr_double_t)*nelem);

            break;
        case DBR_SHORT:
        case DBR_LONG:
        case DBR_ENUM:
        case DBR_CHAR:
        case DBR_FLOAT:
            for (unsigned int  i=0; i<nelem; ++i) {
                val[i] =  (CTYPE) (*(&((PVDataL)->cdblval.value)+i+offset));
            }
            break;
        // strings are handled by a specialized template
        case DBR_STRING:
            default:
            break;
        }

        precision = ((struct dbr_ctrl_double *) PVDataL)->precision;
        RISC_pad      = (short) ((struct dbr_ctrl_double *) PVDataL)->RISC_pad0; //short
        alarmStatus   = ((struct dbr_ctrl_double *) PVDataL)->status;
        alarmSeverity = ((struct dbr_ctrl_double *) PVDataL)->severity;

        memcpy(units, &(((struct dbr_ctrl_double *) PVDataL)->units), sizeof(char[MAX_UNITS_SIZE]));

        upperDispLimit    = (CTYPE)  ((struct dbr_ctrl_double *) PVDataL)->upper_disp_limit;
        lowerDispLimit    = (CTYPE)  ((struct dbr_ctrl_double *) PVDataL)->lower_disp_limit;
        upperAlarmLimit   = (CTYPE)  ((struct dbr_ctrl_double *) PVDataL)->upper_alarm_limit;
        upperWarningLimit = (CTYPE)  ((struct dbr_ctrl_double *) PVDataL)->upper_warning_limit;
        lowerWarningLimit = (CTYPE)  ((struct dbr_ctrl_double *) PVDataL)->lower_warning_limit;
        lowerAlarmLimit   = (CTYPE)  ((struct dbr_ctrl_double *) PVDataL)->lower_alarm_limit;
        upperCtrlLimit    = (CTYPE)  ((struct dbr_ctrl_double *) PVDataL)->upper_ctrl_limit;
        lowerCtrlLimit    = (CTYPE)  ((struct dbr_ctrl_double *) PVDataL)->lower_ctrl_limit;

        break;

    case DBR_CTRL_SHORT:
        switch(_dataTypeClient){
        case DBR_SHORT:
            memcpy(val, &(&((PVDataL)->cshrtval.value))[offset], sizeof(dbr_short_t)*nelem);

            break;
        case DBR_DOUBLE:
        case DBR_LONG:
        case DBR_ENUM:
        case DBR_CHAR:
        case DBR_FLOAT:
            for (unsigned int  i=0; i<nelem; ++i) {
                val[i] =  (CTYPE) (*(&((PVDataL)->cshrtval.value)+i+offset));
            }
            break;
        // strings are handled by a specialized template
        case DBR_STRING:
            default:
            break;
        }


       precision     = 0;  // struct dbr_ctrl_shrt does not have the precision member
       RISC_pad      = 0;  // struct dbr_ctrl_shrt does not have the RISC_pad member
       alarmStatus   = ((struct dbr_ctrl_short *) PVDataL)->status;
       alarmSeverity = ((struct dbr_ctrl_short *) PVDataL)->severity;

       memcpy(units, &(((struct dbr_ctrl_short *) PVDataL)->units), sizeof(char[MAX_UNITS_SIZE]));

       upperDispLimit    = (CTYPE)  ((struct dbr_ctrl_short *) PVDataL)->upper_disp_limit;
       lowerDispLimit    = (CTYPE)  ((struct dbr_ctrl_short *) PVDataL)->lower_disp_limit;
       upperAlarmLimit   = (CTYPE)  ((struct dbr_ctrl_short *) PVDataL)->upper_alarm_limit;
       upperWarningLimit = (CTYPE)  ((struct dbr_ctrl_short *) PVDataL)->upper_warning_limit;
       lowerWarningLimit = (CTYPE)  ((struct dbr_ctrl_short *) PVDataL)->lower_warning_limit;
       lowerAlarmLimit   = (CTYPE)  ((struct dbr_ctrl_short *) PVDataL)->lower_alarm_limit;
       upperCtrlLimit    = (CTYPE)  ((struct dbr_ctrl_short *) PVDataL)->upper_ctrl_limit;
       lowerCtrlLimit    = (CTYPE)  ((struct dbr_ctrl_short *) PVDataL)->lower_ctrl_limit;

       break;


    case DBR_CTRL_LONG:
        switch(_dataTypeClient){
        case DBR_LONG:
            memcpy(val, &(&((PVDataL)->clngval.value))[offset], sizeof(dbr_long_t)*nelem);
            break;
        case DBR_DOUBLE:
        case DBR_SHORT:
        case DBR_ENUM:
        case DBR_CHAR:
        case DBR_FLOAT:
            for (unsigned int  i=0; i<nelem; ++i) {
                val[i] =  (CTYPE) (*(&((PVDataL)->clngval.value)+i+offset));
            }
            break;
        // strings are handled by a specialized template
        case DBR_STRING:
            default:
            break;
        }

        precision     = 0;  // struct dbr_ctrl_long does not have the precision member
        RISC_pad      = 0;  // struct dbr_ctrl_long does not have the RISC_pad member

        alarmStatus   = ((struct dbr_ctrl_long *) PVDataL)->status;
        alarmSeverity = ((struct dbr_ctrl_long *) PVDataL)->severity;

        memcpy(units, &(((struct dbr_ctrl_long *) PVDataL)->units),sizeof(char[MAX_UNITS_SIZE])) ;

        upperDispLimit    = (CTYPE)  ((struct dbr_ctrl_long *) PVDataL)->upper_disp_limit;
        lowerDispLimit    = (CTYPE)  ((struct dbr_ctrl_long *) PVDataL)->lower_disp_limit;
        upperAlarmLimit   = (CTYPE)  ((struct dbr_ctrl_long *) PVDataL)->upper_alarm_limit;
        upperWarningLimit = (CTYPE)  ((struct dbr_ctrl_long *) PVDataL)->upper_warning_limit;
        lowerWarningLimit = (CTYPE)  ((struct dbr_ctrl_long *) PVDataL)->lower_warning_limit;
        lowerAlarmLimit   = (CTYPE)  ((struct dbr_ctrl_long *) PVDataL)->lower_alarm_limit;
        upperCtrlLimit    = (CTYPE)  ((struct dbr_ctrl_long *) PVDataL)->upper_ctrl_limit;
        lowerCtrlLimit    = (CTYPE)  ((struct dbr_ctrl_long *) PVDataL)->lower_ctrl_limit;

        break;
    }

    }
    else {
        cafeStatus.report(ECAFE_INVALID_HANDLE);
        return ECAFE_INVALID_HANDLE;
    }

return ICAFE_NORMAL;
#undef __METHOD__
}


#endif // TRANSPOSE_H






