/*----- PROTECTED REGION ID(TestDeviceClass.cpp) ENABLED START -----*/
//=============================================================================
//
// file :        TestDeviceClass.cpp
//
// description : C++ source for the TestDeviceClass. A singleton
//               class derived from DeviceClass. It implements the
//               command list and all properties and methods required
//               by the �name� once per process.
//
// $Author: graziano $
//
//
//
//=============================================================================
//                This file is generated by POGO
//        (Program Obviously used to Generate tango Object)
//=============================================================================


#include <TestDeviceClass.h>

/*----- PROTECTED REGION END -----*/

//-------------------------------------------------------------------
/**
 *	Create TestDeviceClass singleton and
 *	return it in a C function for Python usage
 */
//-------------------------------------------------------------------
extern "C" {
#ifdef _TG_WINDOWS_

__declspec(dllexport)

#endif

	Tango::DeviceClass *_create_TestDevice_class(const char *name) {
		return TestDevice_ns::TestDeviceClass::init(name);
	}
}


namespace TestDevice_ns
{


//===================================================================
//	Initialize pointer for singleton pattern
//===================================================================
TestDeviceClass *TestDeviceClass::_instance = NULL;

//--------------------------------------------------------
/**
 * method : 		TestDeviceClass::TestDeviceClass(string &s)
 * description : 	constructor for the TestDeviceClass
 *
 * @param s	The class name
 */
//--------------------------------------------------------
TestDeviceClass::TestDeviceClass(string &s):DeviceClass(s)
{
	TANGO_LOG_INFO << "Entering TestDeviceClass constructor" << endl;
	set_default_property();
	get_class_property();
	write_class_property();

	/*----- PROTECTED REGION ID(TestDevice::Class::constructor) ENABLED START -----*/

	/*----- PROTECTED REGION END -----*/	//	TestDevice::Class::constructor

	TANGO_LOG_INFO << "Leaving TestDeviceClass constructor" << endl;
}


//--------------------------------------------------------
/**
 * method : 		TestDeviceClass::~TestDeviceClass()
 * description : 	destructor for the TestDeviceClass
 */
//--------------------------------------------------------
TestDeviceClass::~TestDeviceClass()
{
	/*----- PROTECTED REGION ID(TestDevice::Class::destructor) ENABLED START -----*/

	/*----- PROTECTED REGION END -----*/	//	TestDevice::Class::destructor

	_instance = NULL;
}


//--------------------------------------------------------
/**
 * method : 		TestDeviceClass::init
 * description : 	Create the object if not already done.
 *                  Otherwise, just return a pointer to the object
 *
 * @param	name	The class name
 */
//--------------------------------------------------------
TestDeviceClass *TestDeviceClass::init(const char *name)
{
	if (_instance == NULL)
	{
		try
		{
			string s(name);
			_instance = new TestDeviceClass(s);
		}
		catch (bad_alloc)
		{
			throw;
		}		
	}		
	return _instance;
}

//--------------------------------------------------------
/**
 * method : 		TestDeviceClass::instance
 * description : 	Check if object already created,
 *                  and return a pointer to the object
 */
//--------------------------------------------------------
TestDeviceClass *TestDeviceClass::instance()
{
	if (_instance == NULL)
	{
		cerr << "Class is not initialised !!" << endl;
		exit(-1);
	}
	return _instance;
}




//===================================================================
//	Command execution method calls
//===================================================================
//--------------------------------------------------------
/**
 * method : 		WriteAttrnameClass::execute()
 * description : 	method to trigger the execution of the command.
 *
 * @param	device	The device on which the command must be executed
 * @param	in_any	The command input data
 *
 *	returns The command output data (packed in the Any object)
 */
//--------------------------------------------------------
CORBA::Any *WriteAttrnameClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
	TANGO_LOG_INFO << "WriteAttrnameClass::execute(): arrived" << endl;

