#include <stdio.h>
#include <string.h>
#include "microapp.h"
#include "microperiodichandler.h"
#include "microeventhandler.h"
#include "tasksynchronizer.h"
#include "debug.h"
#include "osutils.h"

MicroApp::MicroApp(const char *systemName,  const char *appName)
{
  DPRINTF_L3("MicroApp::MicroApp() \n");
  
  _systemName = strdup(systemName);
  _appName = strdup(appName);

  _periodicHandler = 0;
  _eventHandler = 0;
  _taskSync = 0;

  // Initialize task params to something reasonable
  _eventHandlerParams.priority = THREAD_PRIORITY_NORMAL;
  _eventHandlerParams.floatingPoint = FALSE;
  _eventHandlerParams.stackSize = 5500;  
  
  _periodicHandlerParams.priority = THREAD_PRIORITY_TIME_CRITICAL;
  _periodicHandlerParams.floatingPoint = FALSE;
  _periodicHandlerParams.stackSize = 5500;
}


MicroApp::~MicroApp()
{
  free((void *)_appName);
  free((void *)_systemName);  

  if(_taskSync != NULL)
	  delete _taskSync;
}

void * MicroApp::run(int argc, char *argv[])
{
  DPRINTF("MicroApp::run()\n");

  if (initialize(argc, argv) == -1)
  {
    DPRINTF("MicroApp::run() - initialize() failed \n");
    return 0;
  }

  // Create and run child tasks
  if (spawnTasks() == -1)
  {
    DPRINTF("MicroApp::run() - spawnTasks() failed \n");
    return 0;
  }

   // Wakeup eventhandler task
  _taskSync->semGive(MicroEventTask);

  while (!_taskSync->_shutdown)
  {	  
	  runApp();

  }

  //TODO: return void* to a status struct...
  return 0;	  
}

int MicroApp::runApp()
{
	return 0;
}

void MicroApp::reset()
{ 
  DPRINTF("MicroApp::reset()\n");
  
  //Set reset flag
  _taskSync->reset(TRUE);
  
  // Wakeup event handler task
  _eventHandler->reset();
  
  //Wakeup sampler task
  _periodicHandler->reset();

  // Wait up to 5 secs for MicroEventTask to confirm reset
  _taskSync->waitForReset(MicroEventTask, 5);

  // Wait up to 5 secs for MicroPeriodicTask to confirm reset
  _taskSync->waitForReset(MicroPeriodicTask, 5);

  //Set reset flag
  _taskSync->reset(FALSE);

  // Handoff semaphore to eventhandler task
  // Event handler task will in turn handoff 
  // to periodichandler task
  _taskSync->semGive(MicroEventTask);   
}

int MicroApp::spawnTasks()
{
 
  DPRINTF("MicroApp::spawnTasks()\n");
  
  // Set priority, stacksize, etc for tasks
  setTaskParams();

  char taskName[512];

  sprintf(taskName, "%sPeriodicHandler", _appName);

	  
  DPRINTF("MicroApp::createPeriodicHandler()\n");
  _periodicHandler = createPeriodicHandler();

  if (_periodicHandler->error())
  {
    setError("MicroApp::createPeriodicHandler() - PeriodicHandler constructor failed");
    return -1;
  }
  
  if(_periodicHandler->activate(taskName, 
									_periodicHandlerParams.priority, 
									0, // no flags
									_periodicHandlerParams.stackSize,
									(TaskBase *)_periodicHandler) != -1)
	_taskSync->setTaskId(MicroPeriodicTask, _periodicHandler->id());	      
  else
  {
	setError("periodicHandler::activate() - Task spawn error.\n");
    return -1;
  } 

  sprintf(taskName, "%sEventHandler", _appName);

  DPRINTF("MicroApp::createEventHandler()\n");
  _eventHandler = createEventHandler();
  if (_eventHandler->error())
  {
    setError("MicroApp::createEventHandler() - EventHandler constructor error.\n");
    return -1;
  }

  if(_eventHandler->activate(taskName, 
									_eventHandlerParams.priority, 
									0, // no flags
									_eventHandlerParams.stackSize,
									(TaskBase *)_eventHandler) != -1)
	_taskSync->setTaskId(MicroPeriodicTask, _eventHandler->id());	      
  else
  {
     setError("eventHandler::activate() - Task spawn error.\n");
    return -1;
  } 

  return 0;
}

int MicroApp::initialize(int argc, char *argv[])
{

  const int nTasks = 3;

  if(!_taskSync) //tasksynchronizer not created yet
	  _taskSync = new TaskSynchronizer(_appName, nTasks);

  if (_taskSync->error())
  {
    setError("MicroApp::initialize() - _taskSync constructor failed");
    return -1;
  }

  return 0;
}
int MicroApp::exit()
{
	// Cannot shutdown if tasksynchronizer never created
	if(_taskSync == NULL) {
		setError("MicroApp::tasksync never created, cannot shutdown");
		return -1;
	}

	// Set shutdown flag
	_taskSync->shutdown();
	
	// Wakeup event handler task and shutdown	
	// Wait up to 10 seconds for task to exit
	if(_eventHandler->shutdown(10) == -1)
		setError("Timed out waiting for MicroEventHandler task to exit");

	//Wakeup periodicHandler task and shutdown
	// Wait up to 20 seconds for task to exit
	if(_periodicHandler->shutdown(20) == -1)
		setError("Timed out waiting for MicroPeriodicHandler task to exit");	

	if(error())
		return -1;

	return 0;
}	
											  
