/*----- PROTECTED REGION ID(UniversalTest.h) ENABLED START -----*/
//=============================================================================
//
// file :        UniversalTest.h
//
// description : Include file for the UniversalTest class
//
// project :     UniversalTest
//
// This file is part of Tango device class.
// 
// Tango is free software: you can redistribute it and/or modify
// it under the terms of the GNU 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 General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with Tango.  If not, see <http://www.gnu.org/licenses/>.
// 
// $Author:  $
// Copyright (C): 2015-2019
//                European Synchrotron Radiation Facility
//                BP 220, Grenoble 38043
//                France
//
// $Revision:  $
// $Date:  $
//
// $HeadURL:  $
//
//=============================================================================
//                This file is generated by POGO
//        (Program Obviously used to Generate tango Object)
//=============================================================================


#ifndef UniversalTest_H
#define UniversalTest_H

#include <tango/tango.h>
#include <map>


/*----- PROTECTED REGION END -----*/	//	UniversalTest.h

#ifdef TANGO_LOG
	// cppTango after c934adea (Merge branch 'remove-cout-definition' into 'main', 2022-05-23)
	// nothing to do
#else
	// cppTango 9.3-backports and older
	#define TANGO_LOG       cout
	#define TANGO_LOG_INFO  cout2
	#define TANGO_LOG_DEBUG cout3
#endif // TANGO_LOG

/**
 *  UniversalTest class description:
 *    The goal of this device server is to be able to provide attributes of every possible Tango type.
 *    It is possible to change dynamically the Quality Factor of a given attribute.
 *    It is possible to make an attribute throw exceptions.
 *    It is possible to change the behaviour of the attributes (increment at each read, read value always set to the set value, 
 *    read value fluctuating around the set value,...)
 *    Some dynamic expert attributes will be created to be able to control the behaviour of the other attributes.
 *    The attributes named xxx_quality will allow to change the quality factor of the attribute named xxx.
 */


namespace UniversalTest_ns
{
/*----- PROTECTED REGION ID(UniversalTest::Additional Class Declarations) ENABLED START -----*/

//	Additional Class Declarations

/*----- PROTECTED REGION END -----*/	//	UniversalTest::Additional Class Declarations

class UniversalTest : public TANGO_BASE_CLASS
{

/*----- PROTECTED REGION ID(UniversalTest::Data Members) ENABLED START -----*/

//	Add your own data members
public:
const std::string USLEEP_CONTROL_SUFFIX = "_usleep_";
const std::string QUALITY_CONTROL_SUFFIX = "_quality_";
const std::string EXCEPTION_CONTROL_SUFFIX = "_throw_";
const std::string RO_READ_VALUE_CONTROL_SUFFIX = "_read_val_";
static const long DEFAULT_SPECTRUM_MAX_DIM_X = 15;
static const long DEFAULT_IMAGE_MAX_DIM_X = 4;
static const long DEFAULT_IMAGE_MAX_DIM_Y = 3;
static const Tango::DevState DEFAULT_STATE_VALUE = Tango::OFF;

private:
std::map<std::string,Tango::AttrQuality> quality_map;
std::map<std::string,Tango::DevBoolean> throw_map;
std::map<std::string,Tango::DevLong> usleep_map;

/*----- PROTECTED REGION END -----*/	//	UniversalTest::Data Members


//	Attribute data members
public:
	Tango::DevState	*attr_setState_read;

//	Constructors and destructors
public:
	/**
	 * Constructs a newly device object.
	 *
	 *	@param cl	Class.
	 *	@param s 	Device Name
	 */
	UniversalTest(Tango::DeviceClass *cl,std::string &s);
	/**
	 * Constructs a newly device object.
	 *
	 *	@param cl	Class.
	 *	@param s 	Device Name
	 */
	UniversalTest(Tango::DeviceClass *cl,const char *s);
	/**
	 * Constructs a newly device object.
	 *
	 *	@param cl	Class.
	 *	@param s 	Device name
	 *	@param d	Device description.
	 */
	UniversalTest(Tango::DeviceClass *cl,const char *s,const char *d);
	/**
	 * The device object destructor.
	 */
	~UniversalTest();


//	Miscellaneous methods
public:
	/*
	 *	will be called at device destruction or at init command.
	 */
	void delete_device();
	/*
	 *	Initialize the device
	 */
	virtual void init_device();
	/*
	 *	Always executed method before execution command method.
	 */
	virtual void always_executed_hook();


//	Attribute methods
public:
	//--------------------------------------------------------
	/*
	 *	Method     : UniversalTest::read_attr_hardware()
	 *	Description: Hardware acquisition for attributes.
	 */
	//--------------------------------------------------------
	virtual void read_attr_hardware(std::vector<long> &attr_list);
	//--------------------------------------------------------
	/*
	 *	Method     : UniversalTest::write_attr_hardware()
	 *	Description: Hardware writing for attributes.
	 */
	//--------------------------------------------------------
	virtual void write_attr_hardware(std::vector<long> &attr_list);

/**
 *	Attribute setState related methods
 *	Description: This represents the state of the device. 
 *               Changing this attribute set_value will invoke the set_state() method with the specified state value.
 *
 *	Data type:	Tango::DevState
 *	Attr type:	Scalar
 */
	virtual void read_setState(Tango::Attribute &attr);
	virtual void write_setState(Tango::WAttribute &attr);
	virtual bool is_setState_allowed(Tango::AttReqType type);