	const Tango::DevVarDoubleStringArray	*argin;
	extract(in_any, argin);

	((static_cast<TestDevice *>(device))->write_attrname(argin));
	return new CORBA::Any();
}
//--------------------------------------------------------
/**
 * method : 		ReadAttrnameClass::execute()
 * description : 	method to trigger the execution of the command.
 *
 * @param	device	The device on which the command must be executed
 * @param	in_any	The command input data
 *
 *	returns The command output data (packed in the Any object)
 */
//--------------------------------------------------------
CORBA::Any *ReadAttrnameClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
	TANGO_LOG_INFO << "ReadAttrnameClass::execute(): arrived" << endl;

	const Tango::DevVarStringArray	*argin;
	extract(in_any, argin);

	return insert((static_cast<TestDevice *>(device))->read_attrname(argin));
}
//--------------------------------------------------------
/**
 * method : 		ConfigClass::execute()
 * description : 	method to trigger the execution of the command.
 *
 * @param	device	The device on which the command must be executed
 * @param	in_any	The command input data
 *
 *	returns The command output data (packed in the Any object)
 */
//--------------------------------------------------------
CORBA::Any *ConfigClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
	TANGO_LOG_INFO << "ConfigClass::execute(): arrived" << endl;

	const Tango::DevVarStringArray	*argin;
	extract(in_any, argin);

	((static_cast<TestDevice *>(device))->config(argin));
	return new CORBA::Any();
}
//--------------------------------------------------------
/**
 * method : 		AddClass::execute()
 * description : 	method to trigger the execution of the command.
 *
 * @param	device	The device on which the command must be executed
 * @param	in_any	The command input data
 *
 *	returns The command output data (packed in the Any object)
 */
//--------------------------------------------------------
CORBA::Any *AddClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
	TANGO_LOG_INFO << "AddClass::execute(): arrived" << endl;

	const Tango::DevVarStringArray	*argin;
	extract(in_any, argin);

	((static_cast<TestDevice *>(device))->add(argin));
	return new CORBA::Any();
}
//--------------------------------------------------------
/**
 * method : 		AddDoubleClass::execute()
 * description : 	method to trigger the execution of the command.
 *
 * @param	device	The device on which the command must be executed
 * @param	in_any	The command input data
 *
 *	returns The command output data (packed in the Any object)
 */
//--------------------------------------------------------
CORBA::Any *AddDoubleClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
	TANGO_LOG_INFO << "AddDoubleClass::execute(): arrived" << endl;

	const Tango::DevVarStringArray	*argin;
	extract(in_any, argin);

	((static_cast<TestDevice *>(device))->add_double(argin));
	return new CORBA::Any();
}
//--------------------------------------------------------
/**
 * method : 		AddLongClass::execute()
 * description : 	method to trigger the execution of the command.
 *
 * @param	device	The device on which the command must be executed
 * @param	in_any	The command input data
 *
 *	returns The command output data (packed in the Any object)
 */
//--------------------------------------------------------
CORBA::Any *AddLongClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
	TANGO_LOG_INFO << "AddLongClass::execute(): arrived" << endl;

	const Tango::DevVarStringArray	*argin;
	extract(in_any, argin);

	((static_cast<TestDevice *>(device))->add_long(argin));
	return new CORBA::Any();
}
//--------------------------------------------------------
/**
 * method : 		AddBoolClass::execute()
 * description : 	method to trigger the execution of the command.
 *
 * @param	device	The device on which the command must be executed
 * @param	in_any	The command input data
 *
 *	returns The command output data (packed in the Any object)
 */
//--------------------------------------------------------
CORBA::Any *AddBoolClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
	TANGO_LOG_INFO << "AddBoolClass::execute(): arrived" << endl;

	const Tango::DevVarStringArray	*argin;
	extract(in_any, argin);

	((static_cast<TestDevice *>(device))->add_bool(argin));
	return new CORBA::Any();
}
//--------------------------------------------------------
/**
 * method : 		AddStringClass::execute()
 * description : 	method to trigger the execution of the command.
 *
 * @param	device	The device on which the command must be executed
 * @param	in_any	The command input data
 *
 *	returns The command output data (packed in the Any object)
 */
