/*

  LongName - Driver that offers writing of long file names.

*/
#include <vo_stdio.h>
#include <volink.h>     /* Linker directives like DLLENTRY */
#include <apploader.h>  /* RunLibraryFunction etc */
#include <kernel.h>
#include <lcd.h>
#include <stdbuttons.h>
#include <string.h>
#include <stdlib.h>
#include <lists.h>
#include <sysmemory.h>
#include <audio.h>
#include <imem.h>
#include <unistd.h>
#include "rename.h"
#include "longname.h"

#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))


#if 0
#  define VERBOSE
#endif

char *StrDup(register const char *s) {
  int toCopy = strlen(s)+1;
  char *d = malloc(toCopy);
  if (d) memcpy(d, s, toCopy);
  return d;
}

struct LongName longName;


VO_FILE *LongNameFOpen(const char *fileName, const char *mode) {
  VO_FILE *fp = NULL;
  int tmpNameLen;
  const char *p;
  int idx = -1;
  struct LongFile *lf = NULL;
  const char *mutexDisableP = fileName;
  
#ifdef VERBOSE
  printf("LongNameFOpen(\"%s\", \"%s\")...\n", fileName, mode);
  Delay(10);
#endif
#if 0
  printf("OpenMutexDisableP %04x=%s, mutexDisableP %04x=%s\n",
	 longName.openMutexDisableP, longName.openMutexDisableP,
	 mutexDisableP, mutexDisableP); Delay(100);
#endif
#if 1
  if (longName.openMutexDisableP != mutexDisableP) {
    ObtainMutex(&longName.fileMutex);
  }
#endif
  
#if 1
  if (mode[0] == 'w') {
    idx = 0;
    lf = longName.longFile;
    
    while (idx < __FOPEN_MAX_FILES && lf->fp) {
      lf++;
      idx++;
    }
    if (idx >= __FOPEN_MAX_FILES) {
      idx = -1;
      goto finally;
    } else {
      u_int16 canBe83 = 0;
      if ((p = strrchr(fileName, '/')) || *(p = fileName+1) == ':') {
	p++;
      } else {
	p = fileName;
      }
      if (CanBe83(p) & F83_CAN_BE_83) {
	idx = -1;
      } else {
	tmpNameLen = p-fileName + 13; /* 13 = 8.3 + '\0' */
	if (!(lf->resName = StrDup(fileName)) ||
	    !(lf->tmpName = malloc(tmpNameLen))) {
	  if (lf->resName) free(lf->resName);
	  goto finally;
	}

	Unlink(lf->resName);

	memcpy(lf->tmpName, fileName, p-fileName);
	p = lf->tmpName+(p-fileName);
	sprintf(p, "LFN_%04X.TMP", (u_int16)(rand()));
	fileName = lf->tmpName;
      }
    }
  }
#endif

#if 1
  fp = longName.fopen_orig(fileName, mode);
#else
  fp = (void *)rand();
#endif
  if (idx >= 0) lf->fp = fp;
#ifdef VERBOSE
  printf("LongFOpen = 0x%04x\n", fp);
  Delay(10);
#endif


 finally:
#if 1
  if (longName.openMutexDisableP != mutexDisableP) {
    ReleaseMutex(&longName.fileMutex);
  } else {
    longName.closeMutexDisableP = fp;
  }
#endif
 
  return fp;
}


ioresult LongNameFClose(register __i0 VO_FILE *fp) {
  ioresult res = 0;
  int idx;
  struct LongFile *lf = NULL;
  
#ifdef VERBOSE
  printf("LongNameFClose(%04x) = ", fp);
  Delay(10);
#endif
  if (longName.closeMutexDisableP != fp) {
    ObtainMutex(&longName.fileMutex);
  }
  res = longName.fclose_orig(fp); /* Don't forget fp, we'll need it later. */
#ifdef VERBOSE
  printf("%x\n", res);
  Delay(10);
#endif

  lf = longName.longFile;
  for (idx=0; idx<__FOPEN_MAX_FILES; idx++) {
    if (fp == lf->fp) {
      lf->fp = NULL;
      res = Rename(lf->tmpName, lf->resName);
      free(lf->tmpName);
      free(lf->resName);
      goto finally;
    }
    lf++;
  }

 finally:
  if (longName.closeMutexDisableP != fp) {
    ReleaseMutex(&longName.fileMutex);
  } else {
    longName.closeMutexDisableP = NULL;
  }

  return res;
}


#if 1
void init(void) {
  longName.fopen_orig = (void *)((u_int16)(ReadIMem((u_int16)vo_fopen)>>6L));
  SetHandler(vo_fopen, LongNameFOpen);

  longName.fclose_orig = (void *)((u_int16)(ReadIMem((u_int16)vo_fclose)>>6L));
  SetHandler(vo_fclose, LongNameFClose); 	

  longName.fileMutex = 1;
}


void fini(void) {
  if ((u_int16)(ReadIMem((u_int16)vo_fopen)>>6) != (u_int16)LongNameFOpen ||
      (u_int16)(ReadIMem((u_int16)vo_fclose)>>6) != (u_int16)LongNameFClose) {
    printf("E: Can't restore fopen()/fclose() pointers, hanging up");
    while (1) Sleep();
  }
  SetHandler(vo_fclose, longName.fclose_orig);
  SetHandler(vo_fopen, longName.fopen_orig);
}
#endif

ioresult main(char *parameters) {
  int nParam, i;
  char *p = parameters;
  ioresult retVal = S_ERROR;

  srand((u_int16)ReadTimeCount());

  nParam = RunProgram("ParamSpl", (u_int16)parameters);
  for (i=0; i<nParam; i++) {
    if (!strcmp(p, "-h")) {
      printf("Usage: LongName [-h]\n"
	     "-h\tShow this help\n");
      goto finally_ok;
    } else {
      printf("E: Unknown parameter \"%s\"\n", p);
      goto finally;
    }
    p += strlen(p)+1;
  }

 finally_ok:
  retVal = S_OK;
 finally:
  return retVal;
}
