#include "h/common.h"
#include "h/pll.h"
#include "h/playrecord.h"
#include <math.h>
#include "h/dac.h"
#include "h/ir.h"
#include "h/lcd16x2.h"
#include "h/oled.h"
#include "h/clock.h"
#include "h/string.h"
#include "h/buttons.h"

FATFS			fileSystem;
FIL				fsrc;
FIL 			fdst;
FILINFO 		finfo;
DIR 			dir;
WAVHeader 		header;
unsigned int	displayMode;
unsigned int	odispmode;
unsigned int    pdisp;

__attribute__((far))
unsigned char myBuffer[DAC_HALF_BUFFER_SIZE];
char fileName0[MAX_FILE_NAME+1];
char fileName1[MAX_FILE_NAME+1];
char fileName2[MAX_FILE_NAME+1];
char pathName[MAX_PATH_NAME];
unsigned int secondsElapsed;
unsigned int minutesElapsed;

void initFF(void)
{
	displayMode=0;
	f_mount(0, &fileSystem);
}

unsigned long getTotalKiloBytes(void)
{
	// returns total size of the disk in kilobytes...
	FATFS			*fs;
	unsigned long 	x;

	fs=&fileSystem;
	f_getfree("", &x, &fs);
	return (fileSystem.max_clust-2)*(fileSystem.csize/2);
}

unsigned long getFreeKiloBytes(void)
{
	// returns the number of kilobytes free...
	FATFS			*fs;
	unsigned long 	x;
	fs=&fileSystem;
	f_getfree("", &x, &fs);
	return (x*fileSystem.csize/2);
}

int  playCallBackId(int y)
{
	return 0;
}

int playHelperID(int y)
{
	return 0;
}

void displayDisplayModePlay(int dispmode)
{
	switch(dispmode)
	{
		case DISP_VOLUME:
#if (USE_LCD)
	if(dispmode!=odispmode)writeStringLCD(0x40, "Vol.: ", 16);
		writeLCD(0xC6, LCDCOMMAND);
		disdecfreeLCD(dacVolume>>7, 2);
#endif
#if (USE_OLED)
		setColourOLED(COLOUR3);
	if(dispmode!=odispmode)writeStringAtPaddedOLED(0, 7, "Vol.: ", 16);
		setCursorOLED(6, 7);
		disdecfreeOLED(dacVolume>>7, 2);
#endif
			break;

		case DISP_SAMPLERATE:
#if (USE_LCD)
	if(odispmode!=dispmode)writeStringLCD(0x40, "S/R.: ", 16);
	writeLCD(0xC6, LCDCOMMAND);
	disdecfreeLCD(header.sampleRate, 5);
	writeLCD(0xCC, LCDCOMMAND);
	if(header.numChannels==2)
	{
	writeLCD('S', LCDDATA);
	writeLCD('T', LCDDATA);
	writeLCD('E', LCDDATA);
	writeLCD('R', LCDDATA);
	} else
	{
	writeLCD('M', LCDDATA);
	writeLCD('O', LCDDATA);
	writeLCD('N', LCDDATA);
	writeLCD('O', LCDDATA);
	}
#endif

#if (USE_OLED)
		setColourOLED(COLOUR5);
	if(odispmode!=dispmode)writeStringAtPaddedOLED(0, 7, "S/R.: ", 16);
		setCursorOLED(6, 7);
		disdecfreeOLED(header.sampleRate, 5);
		if(header.numChannels==2)
		{
		setColourOLED(COLOUR4);
		writeStringAtOLED(12, 7, "STER");
		} else
		{
		setColourOLED(COLOUR4);
		writeStringAtOLED(12, 7, "MONO");
		}
#endif
			break;
	}
	odispmode=dispmode;
}

