//******************************************************************************
//
// Restricted Rights
// WARNING: This is a restricted distribution Zeligsoft file.
//
//******************************************************************************
//
// Copyright (C) 2006 Zeligsoft Inc. - All Rights Reserved
//

//******************************************************************************
//
//     FILE: zceReadDataWorker.cpp
//
//******************************************************************************

#include "zceReadDataWorker.h"

#include "zceReadDataPorts.h"

#include "../../Constants.h"
#include "../../Support.h"
#include "../../Configuration.h"

zceReadDataWorker* theWorker;

void zceReadDataWorker::workerThreadFunc()
{
	mIsThreadRunning = true;
	logToFile("Debug", "ReadData", "Thread started!\n");

	bool mIsEOF = false;
	ifstream mInFile;

	// Load initial configuration
	loadConfiguration();

	ostringstream oss;
	oss << "Sending file " << mInputFilePath << "\n";
	logToFile("Debug", "ReadData", oss.str());

	// Open input file
	mInFile.open(mInputFilePath, ios::in | ios::binary);

	if (mInFile.is_open())
	{
		logToFile("Debug", "ReadData", "ReadData opened file...\n");
	}
	else
	{
		logToFile("Error", "ReadData",
				"ReadData cannot initialize, because input file cannot be found...\n");
	}

	while (!mIsEOF) // initialize'de 0, release'de 1 yapılır.
	{
		if (mIsDone)
		{
			logToFile("Debug", "ReadData", "Waveform shutting down.\n");
			break;
		}

		while (mIsStarted == 0) // initialize'de 0, start'ta 1 yapılır, stop'ta 0 yapılır.
		{
			if (mIsDone)
			{
				logToFile("Debug", "ReadData", "Waveform shutting down.\n");
				break;
			}
			usleep(100);
		}

		while (mIsStarted == 1)
		{
			// If application type is data then start pushing packets
			if (mPropApplicationType == 1)
			{
				int packetLength = CONST_DATA_SIZE;
				CF::OctetSequence_var dataPacketOctet = CF::OctetSequence(
						packetLength + 1);
				dataPacketOctet->length(packetLength);

				char ch;
				long packetSize = 0;
				while (mInFile.get(ch))
				{
					dataPacketOctet[packetSize] = ch;
					packetSize++;

					if (packetSize == CONST_DATA_SIZE)
					{
						break;
					}
				}

				if (packetSize == 0)
				{
					// End of File
					mIsEOF = true;
					break;
				}
				else if (packetSize < CONST_DATA_SIZE)
				{
					// Last packet is shorter
					dataPacketOctet->length(packetSize);
				}

				CF::Properties options(0);
				options.length(0);
				portDataOut_->processOctetMsg(dataPacketOctet, options);
				mPacketID++;

				ostringstream message;
				message << "Packet Size of " << mPacketID << " is "
						<< packetSize << "\n";
				logToFile("Debug", "ReadData", message.str());

				usleep(CONF_PACKET_SLEEP_TIME);
			}

			usleep(100);

		} // while mIsStarted

		usleep(100);

	} // while mIsEOF

	if (mInFile.is_open())
	{
		// Close input file
		mInFile.close();

		ostringstream message;
		message << "ReadData closed file with PackeId " << mPacketID << "\n";
		logToFile("Debug", "ReadData", message.str());
	}

	oss.str("");
	if (mIsEOF)
	{
		oss << "Finished sending file " << mInputFilePath << "\n";
	}
	else
	{
		oss << "Terminating without completely sending file "
				<< mInputFilePath << "\n";
	}
	logToFile("Debug", "ReadData", oss.str());

	mIsThreadRunning = false;
	logToFile("Debug", "ReadData", "Thread exited!\n");

} // workerThreadFunc

void* pushData(void* param)
{
	theWorker->workerThreadFunc();
	pthread_exit(0);
}

bool isFileExists(string strFilename) {
  struct stat stFileInfo;
  bool blnReturn;
  int intStat;

  // Attempt to get the file attributes
  intStat = stat(strFilename.c_str(),&stFileInfo);
  if(intStat == 0) {
    // We were able to get the file attributes
    // so the file obviously exists.
    blnReturn = true;
  } else {
    // We were not able to get the file attributes.
    // This may mean that we don't have permission to
    // access the folder which contains this file. If you
    // need to do that level of checking, lookup the
    // return values of stat which will give you
    // more details on why stat failed.
    blnReturn = false;
  }

  return(blnReturn);
}

zceReadDataWorker::zceReadDataWorker( const ReadData_params& execParams, zcePushPorts_OctetSeqConsumerUsesPort* portDataOut ZCE_EXC_ENV_ARG ):
	portDataOut_(portDataOut)
	#if defined(DEBUG_MSGS)
	, debug_(0)
	#endif

{
	ZCE_ASSERT_EXCEPTION_VOID;
	#if defined(DEBUG_MSGS)
	debug_.rdbuf(std::cout.rdbuf());
	#endif


	initExecParams(execParams ZCE_EXC_ENV_PARAM );

	// TODO : Implement constructor for zceReadDataWorker
}

zceReadDataWorker::~zceReadDataWorker()
{
	// TODO : Implement destructor for zceReadDataWorker
}

void zceReadDataWorker::initExecParams( const ReadData_params& params ZCE_EXC_ENV_ARG)
{

	ZCE_ASSERT_EXCEPTION_VOID;
	execParams_.NAMING_CONTEXT_IOR = params.NAMING_CONTEXT_IOR;
	execParams_.NAME_BINDING = params.NAME_BINDING;
	execParams_.COMPONENT_IDENTIFIER = params.COMPONENT_IDENTIFIER;

	// TODO: perform some action based on these exec parameters
}