//--------------------------------------------------------
CORBA::Any *AddStringClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
	TANGO_LOG_INFO << "AddStringClass::execute(): arrived" << endl;

	const Tango::DevVarStringArray	*argin;
	extract(in_any, argin);

	((static_cast<TestDevice *>(device))->add_string(argin));
	return new CORBA::Any();
}
//--------------------------------------------------------
/**
 * method : 		RemoveClass::execute()
 * description : 	method to trigger the execution of the command.
 *
 * @param	device	The device on which the command must be executed
 * @param	in_any	The command input data
 *
 *	returns The command output data (packed in the Any object)
 */
//--------------------------------------------------------
CORBA::Any *RemoveClass::execute(Tango::DeviceImpl *device, const CORBA::Any &in_any)
{
	TANGO_LOG_INFO << "RemoveClass::execute(): arrived" << endl;

	const Tango::DevVarStringArray	*argin;
	extract(in_any, argin);

	((static_cast<TestDevice *>(device))->remove(argin));
	return new CORBA::Any();
}



//===================================================================
//	Properties management
//===================================================================

//--------------------------------------------------------
/**
 * method : 		TestDeviceClass::get_class_property
 * description : 	Get the class property for specified name.
 *
 * @param	name  The property name
 */
//--------------------------------------------------------
Tango::DbDatum TestDeviceClass::get_class_property(string &prop_name)
{
	for (unsigned int i=0 ; i<cl_prop.size() ; i++)
		if (cl_prop[i].name == prop_name)
			return cl_prop[i];
	//	if not found, returns  an empty DbDatum
	return Tango::DbDatum(prop_name);
}


//--------------------------------------------------------
/**
 *	Method      : TestDevice::TestDeviceClass::get_default_device_property()()
 *	Description : Return the default value for device property.
 */
//--------------------------------------------------------
Tango::DbDatum TestDeviceClass::get_default_device_property(string &prop_name)
{
	for (unsigned int i=0 ; i<dev_def_prop.size() ; i++)
		if (dev_def_prop[i].name == prop_name)
			return dev_def_prop[i];
	//	if not found, return  an empty DbDatum
	return Tango::DbDatum(prop_name);
}


//--------------------------------------------------------
/**
 *	Method      : TestDevice::TestDeviceClass::get_default_class_property()()
 *	Description : Return the default value for class property.
 */
//--------------------------------------------------------
Tango::DbDatum TestDeviceClass::get_default_class_property(string &prop_name)
{
	for (unsigned int i=0 ; i<cl_def_prop.size() ; i++)
		if (cl_def_prop[i].name == prop_name)
			return cl_def_prop[i];
	//	if not found, return  an empty DbDatum
	return Tango::DbDatum(prop_name);
}


//--------------------------------------------------------
/**
 *	Method      : TestDevice::TestDeviceClass::get_class_property()
 *	Description : //	Add your own code to initialize
 */
//--------------------------------------------------------
void TestDeviceClass::get_class_property()
{
}


//--------------------------------------------------------
/**
 *	Method      : TestDevice::TestDeviceClass::set_default_property()
 *	Description : Set default property (class and device) for wizard.
 *	              For each property, add to wizard property name and description.
 *	              If default value has been set, add it to wizard property and.
 *	              store it in a DbDatum.
 */
