/*

  PlayFilD - Play 2 MP3 files at the same time Driver

*/
#include <vo_stdio.h>
#include <volink.h>     /* Linker directives like DLLENTRY */
#include <apploader.h>  /* RunLibraryFunction etc */
#include <timers.h>
#include <libaudiodec.h>
#include <vsostasks.h>
#include <consolestate.h>
#include <ctype.h>
#include <uimessages.h>
#include <string.h>
#include <stdlib.h>
#include <audio.h>
#include <aucommon.h>
#include <sysmemory.h>
#include <kernel.h>
#include <taskandstack.h>
#include <cyclic.h>

void *decoderLibrary = NULL;
AUDIO_DECODER *audioDecoder = NULL;
char *errorString = "";
int eCode = 0;
int running = 1;
int isCyclic = 0;

u_int16 *audioLib = NULL;
FILE *audioFp = NULL;
char *audioFileName = NULL;

ioresult PlayFile(FILE *fp) {
  s_int32 lastSeconds = -1, newSeconds;
  s_int16 lastPerCent = -1;
  static s_int16 cmdLen = -1;

  audioDecoder =
    CreateAudioDecoder(decoderLibrary, fp, audioFp, NULL, auDecFGuess);

  if (!audioDecoder) {
    printf("!createAuDec\n");
    return S_ERROR;
  }

  audioDecoder->pause = 0;
  audioDecoder->cs.fastForward = 0;
  audioDecoder->cs.cancel = 0;

  eCode = DecodeAudio(decoderLibrary, audioDecoder, &errorString);
	
#if 1
  printf("Decode returned %d, %s.\n", eCode, errorString);
#endif

  DeleteAudioDecoder(decoderLibrary, audioDecoder);

  return S_OK;
}



struct TaskAndStack *taskAndStack = NULL;
static char fnumMode[10];

void PlayFilDTask(void) {
  FILE *fp = NULL;

  while (running) {
    Delay(100);
    if (audioFileName) {
      if (audioFileName == (char *)0xFFFFU) {
	audioFileName = NULL;
      } else {
	printf("Play %s\n", audioFileName);
	fp = fopen(audioFileName, "rb");
	if (!fp) {
	  printf("E: Can't open %s\n", audioFileName);
	} else {
	  ioresult playErr;
	  audioFileName = (char *)0xFFFE;
	  playErr = PlayFile(fp);
	  fclose(fp);
	}
	audioFileName = NULL;
      }
    }
  }
 finally:
  ;
}



int TryAudioLibrary(char *audioLibName) {
  if (!(audioLib = LoadLibrary(audioLibName))) {
    return 0;
  }
  audioFp = (FILE *)RunLoadedFunction(audioLib, ENTRY_3, 0);
  if (!audioFp) {
    DropLibrary(audioLib);
    audioLib = NULL;
    return 0;
  }

  /* Close file so that e.g. AuOutput may access it.
     It's naughty to continue using audioFp even after closing the
     file, but necessary until a better way can be thought about. */
  RunLoadedFunction(audioLib, ENTRY_4, (s_int16)audioFp);

  return 1;
}


void CheckCancel(register struct CyclicNode *cyclicNode) {
  if (audioFileName == (char *)0xFFFF) {
    audioDecoder->cs.cancel = 1;
  }
}

struct CyclicNode checkCancel =  {{0}, CheckCancel};



ioresult init(const char *parameters) {
  u_int16 *p/*thisLib*/ = loadedLib[loadedLibs-1];
  /* Invalidate library pointer to force it *not* to be shared between
     different tasks. */
  p += *p + 4;
  *(u_int32 *)p = -1;
}


ioresult main(char *parameters) {
  int nParam, i;
  FILE *fp = NULL;
  char *p = parameters;
  char *audioDriverName = NULL;
  int verbose = 0;
  int retCode = S_ERROR;
  int audioLibNum = 0;
  char *symName = NULL;

  nParam = RunProgram("ParamSpl", parameters);
  for (i=0; i<nParam; i++) {
    if (!strcmp(p, "-h")) {
      printf("Usage: PlayFilD [-1|-2|-h] driv\n"
	     "-1\tStart driver task 1\n"
	     "-2\tStart driver task 2\n"
	     "driv\tUse audio driver driv\n"
	     "-h\tShow this help\n");
      goto finally;
    } else if (!strcmp(p, "-1")) {
      symName = "_playFil1";
    } else if (!strcmp(p, "-2")) {
      symName = "_playFil2";
    } else if (!audioDriverName) {
      audioDriverName = p;
    } else {
      printf("E: Extraneous parameter \"%s\"\n", p);
      goto finally;
    }
    p += strlen(p)+1;
  }

  if (!audioDriverName) {
    printf("E: No audio driver name specified\n");
    goto finally;
  }

  if (!symName) {
    printf("E: No driver task specified\n", audioDriverName);
    goto finally;
  }

  if (!TryAudioLibrary(audioDriverName)) {
    printf("E: Cannot load audio library %s\n", audioDriverName);
    goto finally;
  }

  AddSymbol(symName, (void *)0x279e, (int)(&audioFileName));

  decoderLibrary = LoadLibrary("audiodex");
  if (!decoderLibrary) {
    printf("!audiodex\n");
    goto finally;
  }

  AddCyclic(&checkCancel, 50, 50);
  isCyclic = 1;

  /* Start PlayFilD task */
  if (!(taskAndStack = CreateTaskAndStack(PlayFilDTask, symName, 512, 2))) {
    printf("Couldn't start audio task\n");
    goto finally;
  }

  retCode = S_OK;
 finally:

  return retCode; /* End of files, ok exit */
}

void fini(void) {
  if (isCyclic) DropCyclic(&checkCancel);

  if (taskAndStack) {
    running = 0;
    audioDecoder->cs.cancel = 1;

    while (taskAndStack->task.tc_State &&
	   taskAndStack->task.tc_State != TS_REMOVED) {
      Delay(TICKS_PER_SEC/100);
    }
    FreeTaskAndStack(taskAndStack);
  }

  if (decoderLibrary) {
    DropLibrary(decoderLibrary);
  }
  if (audioLib) {
    DropLibrary(audioLib);
    audioLib = NULL;
  }
}
