//
// CRAM: CREATE Real-time Applications Manager
// See the copyright and acknowledgment of authors in the file COPYRIGHT
//
//// ClockService.cpp -- Clock Service (test program) ////
//
//	Usage:
//		ClockService name li_port em_port [period]
//
// This is an example of a CRAM application; it simply logs the time every "mPeriod" seconds.
//

#include "ClockService.h"
#include <time.h>
#include <signal.h>

using namespace cram;
using namespace std;

// Constructors

ClockService :: ClockService(char * name, unsigned short lport, unsigned short eport) 
			: Server(name, lport, eport), 
			  mPeriod(30), 
			  mRunning(false) {
	mOptions.push_back(make_pair (string("period"), string("60")));
	mAppStatus = CRAM_INIT;
}
	
ClockService :: ClockService(char * name, unsigned short lport, unsigned short eport, unsigned period)
			: Server(name, lport, eport), 
			  mPeriod(period), 
			  mRunning(false) {
	char pdstr[8];
	sprintf(pdstr, "%d", period);
	mOptions.push_back(make_pair (string("period"), string(pdstr)));
	mAppStatus = CRAM_INIT;
}

// The clock loop thread process -- log the time every "period" seconds

extern "C" void * clock_loop (void * inst) {
	ClockService * clock = (ClockService *) inst;
	Logger log = clock->mLog;
	time_t now;
	char msg[26];
	while (true) {
		if (clock->mRunning) {
			now = time(NULL);
			ctime_r(& now, msg);
			msg[24] = '\0';		// fix the fact that ctime puts '\n' in the string
			log.log_msg(kLogInfo, "It's %s.", msg);
		//	printf("--me--It's %s.\n", msg);
		}
		sleep(clock->mPeriod);
	}
}

// Class methods

void ClockService :: start(void) {
	mLog.log_msg("[Starting clock thread]");
	mAppStatus = CRAM_ON;
	mRunning = true;
	int err = pthread_create( & mLoop, NULL, clock_loop, (void *) this);
	if (err !=0 )
		mLog.log_msg(kLogError, "Error starting clock loop thread %d\n", err);
}

void ClockService :: stop(void) {
	mLog.log_msg(kLogImportant, "[Stopping clock thread]");
	mAppStatus = CRAM_OFF;
	pthread_kill(mLoop, SIGINT);
}

// Suspend/resume are optional in services

void ClockService :: suspend(void) {
	mLog.log_msg(kLogImportant, "[Suspending clock thread]");
	mAppStatus = CRAM_SUSPENDED;
	mRunning = false;
}

void ClockService :: resume(void) {
	mLog.log_msg(kLogImportant, "[Resuming clock thread]");
	mAppStatus = CRAM_ON;
	mRunning = true;
}

// Set clock-specific options

void ClockService :: set_opt(const char * nam, const char * val) {
	int i_val;
	
	mLog.log_msg("[Configure %s = %s]", nam, val);
	if ( ! strcmp(nam, "period")) {
		i_val = atoi(val);
		if (i_val < 10)		i_val = 10;
		if (i_val > 600)	i_val = 600;
		mPeriod = i_val;
		return;
	}
	Program :: set_opt(nam, val);				// else hand it up to the superclass
}

//
//// MAIN -- creating the ClockService instance starts its reader thread, so main just waits
// 		

int main(int argc, char * argv[]) {
	cram::ClockService * clock;

	if (argc < 4) {
		printf("Usage: %s service_name listener_port emergency_port [period]\n", argv[0]);
		exit(0);
	}
	int lport = atoi(argv[2]);
	int eport = atoi(argv[3]);
	if (argc > 4) {
		int period = atoi(argv[4]);
		if (period < 10)	period = 10;
		if (period > 600)	period = 600;
		clock = new ClockService(argv[1], lport, eport, period);
	} else {
		clock = new ClockService(argv[1], lport, eport);
	}
	if (clock->start_threads() != 0) {				// start the listener and emergency threads
		printf("\t[%s: FATAL: Application start-up failed]\n", argv[1]);
	} else {
		pthread_join(clock->mEThread, NULL);	// suspend until emergency thread terminates
		printf("\t[%s: Server terminated]\n", argv[1]);
	}
					// Wait for the command thread to die.
					// Normally, you would run your application here...
	pthread_join(clock->mEThread, NULL);
	delete clock;
	exit(0);
}