//--------------------------------------------------------
void TestDeviceClass::set_default_property()
{
	string	prop_name;
	string	prop_desc;
	string	prop_def;
	vector<string>	vect_data;
	
	//	Set Default Class Properties

	//	Set Default Device Properties

	prop_name = "Attr_config";
	prop_desc = "";
	prop_def  = "";
	vect_data.clear();
	if (prop_def.length()>0)
	{
		Tango::DbDatum	data(prop_name);
		data << vect_data ;
		dev_def_prop.push_back(data);
		add_wiz_dev_prop(prop_name, prop_desc,  prop_def);
	}
	else
		add_wiz_dev_prop(prop_name, prop_desc);

	prop_name = "MinSaveDBPeriod";
	prop_desc = "";
	prop_def  = "10";
	vect_data.clear();
	if (prop_def.length()>0)
	{
		Tango::DbDatum	data(prop_name);
		data << vect_data ;
		dev_def_prop.push_back(data);
		add_wiz_dev_prop(prop_name, prop_desc,  prop_def);
	}
	else
		add_wiz_dev_prop(prop_name, prop_desc);
}


//--------------------------------------------------------
/**
 *	Method      : TestDevice::TestDeviceClass::write_class_property()
 *	Description : Set class description fields as property in database
 */
//--------------------------------------------------------
void TestDeviceClass::write_class_property()
{
	//	First time, check if database used
	if (Tango::Util::_UseDb == false)
		return;

	Tango::DbData	data;
	string	classname = get_name();
	string	header;
	string::size_type	start, end;

	//	Put title
	Tango::DbDatum	title("ProjectTitle");
	string	str_title("Storage Ring Access");
	title << str_title;
	data.push_back(title);

	//	Put Description
	Tango::DbDatum	description("Description");
	vector<string>	str_desc;
	str_desc.push_back("");
	description << str_desc;
	data.push_back(description);

	//  Put inheritance
	Tango::DbDatum	inher_datum("InheritedFrom");
	vector<string> inheritance;
	inheritance.push_back("Device_Impl");
	inher_datum << inheritance;
	data.push_back(inher_datum);

	//	Call database and and values
	get_db_class()->put_property(data);
}




//===================================================================
//	Factory methods
//===================================================================


//--------------------------------------------------------
/**
 * method : 		TestDeviceClass::device_factory
 * description : 	Create the device object(s)
 *                  and store them in the device list
 *
 * @param	*devlist_ptr	The device name list
 */
//--------------------------------------------------------
void TestDeviceClass::device_factory(const Tango::DevVarStringArray *devlist_ptr)
{

	/*----- PROTECTED REGION ID(TestDevice::Class::device_factory_before) ENABLED START -----*/

	//	Add your own code

	/*----- PROTECTED REGION END -----*/	//	TestDevice::Class::device_factory_before

	//	Create devices and add it into the device list
	for (unsigned long i=0 ; i<devlist_ptr->length() ; i++)
	{
		TANGO_LOG_DEBUG << "Device name : " << (*devlist_ptr)[i].in() << endl;
		device_list.push_back(new TestDevice(this, (*devlist_ptr)[i]));
	}

	//	Manage dynamic attributes if any
	erase_dynamic_attributes(devlist_ptr, get_class_attr()->get_attr_list());

	//	Export devices to the outside world
	for (unsigned long i=1 ; i<=devlist_ptr->length() ; i++)
	{
		//	Add dynamic attributes if any
		TestDevice *dev = static_cast<TestDevice *>(device_list[device_list.size()-i]);
		dev->add_dynamic_attributes();

		//	Check before if database used.
		if ((Tango::Util::_UseDb == true) && (Tango::Util::_FileDb == false))
			export_device(dev);
		else
			export_device(dev, dev->get_name().c_str());
	}

	/*----- PROTECTED REGION ID(TestDevice::Class::device_factory_after) ENABLED START -----*/

	//	Add your own code

	/*----- PROTECTED REGION END -----*/	//	TestDevice::Class::device_factory_after

	
}


//--------------------------------------------------------
/**
 *	Method      : TestDevice::TestDeviceClass::attribute_factory()
 *	Description : Create the attribute object(s)
 *	              and store them in the attribute list
 */