void zceReadDataWorker::config_propInputFilePath( const CORBA::String_var& propinputfilepath  ZCE_EXC_ENV_ARG )
{
	ZCE_ASSERT_EXCEPTION_VOID;

	// Check whether file exists
	CORBA::String_var mInputToTest;
	mInputToTest = propinputfilepath;
	char* mInputToTestPtr = mInputToTest._retn();
	bool fileFound = isFileExists(mInputToTestPtr);

	if(fileFound)
	{
		mPropInputFilePath = propinputfilepath;

		if(mInputFilePath != NULL)
		{
		   free(mInputFilePath);
		}

		mInputFilePath = mPropInputFilePath._retn();

		ostringstream oss;
		oss << "Input file " << mInputToTestPtr << " is found!\n";
		logToFile("Debug", "ReadData", oss.str());
	}
	else
	{
		ostringstream oss;
		oss << "Input file " << mInputToTestPtr << " is not found!\n";
		logToFile("Debug", "ReadData", oss.str());
		throw(CF::PropertySet::InvalidConfiguration());
	}

	if(mInputToTestPtr != NULL)
	{
	   free(mInputToTestPtr);
	}
}

void zceReadDataWorker::config_propApplicationType( const CORBA::Long& propapplicationtype  ZCE_EXC_ENV_ARG )
{
	ZCE_ASSERT_EXCEPTION_VOID;

    mPropApplicationType = propapplicationtype;
}


void zceReadDataWorker::query_propInputFilePath( CORBA::String_var& propinputfilepath  ZCE_EXC_ENV_ARG  )
{
	ZCE_ASSERT_EXCEPTION_VOID;

	propinputfilepath = mPropInputFilePath;
}

void zceReadDataWorker::query_propApplicationType( CORBA::Long& propapplicationtype  ZCE_EXC_ENV_ARG  )
{
	ZCE_ASSERT_EXCEPTION_VOID;

	propapplicationtype = mPropApplicationType;
}



/*!	\brief
 *
 *	 Describe operation here.
 *
 *	\throw ::CF::LifeCycle::InitializeError
 *
 */
void zceReadDataWorker::CF_LifeCycle_initialize( int portIdentifier ZCE_EXC_ENV_ARG )
{
	ZCE_ASSERT_EXCEPTION_VOID;

	// Load initial configuration
	loadConfiguration();

	mIsDone=0;
	mIsStarted = 0;
	mPacketID = 0;
	mIsThreadRunning = false;
	mThreadId = 0;
	mInputFilePath = NULL;
}

/*!	\brief
 *
 *	 Describe operation here.
 *
 *	\throw ::CF::LifeCycle::ReleaseError
 *
 */
void zceReadDataWorker::CF_LifeCycle_releaseObject( int portIdentifier ZCE_EXC_ENV_ARG )
{
	ZCE_ASSERT_EXCEPTION_VOID;

    mIsStarted=0;
	mIsDone=1;
}

/*!
 * \brief The start operation is provided to command a Resource implementing this
 * interface to start internal processing.
 *
 * Specification reference:  3.1.3.1.6.5.2
 *
 * The start operation puts the Resource in an operating condition.
 *
 * \return This operation does not return a value.
 *
 * \throw StartError The start operation shall raise the StartError exception if
 * an error occurs while starting the resource.
 *
 */
void zceReadDataWorker::CF_Resource_start( int portIdentifier ZCE_EXC_ENV_ARG )
{
	ZCE_ASSERT_EXCEPTION_VOID;

	theWorker = this;

	if(mPropApplicationType == 1)
	{
		if (!mIsThreadRunning)
		{
			// Join with main thread if previous thread is running
			if(mThreadId != 0)
			{
				logToFile("Debug", "ReadData", "Joining thread\n");
				pthread_join(mThreadId, NULL);
				logToFile("Debug", "ReadData", "Joined thread\n");
			}
			logToFile("Debug", "ReadData", "Creating thread\n");
			pthread_create(&mThreadId, NULL, pushData, NULL);
			logToFile("Debug", "ReadData", "Created thread\n");
		}

		mIsStarted = 1;
	}
}

/*!
 * \brief The stop operation is provided to command a Resource implementing this
 * interface to stop internal processing.
 *
 * Specification reference:  3.1.3.1.6.5.1
 *
 * The stop operation shall disable all current operations and put the Resource in
 * a non-operating condition. Subsequent configure, query, and start operations
 * are not inhibited by the stop operation.
 *
 * \return This operation does not return a value.
 *
 * \throw StopError The stop operation shall raise the StopError exception if an
 * error occurs while stopping the resource.
 *
 */
void zceReadDataWorker::CF_Resource_stop( int portIdentifier ZCE_EXC_ENV_ARG )
{
	ZCE_ASSERT_EXCEPTION_VOID;

	mIsStarted = 0;
}


void zceReadDataWorker::setportDataOut( zcePushPorts_OctetSeqConsumerUsesPort& portDataOut )
{
	portDataOut_ = &portDataOut;
}

#if defined(DEBUG_MSGS)
void zceReadDataWorker::setDebugStream(const std::ostream& stream)
{
	debug_.rdbuf(stream.rdbuf());
}

void zceReadDataWorker::debugMsg(const std::string& msg)
{
	if(debug_ != NULL)
	{
		debug_ << msg << std::endl;
	}
}
#endif

// End-Of-File
//------------------------------------------------------------------------------
