/*
 * voipTimer.cpp
 *
 * Copyright (C) 2005, Ranch Networks, Inc.
 *
 * This program 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.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 * Author : Srivatsa Chivukula <srivatsa@ranchnetworks.com>
 *
 */

#ifdef VXWORKS
#include <taskLib.h>
#include "rnos.h"
#endif

#ifdef POSIX
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#endif

#include "sysError.h"

#include "voipTimer.h"
#include "voipTimerManager.h"


#define TIMER_MANAGER(tp) ((VoipTimerManager *)(tp->timer_manager))

/**
 * Timer Main Task
 */
#if defined POSIX
void *timerMainThr(void *arg)
#else
unsigned long WINAPI timerMainThr(void *arg)
#endif
{
    VoipTimerManager *tm;
    unsigned int rticksize;

    if( arg == 0 )
      return NULL; /* -SYS_EINVPTR */

    tm = (VoipTimerManager *)arg;
#ifdef VXWORKS
    rticksize = (unsigned int ) ( tm->unitTic() * sysClkRateGet() / 1000 );
#else
    rticksize = (unsigned int) tm->unitTic();
#endif
    if( rticksize == 0 ) rticksize = 1;
    while(1)
    {
#ifdef VXWORKS
       taskDelay( rticksize );
#elif defined WIN32
       Sleep( rticksize );
#elif defined POSIX
       sleep( rticksize / 1000 );
#endif
       tm->tic();
    }
    return NULL; /* -SYS_FAILURE */
}

void *timermalloc( size_t size )
{
    void *mem_p = 0;
    mem_p = malloc( size );
    return mem_p;
}

void  timerfree( void *p )
{
   free( p );
}


// Pre handler timer handler routine.
int sysTimerPreHandler( TIMER_HANDLER handler_p,
                        void *context, 
                        size_t context_size )
{
   int rc = 0;

   if( handler_p )
   {
       rc = handler_p( context, context_size );
   } 
   return rc;
}

static VoipTimerManager *sysCreateTimerManager( int tic )
{
   VoipTimerManager *tm;
   tm = new VoipTimerManager( timermalloc, timerfree, sysTimerPreHandler ); 
   if( tm != 0 ) {
       if( tm->init( tic ) != SYS_SUCCESS ) {
		   printf("Failed VoipTimerManager\n");
           tm->~VoipTimerManager();
           delete tm;
	   return (VoipTimerManager *)0;
       }
   }
   return tm;
}

static void destroyTimerManager( VoipTimerManager *tm )
{
   if( tm == 0 ) return;
   tm->~VoipTimerManager();
   delete tm;
}

int sysDestroyTimerManager( VoipTimerManager *tm, timer_task_context_t *tp )
{
   if( tm == 0 )
      return SYS_EINVPTR;

   if ( valid_timer_task_context(tp)) {
       // Dont allow destruction of timer manager that
       // is not un-installed.
       if( (void *)tm == tp->timer_manager )
          return -SYS_EINUSE;

       // cancel all timers.
       // Dont care for return value as the timer
       // manager should have been un-installed prior
       // to destruction.
       tm->flush();

       // Install MAIN task's timer manager only if
       // default timer manager is destroyed.
       tm->~VoipTimerManager();
       free( (void*)tm );
       
       return SYS_SUCCESS;
   }
   return -SYS_EINVTCTX;
}


static int installTimerManager( VoipTimerManager *tm, timer_task_context_t *tp)
{
   char name[ ABS_TIMER_TASK_NAME_SIZE + 1];
#if defined VXWORKS
   timer_id_t timerMainTaskHandle;
#elif defined WIN32
   HANDLE timerMainTaskHandle;
   DWORD dwThreadId;
#elif defined POSIX
   pthread_t *timerMainTaskHandle;
   pthread_attr_t attr;
   int status = -1;
#endif
   int priority;

   if ( valid_timer_task_context(tp) ) {
       ABS_TIMER_TASK_NAME( name, tp->task_name, TIMER_TASK_NAME );
       priority = tp->task_priority;
#if defined VXWORKS
       timerMainTaskHandle = taskSpawn(name,
                                       priority,
                                       0,
                                       (int)tp->task_stack_size,
                                       (FUNCPTR)timerMainThr,
                                       (int) tm,
                                       0, 0, 0, 0, 0, 0, 0, 0, 0 );
       if( timerMainTaskHandle < 0 )
#elif defined WIN32
      timerMainTaskHandle = CreateThread(NULL,
                                         (int)tp->task_stack_size,
                                         timerMainThr,
                                         (void *)tm,
                                         0,
                                         &dwThreadId);
       if( timerMainTaskHandle == NULL )
#elif defined POSIX
      timerMainTaskHandle = (pthread_t *)malloc(sizeof(pthread_t));
      pthread_attr_init(&attr);
	  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
      status = pthread_create(timerMainTaskHandle,
								NULL,
								timerMainThr,
								(void*)tm);
       if(( timerMainTaskHandle == NULL ) || ( status != 0 ))
#endif
         return -SYS_FAILURE;

       tp->timer_task_handle = timerMainTaskHandle;

       tp->timer_manager = (void *)tm;
       return SYS_SUCCESS;

   }
   return SYS_EINVPTR;
}

