//+=============================================================================
//
// project :      TANGO Utility
// file :         PogoHelper.h:
//
// Copyright (C) :      2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015
//                        Synchrotron SOLEIL
//                        L'Orme des Merisiers
//                        Saint-Aubin - BP 48 - France
//
// This file is part of Tango.
//
// Tango is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tango is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tango.  If not, see <http://www.gnu.org/licenses/>.
//
//   description :  This utility class helps to allocate and desallocate READ attributes
//    as POGO only generates pointers and let the Device developper manage memory allocation
//
//        Note : these functions also initialise to a default value the allocated attributes
// Usage examples :
//
//        CREATE_SCALAR_ATTRIBUTE(attr_hCoordinate_read);    // by default initialised to 0
//        CREATE_SCALAR_ATTRIBUTE(attr_hCoordinate_read,1);    // initialised to 1
//        DELETE_SCALAR_ATTRIBUTE(attr_hCoordinate_read)
//
//        CREATE_DEVSTRING_ATTRIBUTE(attr_currentUMatrix_read,MAX_STRING_LENGTH);// by default initialised to ""
//        CREATE_DEVSTRING_ATTRIBUTE(attr_currentUMatrix_read,MAX_STRING_LENGTH,"No U Matrix available");
//        DELETE_DEVSTRING_ATTRIBUTE(attr_currentUMatrix_read)
//
//        CREATE_SPECTRUM_ATTRIBUTE(attr_currentspectrum_read,MAX_LENGTH);// by default initialised to 0
//        CREATE_SPECTRUM_ATTRIBUTE(attr_currentspectrum_read,MAX_LENGTH, 1);
//        DELETE_SPECTRUM_ATTRIBUTE(attr_currentspectrum_read);

//-----------------------------------------------------------------------------
//
// function to delete a scalar attribut : You must pass the pointer to the attributs
// Usage :         DELETE_SCALAR_ATTRIBUTE(attr_hCoordinate_read);

//-----------------------------------------------------------------------------
template <class _SCALAR>
void DELETE_SCALAR_ATTRIBUTE(_SCALAR *attributeName)

{
    if(attributeName)
    {
        delete attributeName;
        attributeName = 0;
    }
}

//=============================================================================
// function to allocate and initialise a read SCALAR attribute as generated by POGO
// Usage : ex : CREATE_SCALAR_ATTRIBUTE(attr_hCoordinate_read);
//=============================================================================
template <class _SCALAR>
void CREATE_SCALAR_ATTRIBUTE(_SCALAR *&attributeName, _SCALAR default_value = 0)
{
    attributeName = new _SCALAR;

    if(attributeName == 0)
    {
        TangoSys_OMemStream o;
        o << "[" << __FILE__ << "::" << __LINE__ << "]" << std::ends;
        Tango::Except::throw_exception(
            (const char *) "OUT OF MEMORY", (const char *) "out of memory error", (const char *) (o.str().c_str()));
    }
    // then initialise scalar
    (*attributeName) = (_SCALAR) default_value;
}

//=============================================================================
// function to allocate and initialise a DevString SCALAR attribute as generated by POGO
// Usage : ex : CREATE_DEVSTRING_ATTRIBUTE(attr_currentUMatrix_read,MAX_STRING_LENGTH,"No U Matrix available");
//=============================================================================
inline void CREATE_DEVSTRING_ATTRIBUTE(Tango::DevString *&attributeName, const int length, const char *init_string = "")
{
    attributeName = new char *;

    if(attributeName == 0)
    {
        TangoSys_OMemStream o;
        o << "[" << __FILE__ << "::" << __LINE__ << "]" << std::ends;
        Tango::Except::throw_exception(
            (const char *) "OUT OF MEMORY", (const char *) "out of memory error", (const char *) (o.str().c_str()));
    }

    // std::cout << length << std::endl;
    (*attributeName) = new char[length];
    if((*attributeName) == 0)
    {
        TangoSys_OMemStream o;
        o << "[" << __FILE__ << "::" << __LINE__ << "]" << std::ends;
        Tango::Except::throw_exception(
            (const char *) "OUT OF MEMORY", (const char *) "out of memory error", (const char *) (o.str().c_str()));
    }
    ::strcpy(*attributeName, init_string);
}

//-----------------------------------------------------------------------------
//
// function to delete a DevString attribut : You must pass the pointer to the attributs
// Usage :         DELETE_DEVSTRING_ATTRIBUTE(attr_currentUMatrix_read)

//-----------------------------------------------------------------------------
inline void DELETE_DEVSTRING_ATTRIBUTE(Tango::DevString *attributeName)
{
    if(attributeName)
    {
        if(*attributeName)
        {
            delete[](*attributeName);
        }
        delete attributeName;
        attributeName = 0;
    }
}

//=============================================================================
// function to allocate and initialise a read SPECTRUM attribute as generated by POGO
// Usage : ex : CREATE_SPECTRUM_ATTRIBUTE(attr_currentspectrum_read,MAX_LENGTH);
//=============================================================================
//
template <class _SPECTRUM>
void CREATE_SPECTRUM_ATTRIBUTE(_SPECTRUM *&attributeName, const int size, _SPECTRUM default_value = 0)
{
    attributeName = new _SPECTRUM[size];

    if(attributeName == 0)
    {
        TangoSys_OMemStream o;
        o << "[" << __FILE__ << "::" << __LINE__ << "]" << std::ends;
        Tango::Except::throw_exception(
            (const char *) "OUT OF MEMORY", (const char *) "out of memory error", (const char *) (o.str().c_str()));
    }
    std::fill(attributeName, attributeName + size, default_value);
}

//=============================================================================
// function to desallocate a read SPECTRUM attribute as generated by POGO
// Usage : ex : DELETE_SPECTRUM_ATTRIBUTE(attr_currentspectrum_read);
//=============================================================================
//
template <class _SPECTRUM>
void DELETE_SPECTRUM_ATTRIBUTE(_SPECTRUM *attributeName)
{
    if(attributeName)
    {
        delete[](attributeName);
    }
}