void displayDisplayModeRecord(int dispmode)
{
	switch(dispmode)
	{
		case DISP_VOLUME:
#if (USE_LCD)
		if(dispmode!=odispmode)writeStringLCD(0x40, "Ch.: ", 16);
		writeLCD(0xC5, LCDCOMMAND);
		if(adcCh==0)
		{
			writeLCD('M', LCDDATA); 
			writeLCD('i', LCDDATA); 
			writeLCD('c', LCDDATA); 
		}
		else 
		{
			writeLCD('L', LCDDATA);
			writeLCD('i', LCDDATA);
			writeLCD('n', LCDDATA);
			writeLCD('e', LCDDATA);
		}
#endif
#if (USE_OLED)
		setColourOLED(COLOUR3);
		if(dispmode!=odispmode)writeStringAtPaddedOLED(0, 7, "Ch.: ", 16);
		setCursorOLED(5, 7);
		if(adcCh==0)
		{
			writecOLED('M');
			writecOLED('i');	
			writecOLED('c');
		}
		else 
		{
			writecOLED('L');
			writecOLED('i');	
			writecOLED('n');
			writecOLED('e');	
		}
#endif
			break;

		case DISP_SAMPLERATE:
#if (USE_LCD)
	if(odispmode!=dispmode)writeStringLCD(0x40, "S/R.: ", 16);
	writeLCD(0xC6, LCDCOMMAND);
	disdecfreeLCD(header.sampleRate, 5);
	writeLCD(0xCC, LCDCOMMAND);
	if(header.numChannels==2)
	{
	writeLCD('S', LCDDATA);
	writeLCD('T', LCDDATA);
	writeLCD('E', LCDDATA);
	writeLCD('R', LCDDATA);
	} else
	{
	writeLCD('M', LCDDATA);
	writeLCD('O', LCDDATA);
	writeLCD('N', LCDDATA);
	writeLCD('O', LCDDATA);
	}
#endif

#if (USE_OLED)
		setColourOLED(COLOUR5);
	if(odispmode!=dispmode)writeStringAtPaddedOLED(0, 7, "S/R.: ", 16);
		setCursorOLED(6, 7);
		disdecfreeOLED(header.sampleRate, 5);
		if(header.numChannels==2)
		{
		setColourOLED(COLOUR4);
		writeStringAtOLED(12, 7, "STER");
		} else
		{
		setColourOLED(COLOUR4);
		writeStringAtOLED(12, 7, "MONO");
		}
#endif
			break;
	}
	odispmode=dispmode;
}

int playCallBack(int y)
{
	static unsigned char oldSeconds;
	static int key;
	static TIMET time;
	static int paused;
	static int k, ok;

	if(pdisp!=1)
	{
		LED2=0;
#if (USE_LCD)
		if(randomPlay)writeStringLCD(0,    "Play:        RND", 16); else writeStringLCD(0, "Play: ", 16);
#endif

#if (USE_OLED)
		setColourOLED(COLOUR3);
		writeStringAtPaddedOLED(0, 6, "Play: ", 16);
#endif
	pdisp=1;
	}

	time=getTime();
	if(oldSeconds!=time.seconds)
	{
		oldSeconds=time.seconds;
		//if(LED2==0)LED2=1; else LED2=0;
#if (USE_OLED)
		setColourOLED(COLOUR4);
		setCursorOLED(6, 6);
		disdecfreeOLED(minutesElapsed, 2);
		writecOLED(':');
		disdecfreeOLED(secondsElapsed, 2);
		writecOLED(' ');
#endif

		displayDisplayModePlay(displayMode);

		if(dacDataPlay)
		{
			if(secondsElapsed<59)secondsElapsed++; else { secondsElapsed=0; if(minutesElapsed<59)minutesElapsed++; else minutesElapsed=0; }
#if (USE_LCD)
		writeLCD(0x86, LCDCOMMAND);
		disdecfreeLCD(minutesElapsed, 2);
		writeLCD(':', LCDDATA);
		disdecfreeLCD(secondsElapsed, 2);
#endif
		} else
		{
			if(paused==0)paused=1; else paused=0;
			if(paused)
			{
#if (USE_LCD)
			writeLCD(0x86, LCDCOMMAND);
			disdecfreeLCD(minutesElapsed, 2);
			writeLCD(':', LCDDATA);
			disdecfreeLCD(secondsElapsed, 2);
#endif
			} else
			{
#if (USE_LCD)
			writeLCD(0x86, LCDCOMMAND);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
#endif
			}
		}
 	} else
	{
		key=getKey();
		if(k==0)ok++; else ok=0;
		k=checkButtons();
		if(((ok>10)&&(k==BUTTON8))||(key==KEYPAUSE))
		{
			if(dacDataPlay==1)endPlay(); else continuePlay();
		} else
		if(((ok>10)&&(k==BUTTON4))||(key==KEYSTOP))
		{
			randomPlay=0;
			return 1;
		} else
		if(((ok>10)&&(k==BUTTON1))||(key==KEYVOLUP))
		{
			dacVolumeLock=1;
			if(dacVolume<DAC_FULL_VOLUME)dacVolume+=128;
			dacVolumeLock=0;
		} else
		if(((ok>10)&&(k==BUTTON7))||(key==KEYVOLDOWN))
		{
			dacVolumeLock=1;
			if(dacVolume>=128)dacVolume-=128;
			dacVolumeLock=0;
		} else
		if(((ok>10)&&(k==BUTTON5))||(key==KEYMODEUP))
		{
			if(displayMode<DISP_MAX)displayMode++;

		} else
		if(((ok>10)&&(k==BUTTON3))||(key==KEYMODEDOWN))
		{
			if(displayMode>0)displayMode--;		
		}
	}
	return 0;
}