//--------------------------------------------------------
void TestDeviceClass::attribute_factory(vector<Tango::Attr *> &att_list)
{
	/*----- PROTECTED REGION ID(TestDevice::Class::attribute_factory_before) ENABLED START -----*/

	//	Add your own code
	//	Attribute : Ref
	RefAttrib	*ref = new RefAttrib();
	att_list.push_back(ref);

	//	Attribute : Values
	ValuesAttrib	*values = new ValuesAttrib();
	att_list.push_back(values);
	/*----- PROTECTED REGION END -----*/	//	TestDevice::Class::attribute_factory_before


	//	Create a list of static attributes
	create_static_attribute_list(get_class_attr()->get_attr_list());

	/*----- PROTECTED REGION ID(TestDevice::Class::attribute_factory_after) ENABLED START -----*/

	//	Add your own code

	/*----- PROTECTED REGION END -----*/	//	TestDevice::Class::attribute_factory_after

}


//--------------------------------------------------------
/**
 *	Method      : TestDevice::TestDeviceClass::command_factory()
 *	Description : Create the command object(s)
 *	              and store them in the command list
 */
//--------------------------------------------------------
void TestDeviceClass::command_factory()
{
	/*----- PROTECTED REGION ID(TestDevice::Class::command_factory_before) ENABLED START -----*/

	/*----- PROTECTED REGION END -----*/	//	TestDevice::Class::command_factory_before

	ConfigClass	*pConfigCmd =
		new ConfigClass("Config",
				Tango::DEVVAR_STRINGARRAY, Tango::DEV_VOID,
			"Array of attribute names (double) to be created removing everything else",
			"",
			Tango::OPERATOR);
	command_list.push_back(pConfigCmd);

	AddClass	*pAddCmd =
		new AddClass("Add",
				Tango::DEVVAR_STRINGARRAY, Tango::DEV_VOID,
			"Array of attribute to be added.\nSyntax= name:type:value:timestamp.\ntype=double, long, bool, string.\ntimestamp=0 means now.",
			"",
			Tango::OPERATOR);
	command_list.push_back(pAddCmd);

	AddDoubleClass	*pAddDoubleCmd =
		new AddDoubleClass("AddDouble",
				Tango::DEVVAR_STRINGARRAY, Tango::DEV_VOID,
			"Array of double attribute to be added.",
			"",
			Tango::OPERATOR);
	command_list.push_back(pAddDoubleCmd);

	AddLongClass	*pAddLongCmd =
		new AddLongClass("AddLong",
				Tango::DEVVAR_STRINGARRAY, Tango::DEV_VOID,
			"Array of long attribute to be added.",
			"",
			Tango::OPERATOR);
	command_list.push_back(pAddLongCmd);

	AddBoolClass	*pAddBoolCmd =
		new AddBoolClass("AddBool",
				Tango::DEVVAR_STRINGARRAY, Tango::DEV_VOID,
			"Array of boolean attribute to be added.",
			"",
			Tango::OPERATOR);
	command_list.push_back(pAddBoolCmd);

	AddStringClass	*pAddStringCmd =
		new AddStringClass("AddString",
				Tango::DEVVAR_STRINGARRAY, Tango::DEV_VOID,
			"Array of string attribute to be added.",
			"",
			Tango::OPERATOR);
	command_list.push_back(pAddStringCmd);

	RemoveClass	*pRemoveCmd =
		new RemoveClass("Remove",
				Tango::DEVVAR_STRINGARRAY, Tango::DEV_VOID,
			"Array of attribute names to be removed",
			"",
			Tango::OPERATOR);
	command_list.push_back(pRemoveCmd);

	WriteAttrnameClass	*pWriteAttrnameCmd =
		new WriteAttrnameClass("WriteAttrname",
			Tango::DEVVAR_DOUBLESTRINGARRAY, Tango::DEV_VOID,
			"",
			"",
			Tango::OPERATOR);
	command_list.push_back(pWriteAttrnameCmd);

	ReadAttrnameClass	*pReadAttrnameCmd =
		new ReadAttrnameClass("ReadAttrname",
			Tango::DEVVAR_STRINGARRAY, Tango::DEVVAR_DOUBLEARRAY,
			"",
			"",
			Tango::OPERATOR);
	command_list.push_back(pReadAttrnameCmd);

	/*----- PROTECTED REGION ID(TestDevice::Class::command_factory_after) ENABLED START -----*/

	/*----- PROTECTED REGION END -----*/	//	TestDevice::Class::command_factory_after

}