	//--------------------------------------------------------
	/**
	 *	Method     : UniversalTest::add_dynamic_attributes()
	 *	Description: Add dynamic attributes if any.
	 */
	//--------------------------------------------------------
	void add_dynamic_attributes();




//	Command related methods
public:


	//--------------------------------------------------------
	/**
	 *	Method     : UniversalTest::add_dynamic_commands()
	 *	Description: Add dynamic commands if any.
	 */
	//--------------------------------------------------------
	void add_dynamic_commands();

/*----- PROTECTED REGION ID(UniversalTest::Additional Method prototypes) ENABLED START -----*/

//	Additional Method prototypes
	virtual void read_attr_quality(Tango::Attribute &attr);
	virtual void write_attr_quality(Tango::WAttribute &attr);
	virtual bool is_attr_quality_allowed(Tango::AttReqType type);
	virtual void read_attr_throw(Tango::Attribute &attr);
	virtual void write_attr_throw(Tango::WAttribute &attr);
	virtual bool is_attr_throw_allowed(Tango::AttReqType type);
	virtual void read_attr_usleep(Tango::Attribute &attr);
	virtual void write_attr_usleep(Tango::WAttribute &attr);
	virtual bool is_attr_usleep_allowed(Tango::AttReqType type);
	template <class T> void read_scalar_attr(Tango::Attribute &attr);
	template <class T> void write_scalar_attr(Tango::WAttribute &attr);
	template <class T> void read_spectrum_attr(Tango::Attribute &attr);
	template <class T> void write_spectrum_attr(Tango::WAttribute &attr);
	template <class T> void read_image_attr(Tango::Attribute &attr);
	template <class T> void write_image_attr(Tango::WAttribute &attr);
	template <class T> void read_RO_scalar_attr(Tango::Attribute &attr);
	template <class T> void read_RO_spectrum_attr(Tango::Attribute &attr);
	template <class T> void read_RO_image_attr(Tango::Attribute &attr);
	template <class T> void read_RO_ctrl_scalar_attr(Tango::Attribute &attr);
	template <class T> void read_RO_ctrl_spectrum_attr(Tango::Attribute &attr);	
	template <class T> void read_RO_ctrl_image_attr(Tango::Attribute &attr);
	template <class T> void write_scalar_RO_Control_attr(Tango::WAttribute &attr);
	template <class T> void write_spectrum_RO_Control_attr(Tango::WAttribute &attr);
	template <class T> void write_image_RO_Control_attr(Tango::WAttribute &attr);
	virtual bool is_scalar_attr_allowed(Tango::AttReqType type);
	virtual bool is_spectrum_attr_allowed(Tango::AttReqType type);
	virtual bool is_image_attr_allowed(Tango::AttReqType type);
	Tango::AttrQuality get_quality(Tango::Attribute &attr);
	void set_quality(Tango::Attribute &attr);
	void throw_exception_ctrl(Tango::Attribute &attr);
	void usleep_ctrl(Tango::Attribute &attr);