int playMinimalCallBack(int y)
{
	static unsigned char oldSeconds;
	static int key;
	static TIMET time;
	static int paused;
	static int k, ok;

	if(pdisp!=1)
	{
		LED2=0;
#if (USE_LCD)
		writeStringLCD(0,    "Play: ", 16);
#endif

#if (USE_OLED)
		setColourOLED(COLOUR3);
		writeStringAtPaddedOLED(0, 6, "Play: ", 16);
#endif
	pdisp=1;
	}

	time=getTime();
	if(oldSeconds!=time.seconds)
	{
		oldSeconds=time.seconds;
		//if(LED2==0)LED2=1; else LED2=0;
#if (USE_OLED)
		setColourOLED(COLOUR4);
		setCursorOLED(6, 6);
		disdecfreeOLED(minutesElapsed, 2);
		writecOLED(':');
		disdecfreeOLED(secondsElapsed, 2);
		writecOLED(' ');
#endif

		displayDisplayModePlay(0);

		if(dacDataPlay)
		{
			if(secondsElapsed<59)secondsElapsed++; else { secondsElapsed=0; if(minutesElapsed<59)minutesElapsed++; else minutesElapsed=0; }
#if (USE_LCD)
		writeLCD(0x86, LCDCOMMAND);
		disdecfreeLCD(minutesElapsed, 2);
		writeLCD(':', LCDDATA);
		disdecfreeLCD(secondsElapsed, 2);
#endif
		} else
		{
			if(paused==0)paused=1; else paused=0;
			if(paused)
			{
#if (USE_LCD)
			writeLCD(0x86, LCDCOMMAND);
			disdecfreeLCD(minutesElapsed, 2);
			writeLCD(':', LCDDATA);
			disdecfreeLCD(secondsElapsed, 2);
#endif
			} else
			{
#if (USE_LCD)
			writeLCD(0x86, LCDCOMMAND);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
#endif
			}
		}
 	} else
	{
		key=getKey();
		if(k==0)ok++; else ok=0;
		k=checkButtons();
		if(((ok>50)&&(k!=0))||(key==KEYSTOP))
		{
			return 1;
		}
	}
	return 0;
}

int recordCallBack(int y)
{
	static unsigned char oldSeconds;
	static int key;
	static TIMET time;
	static int paused;
	static int k, ok;

	if(pdisp!=1)
	{
		LED1=0;
#if (USE_LCD)
		writeStringLCD(0,    "Record: ", 16);
#endif

#if (USE_OLED)
		setColourOLED(COLOUR3);
		writeStringAtPaddedOLED(0, 6, "Record: ", 16);
#endif
	pdisp=1;
	}

	time=getTime();
	if(oldSeconds!=time.seconds)
	{
		//if(LED1==0)LED1=1; else LED1=0;
		oldSeconds=time.seconds;
#if (USE_OLED)
		setColourOLED(COLOUR4);
		setCursorOLED(8, 6);
		disdecfreeOLED(minutesElapsed, 2);
		writecOLED(':');
		disdecfreeOLED(secondsElapsed, 2);
		writecOLED(' ');
#endif

		displayDisplayModeRecord(displayMode);

		if(adcDataRecord)
		{
			if(secondsElapsed<59)secondsElapsed++; else { secondsElapsed=0; if(minutesElapsed<59)minutesElapsed++; else minutesElapsed=0; }
#if (USE_LCD)
		writeLCD(0x88, LCDCOMMAND);
		disdecfreeLCD(minutesElapsed, 2);
		writeLCD(':', LCDDATA);
		disdecfreeLCD(secondsElapsed, 2);
#endif
		} else
		{
			if(paused==0)paused=1; else paused=0;
			if(paused)
			{
#if (USE_LCD)
			writeLCD(0x88, LCDCOMMAND);
			disdecfreeLCD(minutesElapsed, 2);
			writeLCD(':', LCDDATA);
			disdecfreeLCD(secondsElapsed, 2);
#endif
			} else
			{
#if (USE_LCD)
			writeLCD(0x88, LCDCOMMAND);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
			writeLCD(' ', LCDDATA);
#endif
			}
		}
 	} else
	{
		key=getKey();
		if(k==0)ok++; else ok=0;
		k=checkButtons();
		if(((ok>10)&&(k==BUTTON8))||(key==KEYPAUSE))
		{
			if(adcDataRecord==1)endRecord(); else continueRecord();
		} else
		if(((ok>10)&&(k==BUTTON4))||(key==KEYSTOP))
		{
			return 1;
		} else
		if(((ok>10)&&(k==BUTTON5))||(key==KEYMODEUP))
		{
			if(displayMode<DISP_MAX)displayMode++;
		} else
		if(((ok>10)&&(k==BUTTON3))||(key==KEYMODEDOWN))
		{
			if(displayMode>0)displayMode--;		
		}
	}
	return 0;
}

