/*----- PROTECTED REGION ID(PreProcessor.cpp) ENABLED START -----*/
//=============================================================================
//
// file :        PreProcessor.cpp
//
// description : C++ source for the PreProcessor class and its commands.
//               The class is derived from Device. It represents the
//               CORBA servant object which will be accessed from the
//               network. All commands which can be executed on the
//               PreProcessor are implemented in this file.
//
// project :     PreProcessor
//
// 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:  $
//
// $Revision:  $
// $Date:  $
//
// $HeadURL:  $
//
//=============================================================================
//                This file is generated by POGO
//        (Program Obviously used to Generate tango Object)
//=============================================================================


#include <PreProcessor.h>
#include <PreProcessorClass.h>

/*----- PROTECTED REGION END -----*/	//	PreProcessor.cpp

/**
 *  PreProcessor class description:
 *    Pre proccesing generic server
 */

//================================================================
//  The following table gives the correspondence
//  between command and method names.
//
//  Command name  |  Method name
//================================================================
//  State         |  Inherited (no method)
//  Status        |  Inherited (no method)
//  On            |  on
//  Off           |  off
//================================================================

//================================================================
//  Attributes managed is:
//================================================================
//================================================================

namespace PreProcessor_ns
{
/*----- PROTECTED REGION ID(PreProcessor::namespace_starting) ENABLED START -----*/

//	static initializations

/*----- PROTECTED REGION END -----*/	//	PreProcessor::namespace_starting

//--------------------------------------------------------
/**
 *	Method      : PreProcessor::PreProcessor()
 *	Description : Constructors for a Tango device
 *                implementing the classPreProcessor
 */
//--------------------------------------------------------
PreProcessor::PreProcessor(Tango::DeviceClass *cl, string &s)
 : TANGO_BASE_CLASS(cl, s.c_str())
{
	/*----- PROTECTED REGION ID(PreProcessor::constructor_1) ENABLED START -----*/
	init_device();

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::constructor_1
}
//--------------------------------------------------------
PreProcessor::PreProcessor(Tango::DeviceClass *cl, const char *s)
 : TANGO_BASE_CLASS(cl, s)
{
	/*----- PROTECTED REGION ID(PreProcessor::constructor_2) ENABLED START -----*/
	init_device();

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::constructor_2
}
//--------------------------------------------------------
PreProcessor::PreProcessor(Tango::DeviceClass *cl, const char *s, const char *d)
 : TANGO_BASE_CLASS(cl, s, d)
{
	/*----- PROTECTED REGION ID(PreProcessor::constructor_3) ENABLED START -----*/
	init_device();

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::constructor_3
}

//--------------------------------------------------------
/**
 *	Method      : PreProcessor::delete_device()
 *	Description : will be called at device destruction or at init command
 */
//--------------------------------------------------------
void PreProcessor::delete_device()
{
	DEBUG_STREAM << "PreProcessor::delete_device() " << device_name << endl;
	/*----- PROTECTED REGION ID(PreProcessor::delete_device) ENABLED START -----*/

	//	Delete device allocated objects

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::delete_device
}

//--------------------------------------------------------
/**
 *	Method      : PreProcessor::init_device()
 *	Description : will be called at device initialization.
 */
//--------------------------------------------------------
void PreProcessor::init_device()
{
	DEBUG_STREAM << "PreProcessor::init_device() create device " << device_name << endl;
	/*----- PROTECTED REGION ID(PreProcessor::init_device_before) ENABLED START -----*/

    set_state(Tango::INIT);
    set_status("Initializing device");

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::init_device_before


	//	Get the device properties from database
	get_device_property();


	/*----- PROTECTED REGION ID(PreProcessor::init_device) ENABLED START -----*/

    try
    {
            //Create event thread
            m_eventThread_sp = EventThread::create(this, m_configuration_sp);

            //Start device if auto start enabled
//            if(autoStart)
//            {
//                INFO_STREAM << "FitsImporter::init_device() auto start enabled " << endl;
//                on();
//            }
    }
    catch(std::exception& ex)
    {
        set_state(Tango::FAULT);
        std::stringstream error_stream;
        error_stream << "PreProcessor::init_device() " << ex.what() << std::endl;
        set_status(error_stream.str());
    }
    catch(...)
    {
        set_state(Tango::FAULT);
        set_status("PreProcessor::init_device() unknown error");
    }

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::init_device
}

//--------------------------------------------------------
/**
 *	Method      : PreProcessor::get_device_property()
 *	Description : Read database to initialize property data members.
 */
//--------------------------------------------------------
void PreProcessor::get_device_property()
{
	/*----- PROTECTED REGION ID(PreProcessor::get_device_property_before) ENABLED START -----*/

	//	Initialize property data members

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::get_device_property_before


	//	Read device properties from database.
	Tango::DbData	dev_prop;
	dev_prop.push_back(Tango::DbDatum("WatchPath"));
	dev_prop.push_back(Tango::DbDatum("DestPath"));
	dev_prop.push_back(Tango::DbDatum("ScriptPath"));
	dev_prop.push_back(Tango::DbDatum("EventList"));
	dev_prop.push_back(Tango::DbDatum("SleepTime"));
	dev_prop.push_back(Tango::DbDatum("WaitTime"));
	dev_prop.push_back(Tango::DbDatum("WorkerNumber"));

	//	is there at least one property to be read ?
	if (dev_prop.size()>0)
	{
		//	Call database and extract values
		if (Tango::Util::instance()->_UseDb==true)
			get_db_device()->get_property(dev_prop);

		//	get instance on PreProcessorClass to get class property
		Tango::DbDatum	def_prop, cl_prop;
		PreProcessorClass	*ds_class =
			(static_cast<PreProcessorClass *>(get_device_class()));
		int	i = -1;

		//	Try to initialize WatchPath from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  watchPath;
		else {
			//	Try to initialize WatchPath from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  watchPath;
		}
		//	And try to extract WatchPath value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  watchPath;

		//	Try to initialize DestPath from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  destPath;
		else {
			//	Try to initialize DestPath from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  destPath;
		}
		//	And try to extract DestPath value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  destPath;

		//	Try to initialize ScriptPath from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  scriptPath;
		else {
			//	Try to initialize ScriptPath from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  scriptPath;
		}
		//	And try to extract ScriptPath value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  scriptPath;

		//	Try to initialize EventList from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  eventList;
		else {
			//	Try to initialize EventList from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  eventList;
		}
		//	And try to extract EventList value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  eventList;

		//	Try to initialize SleepTime from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  sleepTime;
		else {
			//	Try to initialize SleepTime from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  sleepTime;
		}
		//	And try to extract SleepTime value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  sleepTime;

		//	Try to initialize WaitTime from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  waitTime;
		else {
			//	Try to initialize WaitTime from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  waitTime;
		}
		//	And try to extract WaitTime value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  waitTime;

		//	Try to initialize WorkerNumber from class property
		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
		if (cl_prop.is_empty()==false)	cl_prop  >>  workerNumber;
		else {
			//	Try to initialize WorkerNumber from default device value
			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
			if (def_prop.is_empty()==false)	def_prop  >>  workerNumber;
		}
		//	And try to extract WorkerNumber value from database
		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  workerNumber;
	}

	/*----- PROTECTED REGION ID(PreProcessor::get_device_property_after) ENABLED START -----*/

    try
    {
        if(watchPath.empty())
            throw(invalid_argument("WatchPath property is empty or not defined"));

        if(destPath.empty())
            throw(invalid_argument("DestPath property is empty or not defined"));

        if(scriptPath.empty())
            throw(invalid_argument("ScriptPath property is empty or not defined"));

        if(eventList.empty())
            throw(invalid_argument("EventList property is empty or not defined"));

        for(vector<string>::size_type e_ind=0; e_ind<eventList.size(); ++e_ind)
            if(eventList.at(e_ind).empty())
            {
                stringstream event_list_error;
                event_list_error << "EventList property has an empty element at \""
                        << e_ind << "\" position" << endl;
                throw(invalid_argument(event_list_error.str()));
            }

        //Create i-notify mask from event list property
        const uint32_t inotifyMask = create_inotify_mask(eventList);

        if(sleepTime<MIN_SLEEP_TIME || sleepTime>MAX_SLEEP_TIME)
            throw(invalid_argument("SleepTime property is out of range or not defined"));

        if(waitTime>MAX_WAIT_TIME)
            throw(invalid_argument("WaitTime property is out of range or not defined"));

        if(workerNumber<1 || workerNumber>MAX_WORKER_NUMBER)
            throw(invalid_argument("WorkerNumber property out of range or not defined"));

        m_configuration_sp = Configuration::create(watchPath,
            destPath, scriptPath, workerNumber, sleepTime, waitTime, inotifyMask);
    }
    catch(invalid_argument& ex)
    {
        set_state(Tango::FAULT);
        stringstream error_stream;
        error_stream << "FitsImporter::get_device_property() " << ex.what() << endl;
        set_status(error_stream.str());
    }

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::get_device_property_after
}

//--------------------------------------------------------
/**
 *	Method      : PreProcessor::always_executed_hook()
 *	Description : method always executed before any command is executed
 */
//--------------------------------------------------------
void PreProcessor::always_executed_hook()
{
	INFO_STREAM << "PreProcessor::always_executed_hook()  " << device_name << endl;
	/*----- PROTECTED REGION ID(PreProcessor::always_executed_hook) ENABLED START -----*/

	if(get_state() != Tango::FAULT)
    {
        if(m_eventThread_sp)
        {
            set_state(m_eventThread_sp->readState());

            set_status(m_eventThread_sp->readStatus());
        }
    }

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::always_executed_hook
}

//--------------------------------------------------------
/**
 *	Method      : PreProcessor::read_attr_hardware()
 *	Description : Hardware acquisition for attributes
 */
//--------------------------------------------------------
void PreProcessor::read_attr_hardware(TANGO_UNUSED(vector<long> &attr_list))
{
	DEBUG_STREAM << "PreProcessor::read_attr_hardware(vector<long> &attr_list) entering... " << endl;
	/*----- PROTECTED REGION ID(PreProcessor::read_attr_hardware) ENABLED START -----*/

	//	Add your own code

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::read_attr_hardware
}


//--------------------------------------------------------
/**
 *	Method      : PreProcessor::add_dynamic_attributes()
 *	Description : Create the dynamic attributes if any
 *                for specified device.
 */
//--------------------------------------------------------
void PreProcessor::add_dynamic_attributes()
{
	/*----- PROTECTED REGION ID(PreProcessor::add_dynamic_attributes) ENABLED START -----*/

	//	Add your own code to create and add dynamic attributes if any

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::add_dynamic_attributes
}

//--------------------------------------------------------
/**
 *	Command On related method
 *	Description:
 *
 */
//--------------------------------------------------------
void PreProcessor::on()
{
	DEBUG_STREAM << "PreProcessor::On()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(PreProcessor::on) ENABLED START -----*/

	//	Add your own code

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::on
}
//--------------------------------------------------------
/**
 *	Command Off related method
 *	Description:
 *
 */
//--------------------------------------------------------
void PreProcessor::off()
{
	DEBUG_STREAM << "PreProcessor::Off()  - " << device_name << endl;
	/*----- PROTECTED REGION ID(PreProcessor::off) ENABLED START -----*/

	//	Add your own code

	/*----- PROTECTED REGION END -----*/	//	PreProcessor::off
}

/*----- PROTECTED REGION ID(PreProcessor::namespace_ending) ENABLED START -----*/

//==============================================================================
//	FitsImporter::create_inotify_mask()
//==============================================================================
uint32_t PreProcessor::create_inotify_mask(const std::vector<std::string>& event_list)
    throw(std::invalid_argument)
{
    DEBUG_STREAM << "PreProcessor::create_inotify_mask()  - " << device_name << endl;

	uint32_t iNotifyMask = 0;

	if(event_list.empty())
		throw std::invalid_argument("PreProcessor::create_inotify_mask(): "
                "event list is empty");

	std::vector<std::string>::const_iterator it;
	for(it=event_list.begin(); it!=event_list.end(); it++)
	{
        std::stringstream event_stream;
        event_stream << "FitsImporter::create_inotify_mask() ";

		if(it->compare("IN_ACCESS")==0)
		{
            event_stream << "IN_ACCESS event found";
			iNotifyMask += IN_ACCESS;
		}
		else if(it->compare("IN_MODIFY")==0)
		{

            event_stream << "IN_MODIFY event found";
			iNotifyMask += IN_MODIFY;
		}
		else if(it->compare("IN_ATTRIB")==0)
		{
            event_stream << "IN_ATTRIB event found";
			iNotifyMask += IN_ATTRIB;
		}
		else if(it->compare("IN_CLOSE_WRITE")==0)
		{
            event_stream << "IN_CLOSE_WRITE event found";
			iNotifyMask += IN_CLOSE_WRITE;
		}
		else if(it->compare("IN_CLOSE_NOWRITE")==0)
		{
            event_stream << "IN_CLOSE_NOWRITE event found";
			iNotifyMask += IN_CLOSE_NOWRITE;
		}
		else if(it->compare("IN_OPEN")==0)
		{
            event_stream << "IN_OPEN event found";
			iNotifyMask += IN_OPEN;
		}
		else if(it->compare("IN_MOVED_FROM")==0)
		{
            event_stream << "IN_MOVED_FROM event found";
			iNotifyMask += IN_MOVED_FROM;
		}
		else if(it->compare("IN_MOVED_TO")==0)
		{
            event_stream << "IN_MOVED_TO event found";
			iNotifyMask += IN_MOVED_TO;
		}
		else if(it->compare("IN_DELETE")==0)
		{
            event_stream << "IN_DELETE event found";
			iNotifyMask += IN_DELETE;
		}
		else if(it->compare("IN_DELETE_SELF")==0)
		{
            event_stream << "IN_DELETE_SELF event found";
			iNotifyMask += IN_DELETE_SELF;
		}
		else if(it->compare("IN_CLOSE")==0)
		{
            event_stream << "IN_CLOSE event found";
			iNotifyMask += IN_CLOSE;
		}
		else if(it->compare("IN_MOVE")==0)
		{
            event_stream << "IN_MOVE event found";
			iNotifyMask += IN_MOVE;
		}
		else if(it->compare("IN_ALL_EVENTS")==0)
		{
            event_stream << "IN_ALL_EVENTS event found";
			iNotifyMask += IN_ALL_EVENTS;
		}
		else
			throw std::invalid_argument("FitsImporter::create_inotify_mask() "
                    "string \"" + *it + " \" is invalid inotify event");

        INFO_STREAM << event_stream.str() << endl;
	}

	return iNotifyMask;
}

/*----- PROTECTED REGION END -----*/	//	PreProcessor::namespace_ending
} //	namespace