	void add_scalar_attr(const std::string & attr_name,
	                     long data_type,
	                     Tango::AttrWriteType w_type);
	template <class T>	void add_scalar_attribute(const std::string & attr_name,
	                                              long data_type,
	                                              Tango::AttrWriteType w_type);
	template <class T>	void add_image_attribute(const std::string & attr_name,
	                                             long data_type,
	                                             Tango::AttrWriteType w_type,
	                                             long max_dim_x,
	                                             long max_dim_y);
	template <class T>	void add_spectrum_attribute(const std::string & attr_name,
	                                                long data_type,
	                                                Tango::AttrWriteType w_type,
	                                                long max_dim_x);
	void add_quality_control_attribute(const std::string & attr_name);
	void add_throw_except_control_attribute(const std::string & att_name);
	void add_usleep_control_attribute(const std::string & att_name);
	
	template <class T> void add_RO_attr_read_value_control_attribute(const std::string & att_name,
	                                                                 long type,
	                                                                 long max_dim_x = 0,
	                                                                 long max_dim_y = 0);
	/**
	 * set_default_write_value(): Will initialize the corresponding attribute set value to a default value
	 *
	 * @param attr_name: name of the attribute on which we want to set the default write value
	 * @param dim_x: X dimension of the attribute default write value
	 * @param dim_y: Y dimension of the attribute default write value
	 */
	template <class T> void set_default_write_value(const std::string & attr_name, long dim_x=1, long dim_y=0);

/*----- PROTECTED REGION END -----*/	//	UniversalTest::Additional Method prototypes
};

/*----- PROTECTED REGION ID(UniversalTest::Additional Classes Definitions) ENABLED START -----*/

//	Additional Classes Definitions
bool ends_with(const std::string &str, const std::string &suffix);

class UniversalScalarQualityAttrib: public Tango::Attr
{
public:
	UniversalScalarQualityAttrib(const char *name)
		:Attr(name, Tango::DEV_ENUM, Tango::READ_WRITE) {};
	~UniversalScalarQualityAttrib() {};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_attr_quality(att);
	}
	virtual void write(Tango::DeviceImpl *dev,Tango::WAttribute &att)
	{
		(static_cast<UniversalTest *>(dev))->write_attr_quality(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_attr_quality_allowed(ty);
	}
	virtual bool same_type(const std::type_info &in_type) 
	{
		return typeid(Tango::AttrQuality) == in_type;
	}
	virtual std::string get_enum_type() 
	{
		return std::string("AttrQuality");
	}
};

class UniversalScalarThrowExceptionAttrib: public Tango::Attr
{
public:
	UniversalScalarThrowExceptionAttrib(const char *name)
		:Attr(name,Tango::DEV_BOOLEAN,Tango::READ_WRITE) {};
	~UniversalScalarThrowExceptionAttrib() {};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_attr_throw(att);
	}
	virtual void write(Tango::DeviceImpl *dev,Tango::WAttribute &att)
	{
		(static_cast<UniversalTest *>(dev))->write_attr_throw(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_attr_throw_allowed(ty);
	}
};

class UniversalScalarUSleepAttrib: public Tango::Attr
{
public:
	UniversalScalarUSleepAttrib(const char *name)
		:Attr(name,Tango::DEV_LONG,Tango::READ_WRITE) {};
	~UniversalScalarUSleepAttrib() {};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_attr_usleep(att);
	}
	virtual void write(Tango::DeviceImpl *dev,Tango::WAttribute &att)
	{
		(static_cast<UniversalTest *>(dev))->write_attr_usleep(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_attr_usleep_allowed(ty);
	}
};

template <class T> 
class UniversalScalarRWAttrib: public Tango::Attr
{
public:
	UniversalScalarRWAttrib(const char *name,long data_type,Tango::AttrWriteType w_type)
		:Attr(name,data_type,w_type)
	{
		scalar_attr_read = new T();
	};
	~UniversalScalarRWAttrib()
	{
		delete scalar_attr_read;
	};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_scalar_attr<T>(att);
	}
	virtual void write(Tango::DeviceImpl *dev,Tango::WAttribute &att)
	{
		(static_cast<UniversalTest *>(dev))->write_scalar_attr<T>(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_scalar_attr_allowed(ty);
	}
// members
	T * scalar_attr_read;
};

template <class T> 
class UniversalImageRWAttrib: public Tango::ImageAttr
{
public:
	UniversalImageRWAttrib(const char *name,long data_type,Tango::AttrWriteType w_type,long max_dim_x,long max_dim_y)
		:ImageAttr(name,data_type,w_type,max_dim_x,max_dim_y)
	{
		dim_x = max_dim_x? max_dim_x:1;
		dim_y = max_dim_y? max_dim_y:1;
		attr_read = new T[dim_x * dim_y];
		std::memset(attr_read,0,dim_x * dim_y * sizeof(T));
	};
	~UniversalImageRWAttrib()
	{
		if(attr_read)
		{
			delete [] attr_read;
			attr_read = 0;
		}
	};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_image_attr<T>(att);
	}
	virtual void write(Tango::DeviceImpl *dev,Tango::WAttribute &att)
	{
		(static_cast<UniversalTest *>(dev))->write_image_attr<T>(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_image_attr_allowed(ty);
	}
// members
	T * attr_read;
	long dim_x;
	long dim_y;
};

template <class T> 
class UniversalSpectrumRWAttrib: public Tango::SpectrumAttr
{
public:
	UniversalSpectrumRWAttrib(const char *name,long data_type,Tango::AttrWriteType w_type,long max_dim_x)
		:SpectrumAttr(name,data_type,w_type,max_dim_x)
	{
		dim_x = max_dim_x? max_dim_x:1;
		attr_read = new T[dim_x];
		std::memset(attr_read,0,dim_x * sizeof(T));
	};
	~UniversalSpectrumRWAttrib()
	{
		if(attr_read)
		{
			delete [] attr_read;
			attr_read = 0;
		}
	};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_spectrum_attr<T>(att);
	}
	virtual void write(Tango::DeviceImpl *dev,Tango::WAttribute &att)
	{
		(static_cast<UniversalTest *>(dev))->write_spectrum_attr<T>(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_spectrum_attr_allowed(ty);
	}
// members
	T * attr_read;
	long dim_x;
};

/**
 * class UniversalScalarROControlAttrib
 * This class represents a RW attribute which will be used to control the 
 * value returned by another Scalar Read Only attribute
 */
template <class T> 
class UniversalScalarROControlAttrib: public Tango::Attr
{
public:
	UniversalScalarROControlAttrib(const char *name,long data_type)
		:Attr(name,data_type,Tango::READ_WRITE)
	{
		scalar_attr_read = new T();
	};
	~UniversalScalarROControlAttrib()
	{
		delete scalar_attr_read;
	};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_RO_ctrl_scalar_attr<T>(att);
	}
	virtual void write(Tango::DeviceImpl *dev,Tango::WAttribute &att)
	{
		(static_cast<UniversalTest *>(dev))->write_scalar_RO_Control_attr<T>(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_scalar_attr_allowed(ty);
	}
// members
	T * scalar_attr_read;
};

/**
 * class UniversalSpectrumROControlAttrib
 * This class represents a RW attribute which will be used to control the 
 * value returned by another Spectrum Read Only attribute
 */
template <class T> 
class UniversalSpectrumROControlAttrib: public Tango::SpectrumAttr
{
public:
	UniversalSpectrumROControlAttrib(const char *name,long data_type,long max_dim_x)
		:SpectrumAttr(name,data_type,Tango::READ_WRITE,max_dim_x)
	{
		dim_x = max_dim_x? max_dim_x:1;
		attr_read = new T[dim_x];
		std::memset(attr_read,0,dim_x * sizeof(T));
	};
	~UniversalSpectrumROControlAttrib()
	{
		if(attr_read)
		{
			delete [] attr_read;
			attr_read = 0;
		}
	};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_RO_ctrl_spectrum_attr<T>(att);
	}
	virtual void write(Tango::DeviceImpl *dev,Tango::WAttribute &att)
	{
		(static_cast<UniversalTest *>(dev))->write_spectrum_RO_Control_attr<T>(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_spectrum_attr_allowed(ty);
	}
// members
	T * attr_read;
	long dim_x;
};

/**
 * class UniversalImageROControlAttrib
 * This class represents a RW attribute which will be used to control the 
 * value returned by another Image Read Only attribute
 */
template <class T> 
class UniversalImageROControlAttrib: public Tango::ImageAttr
{
public:
	UniversalImageROControlAttrib(const char *name,
	                              long data_type,
	                              long max_dim_x,
	                              long max_dim_y)
		:ImageAttr(name,data_type,Tango::READ_WRITE,max_dim_x,max_dim_y)
	{
		dim_x = max_dim_x? max_dim_x:1;
		dim_y = max_dim_y? max_dim_y:1;
		attr_read = new T[dim_x*dim_y];
		std::memset(attr_read,0,dim_x * dim_y * sizeof(T));
	};
	~UniversalImageROControlAttrib()
	{
		if(attr_read)
		{
			delete [] attr_read;
			attr_read = 0;
		}
	};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_RO_ctrl_image_attr<T>(att);
	}
	virtual void write(Tango::DeviceImpl *dev,Tango::WAttribute &att)
	{
		(static_cast<UniversalTest *>(dev))->write_image_RO_Control_attr<T>(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_image_attr_allowed(ty);
	}
// members
	T * attr_read;
	long dim_x;
	long dim_y;
};

template <class T> 
class UniversalScalarROAttrib: public Tango::Attr
{
public:
	UniversalScalarROAttrib(const char *name,long data_type)
		:Attr(name,data_type,Tango::READ)
	{
		scalar_attr_read = new T();
	};
	~UniversalScalarROAttrib()
	{
		delete scalar_attr_read;
	};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_RO_scalar_attr<T>(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_scalar_attr_allowed(ty);
	}
// members
	T * scalar_attr_read;
};

template <class T> 
class UniversalSpectrumROAttrib: public Tango::SpectrumAttr
{
public:
	UniversalSpectrumROAttrib(const char *name,long data_type,long max_dim_x)
		:SpectrumAttr(name,data_type,Tango::READ,max_dim_x)
	{
		dim_x = max_dim_x? max_dim_x:1;
		attr_read = new T[dim_x];
		std::memset(attr_read,0,dim_x * sizeof(T));
	};
	~UniversalSpectrumROAttrib()
	{
		if(attr_read)
		{
			delete [] attr_read;
			attr_read = 0;
		}
	};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_RO_spectrum_attr<T>(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_spectrum_attr_allowed(ty);
	}
// members
	T * attr_read;
	long dim_x;
};

template <class T> 
class UniversalImageROAttrib: public Tango::ImageAttr
{
public:
	UniversalImageROAttrib(const char *name,long data_type,long max_dim_x,long max_dim_y)
		:ImageAttr(name,data_type,Tango::READ,max_dim_x,max_dim_y)
	{
		dim_x = max_dim_x? max_dim_x:1;
		dim_y = max_dim_y? max_dim_y:1;
		attr_read = new T[dim_x*dim_y];
		std::memset(attr_read,0,dim_x * dim_y * sizeof(T));
	};
	~UniversalImageROAttrib()
	{
		if(attr_read)
		{
			delete [] attr_read;
			attr_read = 0;
		}
	};

	virtual void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
	{
		(static_cast<UniversalTest *>(dev))->read_RO_image_attr<T>(att);
	}
	virtual bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
	{
		return (static_cast<UniversalTest *>(dev))->is_spectrum_attr_allowed(ty);
	}
// members
	T * attr_read;
	long dim_x;
	long dim_y;
};


/*----- PROTECTED REGION END -----*/	//	UniversalTest::Additional Classes Definitions

}	//	End of namespace

#endif   //	UniversalTest_H