int isWAVFile(char *path)
{
	FRESULT result;
	unsigned int u;

	result=f_open(&fsrc, path, FA_OPEN_EXISTING | FA_READ);
	if(result==0)
	{
	result=f_read(&fsrc, &dataBuffer[0], 44, &u);
	if(result==0)
	{
	readWAVHeader(&header, (BYTE*)&dataBuffer[0]);
	if(header.riff==0x46464952)
	{
	f_close(&fsrc);
	return 1;
	}
	}
	}
	f_close(&fsrc);
	return 0;
}

int playWAVFile(char *path, int (*callback)(int), unsigned long size)
{
	// play the WAV File
	FRESULT result;
	int 	callbackResult;
	unsigned int u;
	double speed;
	unsigned long bytesRead;
	double f;
	
	odispmode=-1;
	pdisp=-1;
	minutesElapsed=0;
	secondsElapsed=0;
	if(dacDataPlay)endPlay();
	result=f_open(&fsrc, path, FA_OPEN_EXISTING | FA_READ);
	if(result==0)
	{
	result=f_read(&fsrc, &dataBuffer[0], 44, &u);
	if(result==0)
	{
	bytesRead=44;
	readWAVHeader(&header, (BYTE*)&dataBuffer[0]);
	if(header.riff==0x46464952)
	{
	if(header.numChannels==1)f=64.0; else f=32.0;
	speed=0.5+(FOSC/(f*(double)header.byteRate));
	result=f_read(&fsrc, &dataBuffer[0], DAC_BUFFER_SIZE, &u);
	bytesRead+=u;
	if(result==0)
		{
			u=DAC_BUFFER_SIZE;
			callbackResult=0;
			result=0;
			startPlay((int)speed, header.numChannels);
			while((result==0)&&(callbackResult==0)&&(u==DAC_BUFFER_SIZE)&&((size==0)||(bytesRead<=size)))
			{
				if((dacDataPlay==1)&&(dacDataReady==0))
				{
					//result=f_read(&fsrc, (unsigned char*)&myBuffer[0], 2048, &u);
					//alaw_compress(2048, (short*)&dataBuffer[dacDataReadyPtr], (unsigned char*)&myBuffer[0]);
					//alaw_expand(2048, (unsigned char*)&myBuffer[0], (short*)&dataBuffer[dacDataReadyPtr]);
					result=f_read(&fsrc, (unsigned char*)&dataBuffer[dacDataReadyPtr], DAC_BUFFER_SIZE, &u);
					bytesRead+=u;
					dacDataReady=1;	
				}
				else
				{
					callbackResult=callback(0);
				}
			}
			endPlay();
			f_close(&fsrc);
			return 0;
		}
		return 1;
	}
	return 1;
	}
	return 1;
	}
	return 1;
}

