/*
 *  Copyright (c) by Jaroslav Kysela (Perex soft)
 */

#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <malloc.h>
#include <errno.h>
#include "pmod.h"

long absTick = 0;

struct sTimeSynchro *timeSynchroFirst = NULL;
struct sTimeSynchro *timeSynchroLast = NULL;

void timeSynchroAdd( word order, word row )
{
  struct sTimeSynchro *ts;
  
  if ( ( ts = (struct sTimeSynchro *)malloc( sizeof( struct sTimeSynchro ) ) ) == NULL )
    fatal( "timeSynchroAdd: malloc\n" );
  ts -> tick = absTick;
#ifdef 0
  printf( "add: absTick: %i\n", absTick );
#endif
  ts -> order = order;
  ts -> row = row;
  ts -> next = NULL;
  if ( !timeSynchroFirst )
    timeSynchroFirst = timeSynchroLast = ts;
   else
    {
      timeSynchroLast -> next = ts;
      timeSynchroLast = ts;
    }
}

struct sTimeSynchro *timeSynchroGet( long tick )
{
  static struct sTimeSynchro result;
  struct sTimeSynchro *ts = NULL;
  
  while ( timeSynchroFirst && timeSynchroFirst -> tick <= tick )
    {
      ts = timeSynchroFirst;
      result = *ts;
      timeSynchroFirst = ts -> next;
      free( ts );
    }  
  if ( !ts ) return NULL;
  return &result;
}

void timeSynchroFree()
{
  struct sTimeSynchro *ts;

  while ( timeSynchroFirst )
    {
      ts = timeSynchroFirst;
      timeSynchroFirst = timeSynchroFirst -> next;
      free( ts );
    }
  timeSynchroFirst = timeSynchroLast = NULL;
}

void queueFlush()
{
  int size;
  char *s;

  if ( ( size = _seq_buf - seqBuf ) > 0 )
    {
      if ( size > SIZE_OF_SEQBUF )
        fatal( "timer: seqBuf overflow" );
      if ( write( seqfd, seqBuf, _seq_buf - seqBuf ) < 0 )
        {
          switch ( errno ) {
            case EBADVOICE:	s = "BAD VOICE"; break;
            case EBADSAMPLE:	s = "BAD SAMPLE"; break;
            case EBADRAMP:      s = "BAD RAMP"; break;
            default:		s = strerror( errno );
          }
          fatal( "timer: unable to write buffer [%s] (%i)\n", s, errno );
        }
      _seq_buf = seqBuf;
    }
}

void timerSetup()
{
  if ( ioctl( seqfd, GUS_IOCTL_START_TIMER, CALC_BPM( songTempo ) ) < 0 )
    fatal( "timer: ioctl failed - START TIMER" );
  absTick = 0;
}

void timerNext()
{
  queueFlush();
  doEnvelopeThings();
  doNewThings();
  GUS_DO_WAIT( 1 );
  absTick++;
}