//===================================================================
//	Dynamic attributes related methods
//===================================================================


//--------------------------------------------------------
/**
 * method : 		TestDeviceClass::create_static_attribute_list
 * description : 	Create the a list of static attributes
 *
 * @param	att_list	the ceated attribute list 
 */
//--------------------------------------------------------
void TestDeviceClass::create_static_attribute_list(vector<Tango::Attr *> &att_list)
{
	for (unsigned long i=0 ; i<att_list.size() ; i++)
	{
		string att_name(att_list[i]->get_name());
		transform(att_name.begin(), att_name.end(), att_name.begin(), ::tolower);
		defaultAttList.push_back(att_name);
	}

	TANGO_LOG_INFO << defaultAttList.size() << " attributes in default list" << endl;


	/*----- PROTECTED REGION ID(TestDevice::Class::create_static_att_list) ENABLED START -----*/

	/*----- PROTECTED REGION END -----*/	//	TestDevice::Class::create_static_att_list

}


//--------------------------------------------------------
/**
 * method : 		TestDeviceClass::erase_dynamic_attributes
 * description : 	delete the dynamic attributes if any.
 *
 * @param	devlist_ptr	the device list pointer
 * @param	list of all attributes
 */
//--------------------------------------------------------
void TestDeviceClass::erase_dynamic_attributes(const Tango::DevVarStringArray *devlist_ptr, vector<Tango::Attr *> &att_list)
{
	Tango::Util *tg = Tango::Util::instance();

	for (unsigned long i=0 ; i<devlist_ptr->length() ; i++)
	{	
		Tango::DeviceImpl *dev_impl = tg->get_device_by_name(((string)(*devlist_ptr)[i]).c_str());
		TestDevice *dev = static_cast<TestDevice *> (dev_impl);
		
		vector<Tango::Attribute *> &dev_att_list = dev->get_device_attr()->get_attribute_list();
		vector<Tango::Attribute *>::iterator ite_att;
		for (ite_att=dev_att_list.begin() ; ite_att != dev_att_list.end() ; ++ite_att)
		{
			string att_name((*ite_att)->get_name_lower());
			if ((att_name == "state") || (att_name == "status") || (att_name == "ref"))
				continue;
			vector<string>::iterator ite_str = find(defaultAttList.begin(), defaultAttList.end(), att_name);
			if (ite_str == defaultAttList.end())
			{
				TANGO_LOG_INFO << att_name << " is a UNWANTED dynamic attribute for device " << (*devlist_ptr)[i] << endl;
				Tango::Attribute &att = dev->get_device_attr()->get_attr_by_name(att_name.c_str());
				dev->remove_attribute(att_list[att.get_attr_idx()],true);
				--ite_att;
			}
		}
	}
	/*----- PROTECTED REGION ID(TestDevice::Class::erase_dynamic_attributes) ENABLED START -----*/

	/*----- PROTECTED REGION END -----*/	//	TestDevice::Class::erase_dynamic_attributes

}



	/*----- PROTECTED REGION ID(TestDevice::Class::Additional Methods) ENABLED START -----*/

	/*----- PROTECTED REGION END -----*/	//	TestDevice::Class::Additional Methods

} //	namespace