int recordWAVFile(char *path, int (*callback)(int), unsigned long size)
{
	FRESULT	result;
	int 	callbackResult;
	unsigned int u;
	unsigned long bytesWritten;

	odispmode=-1;
	pdisp=-1;
	minutesElapsed=0;
	secondsElapsed=0;
	endRecord();

	result=f_open(&fsrc, path, FA_CREATE_ALWAYS | FA_WRITE);
	if(result==0)
	{
		bytesWritten=0;
		fillWAVHeader(&header);
		header.sampleRate=16000;
		header.audioFormat=1;
		header.numChannels=1;
		writeWAVHeader(&header, (BYTE*)&dataBuffer[0]);
		result=f_write(&fsrc, (unsigned char*)&dataBuffer[0], 44, &u);
		bytesWritten+=u;
		if(result==0)
		{

			adcLoopBack=0;
			u=DAC_BUFFER_SIZE;
			callbackResult=0;
			result=0;
			startRecord();
			while((result==0)&&(callbackResult==0)&&(u==DAC_BUFFER_SIZE)&&((size==0)||(bytesWritten<size)))
			{
				if(adcDataReady==0)
				{
					//alaw_compress(2048, (short*)&dataBuffer[dacDataReadyPtr], (unsigned char*)&myBuffer[0]);
					//result=f_write(&fsrc, (unsigned char*)&myBuffer[0], 2048, &u);
					result=f_write(&fsrc, (unsigned char*)&dataBuffer[adcDataReadyPtr], DAC_BUFFER_SIZE, &u);
					adcDataReady=1;	
					bytesWritten+=u;
				} else
				{
					callbackResult=callback(0);
				}
			}
			endRecord();
			header.subChunk2Size=bytesWritten-44;
			header.bitsPerSample=16;
			header.chunkSize=36+header.subChunk2Size;
			header.blockAlign=(header.numChannels*header.bitsPerSample/8);
			header.byteRate=(header.sampleRate*header.blockAlign);
			writeWAVHeader(&header, (BYTE*)&dataBuffer[0]);
			result=f_lseek(&fsrc, 0);
			if(result==0)
			{
				result=f_write(&fsrc, (unsigned char*)&dataBuffer[0], 44, &u);
				if(result==0)
				{
				f_close(&fsrc);
				return 0;
				}
			return 1;
			}
			return 1;
		}
		return 1;
	}
	return 1;
}

int getNextDirectoryEntry(char* path, char* outstrnext, int maxsize)
{
	FRESULT result;
	char* instr;
	int j;

	finfo.lfname=fileName0;
	finfo.lfsize=maxsize;
	result=f_readdir(&dir, &finfo);
	if(finfo.fname[0]==0)
	{
	*outstrnext='\0';
	return -1;
	}
	else
	{
	if(finfo.fattrib & AM_DIR){ j=1; *outstrnext++='['; } else j=0;
	if((*finfo.lfname)=='\0')instr=&finfo.fname[0]; else instr=&finfo.lfname[0];
	outstrnext=copyStringLimited(outstrnext, instr, maxsize);
	if(finfo.fattrib & AM_DIR)*outstrnext++=']';
	*outstrnext='\0';
	}
	return j;
}

int getDirectoryEntry(char* path, int index, char* outstr, int maxsize)
{
	// copies the index th directory index in path to outstr
	FRESULT result;
	int j;
	int i;

	result=f_opendir(&dir, path);
	result=f_readdir(&dir, 0);
	if(index==0)
	{
	*outstr++='[';
	*outstr++='.';
	*outstr++='.';
	*outstr++=']';
	*outstr='\0';
	} else
	{
	i=0;
	while((result==FR_OK)&&(i<index)&&(j>=0))
	{
	j=getNextDirectoryEntry(path, outstr, maxsize);
	i++;
	}
	}
	return j;
}

int enterDirectory(char* path, int* dirIndex, int modulo, void (*displayCallBack)(int, char*))
{
	// enter the directory at path and select a file or directory... Returns the index of the chosen file...
	int directoryIndex;
	int key;
	int subIndex;
	int j;
	int k;

	directoryIndex=*dirIndex;
	subIndex=0;
	while(1)
	{
		(void)getDirectoryEntry(path, directoryIndex, &fileName1[1], MAX_FILE_NAME);
		j=0;
		while(j<modulo)
		{
			if(j==subIndex)
			{
				fileName1[0]='>';
				copyString(fileName2, fileName1);
			} else fileName1[0]=' ';
			displayCallBack(j, &fileName1[0]);
			getNextDirectoryEntry(path, &fileName1[1], MAX_FILE_NAME); 
			j++;
		}
		if(checkButtons()!=0)delayMs(150);
		k=0;
		while((k==0)&&(keyFull==0))k=checkButtons();
		key=getKey();
		if((k==BUTTON6)||(key==KEYVOLDOWN))
		{
			if(subIndex<(modulo-1))subIndex++; else if((fileName1[1]=='\0')||((fileName1[1]=='[')&&(fileName1[2]==']')&&(fileName1[3]=='\0'))){ } else directoryIndex++;
		} else
		if((k==BUTTON2)||(key==KEYVOLUP))
		{
			if(subIndex>0)subIndex--; else if(directoryIndex>0)directoryIndex--;			
		} else
		if((k==BUTTON8)||(k==BUTTON4)||(k==BUTTON3)||(k==BUTTON5)||(key==KEYOK)||(key==KEYPLAY)||(key==KEYMENU)||(key==KEYRECORD)||(key==KEYLINE)||(key==KEYFF)||(k==BUTTON1))
		{
		if(k==BUTTON8)key=KEYPLAY; else if(k==BUTTON3)key=KEYRECORD; else if(k==BUTTON4)key=KEYMENU; else if(k==BUTTON5)key=KEYLINE; else if(k==BUTTON1)key=KEYFF;
		break;
		}
	}
	*dirIndex=(subIndex+directoryIndex);
	return key;
}