/**
 * Create a Timer Manager and install it. This call is meant to spawn
 * a timer task under the corresponding task context.
 * The task context must be created before calling this routine.
 * SYS_SUCCESS upon success
 */
int sysInstallTimerManager( int unit, timer_task_context_t *tp )
{
   VoipTimerManager *tmrmgr_p;

   tmrmgr_p = sysCreateTimerManager (unit);
   if( tmrmgr_p == 0 ) return -SYS_ENOMEM;

   if ( valid_timer_task_context(tp) ) {
       // Multiple installation of the same timer manager has no effect.
       if( tp->timer_manager != (void *)tmrmgr_p ) {
          return installTimerManager(tmrmgr_p, tp); 
       }
       
       return -SYS_EEXISTS;
   }
   return -SYS_EINVTCTX;
}

static int shutdownTimerManager( timer_task_context_t *tp )
{
   if( tp == 0 )
      return -SYS_EINVPTR;

#if defined VXWORKS
   if ( (rc = taskDelete( tp->timer_task_handle )) == 0 )
#elif defined WIN32
   if ( (rc = CloseHandle( tp->timer_task_handle )) != 0 )
#endif
   {
#if defined POSIX
	   free(tp->timer_task_handle);
#endif
      tp->timer_task_handle = 0;
      TIMER_MANAGER(tp)->shutdown();
   }
      
   return SYS_SUCCESS;
}

int sysUninstallTimerManager( timer_task_context_t *tp )
{
   VoipTimerManager *tm;
   int rc;

   if ( valid_timer_task_context(tp) ) {
      tm = TIMER_MANAGER(tp);
      tm->flush();
      rc = shutdownTimerManager(tp);
      destroyTimerManager(tm);
      return rc;
   }   
   return SYS_EINVTCTX;
}

int sysInitTimerManager( timer_task_context_t *tp, unsigned int tic )
{
/*
   unsigned int rc;
   if ( valid_timer_task_context(tp) ) {
       rc = TIMER_MANAGER(tp)->flush( (unsigned int)tp);
       if( rc == SYS_SUCCESS )
            return TIMER_MANAGER(tp)->init( tic );

   }   
*/
   return -SYS_EINVTCTX;
}


timer_id_t sysSetTimer( timer_task_context_t *tp, sysTimer_t *t)
{
   if (valid_timer_task_context(tp)) {
      return TIMER_MANAGER(tp)->setTimer( t );
   }   

   return 0;
}

int sysGetTimer( timer_task_context_t *tp, timer_id_t handle, sysTimer_t *t )
{
   if ( valid_timer_task_context(tp) ) {
      return TIMER_MANAGER(tp)->getTimer( handle, t);
   }   

   return -SYS_EINVTCTX;
}

int sysCancelTimer( timer_task_context_t *tp, timer_id_t handle )
{
   if ( valid_timer_task_context(tp) ) {
      return TIMER_MANAGER(tp)->cancelTimer( handle );
   }   
   return -SYS_EINVTCTX;
}

int
sysSetTimerContext( timer_task_context_t *tp, timer_id_t handle, void *context_p, size_t context_size )
{
   if ( valid_timer_task_context(tp) ) {
      return TIMER_MANAGER(tp)->setTimerContext( handle, context_p, context_size );
   }   
   return -SYS_EINVTCTX;
}


int sysSetTimerHandler( timer_task_context_t *tp, timer_id_t handle, TIMER_HANDLER handler_p)
{
   if ( valid_timer_task_context(tp) ) {
      return TIMER_MANAGER(tp)->setTimerHandler( handle, handler_p );
   }   
   return -SYS_EINVTCTX;
}

int sysGetElapsedTime( timer_task_context_t *tp, timer_id_t handle, int unit)
{
   if ( valid_timer_task_context(tp) ) {
      return TIMER_MANAGER(tp)->getElapsedTime( handle, unit );
   }   

   return -SYS_EINVTCTX;
}


int sysGetRemainingTime( timer_task_context_t *tp, timer_id_t handle, int unit)
{
   if ( valid_timer_task_context(tp) ) {
      return TIMER_MANAGER(tp)->getRemainingTime( handle, unit );
   }   

   return -SYS_EINVTCTX;
}