void displayCallBackLCD(int y, char* instr)
{
	if(y==0)writeStringLCD(0, instr, 16); else writeStringLCD(0x40, instr, 16);
}

#if (USE_OLED)
void displayCallBackOLED(int y, char* instr)
{
	setColourOLED(COLOUR3);
	writeStringAtPaddedOLED(0, y+2, instr, 16);
}
#endif

char* stripFileName(char* path)
{
	int i;
	i=0;
	while(path[i]!='\0')i++;
	while((path[i]!='/')&&(i>0))i--;
	path[i]='\0';
	return &path[i];
}

char* selectFile(char* path, int* key, int* startIndex, int modulus, void (*dispCallBack)(int, char*))
{
	char* outstr;
	int i, j, u;
	char* result;

	outstr=&pathName[0];
	i=copyStringLimited(outstr, path, MAX_PATH_NAME)-&pathName[0];
	while(1)
	{
		u=*startIndex;
		(*key)=enterDirectory(pathName, &u, modulus, dispCallBack);
		*startIndex=u;
		if((i==0)&&(u==0))
		{
		result=0;
		break;
		}
	
		if(u==0)
		{
				// here the previous directory has been chosen...
				while((pathName[i]!='/')&&(i>0))
				{
				i--;
				}
				pathName[i]='\0';
		}
		else
		{
			if(fileName2[1]=='[')
			{
				if((fileName2[2]==']')&&(fileName2[3]=='\0'))
				{
				  if(((*key)==KEYRECORD)||((*key)==KEYLINE)){ pathName[i++]='/'; pathName[i]='\0'; result=&pathName[0]; break; }
				} else
				{
				pathName[i++]='/';
				j=2;
				while((fileName2[j]!=']')&&(i<MAX_PATH_NAME))
				{
				pathName[i++]=fileName2[j++];
				}
				pathName[i]='\0';
				}
				*startIndex=0;
			} else
			if(fileName2[1]!='\0')
			{
			pathName[i++]='/';
			i=copyStringLimited(&pathName[i], &fileName2[1], MAX_PATH_NAME)-&pathName[0];
			result=&pathName[0];
			break;
			} else
			{
				if(((*key)==KEYRECORD)||((*key)==KEYLINE)){ pathName[i++]='/'; pathName[i]='\0'; result=&pathName[0]; break; }
			}
   		}
   }
   return result;
}

int countEntries(char* path)
{
	int i, j;
	char* outstr;

	j=0;
	outstr=&pathName[0];
	i=copyStringLimited(outstr, path, MAX_PATH_NAME)-&pathName[0];
	fileName1[1]=' ';
	while(fileName1[1]!='\0')
	{
	(void)getDirectoryEntry(path, j, &fileName1[1], MAX_FILE_NAME);
	j++;
	}
	return j;
}

char* getRandomTrack(char* path, int modulus)
{
		int random;
		char* outstr;
		int i;
		int j;	
		int l;
		
		outstr=&pathName[0];
		i=copyStringLimited(outstr, path, MAX_PATH_NAME)-&pathName[0];
		j=1;
		random=TMR3;
		l=0;
		while((j==1)&&(l<modulus))
		{
		j=getDirectoryEntry(path, ((random+l) % modulus), &fileName1[1], MAX_FILE_NAME);
		l++;
		}
		pathName[i++]='/';
		i=copyStringLimited(&pathName[i], &fileName1[1], MAX_PATH_NAME)-&pathName[0];		
		return &pathName[0];
}
