/*****************************************************************************\

  File Name: mgr_filesystem.c

  Description: This module contains file manager specific functions.

  Copyright(c) 2007 Analog Devices Incorporated. All Rights Reserved.

  Revision History:


\*****************************************************************************/

/*****************************************************************************\

  Includes:

\*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <services/services.h>
#include <services/fss/adi_fss.h>
#include <SDK-ezkitutilities.h>
#include "mediaplayer.h"

/*****************************************************************************\

  Defines:

\*****************************************************************************/
#define SLEEP_PERIOD 40 /* ticks */
/*****************************************************************************\

  Declarations:

\*****************************************************************************/
section("sdram0_bank2_stack") static OS_STK stack[THRD_STACKSIZE * sizeof(OS_STK)];
section("sdram0_bank2_stack") static OS_STK stack1[THRD_STACKSIZE * sizeof(OS_STK)];


OS_EVENT *poll_Q;
void* poll_arr[SZ_MSGQ_APP_CMD];
OS_EVENT *pollEvent;
DRIVEENTRY diskList;

/*****************************************************************************\

  Externs:

\*****************************************************************************/
extern void* mgr_filesystem_arr[SZ_MSGQ_APP_CMD]; 
extern semaphore_t mpEvents[];
extern OS_EVENT *mgr_display_Q;
extern OS_EVENT *mgr_player_Q;	
extern OS_EVENT *mgr_filesystem_Q;	

/*****************************************************************************\

  Function Prototypes:

\*****************************************************************************/
void launch_mgr_filesystem(void) ;
void thread_mgr_filesystem(void *pEvent);
void thread_poll_media(void *pEvent);



u32 ListDirectory( char *dirname, int dirtype );
u32 ShowVolumes(bool update);

/*********************************************************************

	Function:	initialise mgr_filesystem																			
	
 	Parameters:	None 
																		
 	Return:		None														
																			
 	Description:	Initialises the file system manager
*********************************************************************/
void init_mgr_filesystem(void)
{
	int i;
	
	u32 Result= ADI_DEV_RESULT_SUCCESS;
	
	/* short delay is needed for 527 between init_fss and PollMedia */	
	for (i=0; i<0xfffff; i++);
	
	/* poll the fss for connected media */
	if (Result == ADI_DEV_RESULT_SUCCESS)
	    Result = adi_fss_PollMedia();
	

	/* Mount the drive volumes (HDD, or memory stick, or SD card) */
	if (Result == ADI_DEV_RESULT_SUCCESS)
		ShowVolumes(true);
	
    /* create a task to handle file select from keypad */	
    launch_mgr_filesystem();	
      	
	
}	

/*********************************************************************

	Function:	launch_mgr_filesystem																			
	
 	Parameters:	None 
																		
 	Return:		None														
																			
 	Description:	Launches a task thread which handles file selection
*********************************************************************/
section ("sdram0_bank2_thread")
void launch_mgr_filesystem(void) 
{
	/*OS_STK *stack, *stack1;*/
	int Result;
	INT32U i;

	/* Create app-fileMgr message Queue */
	mgr_filesystem_Q = OSQCreate(mgr_filesystem_arr, SZ_MSGQ_APP_CMD);
	mpEvents[2].sem = mgr_filesystem_Q;
	
/*------------ create a task to handle APP commands ---------------*/
	Result = OSTaskCreateExt(thread_mgr_filesystem, 
						(void *)&mpEvents[2], 
						&stack[THRD_STACKSIZE -1], 
						THRD_PRIORITY_MANAGER_FILESYSTEM, 
						MANAGER_FILESYSTEM_ID, 
						&stack[0], 
						THRD_STACKSIZE , 
						(void *)0, 
						OS_TASK_OPT_STK_CHK );
						
	if(Result && APP_TRACE_LEVEL)
	{
		APP_TRACE("OSTaskCreateExt thread_mgr_filesystem failed %d\n",Result);
		ezErrorCheck(1);/*wait for help*/

	}						
						
	/* Create command Queue */
	poll_Q = OSQCreate(poll_arr,SZ_MSGQ_APP_CMD );
	pollEvent = poll_Q;

	/*------------ create a task to handle poll devices ---------------*/
	Result = OSTaskCreateExt(thread_poll_media, 
						(void *)&pollEvent, 
						&stack1[THRD_STACKSIZE -1], 
						THRD_PRIORITY_POLL_MEDIA, 
						POLL_MEDIA_THREAD_ID, 
						&stack1[0], 
						THRD_STACKSIZE , 
						(void *)0, 
						OS_TASK_OPT_STK_CHK );
						
	if(Result && APP_TRACE_LEVEL)
	{
		APP_TRACE("OSTaskCreateExt thread_poll_media failed %d\n",Result);
		ezErrorCheck(1);/*wait for help*/

	}						
	
}// end of launch_threads

/*********************************************************************

	Function:	thread_mgr_filesystem																			
	
 	Parameters:	None 
																		
 	Return:		None														
																			
 	Description: handles all APP commands
 					
*********************************************************************/
section ("sdram0_bank2_thread")
void thread_mgr_filesystem(void *pEvent)
{
	INT8U err;
	int Result;
	MPPMESSAGE	*pMessage;
	INT8U diskIndex =0; 
	MPPMESSAGE	MessageToDisplay;
	MPPMESSAGE	MessageToPlayer;
	
	char current_path[MAX_PATH_NAME_LEN];	
	semaphore_t *p;
	p = (semaphore_t *)pEvent;
	
	OS_EVENT *queue = p->sem;
	
	
	/* post a message to mgr_display to reset lcd screen */
	MessageToDisplay.uMID = MSGID_LCD_REFRESH_RESET;
	MessageToDisplay.Param1 = diskIndex;
	MessageToDisplay.Param2 = &diskList;
	err = OSQPost(mgr_display_Q, &MessageToDisplay);
	
	if (err && APP_TRACE_LEVEL)
	{
    	APP_TRACE("thread_mgr_filesystem OSQPost failed %d\n",err);
		ezErrorCheck(1);/*wait for help*/
	}
	
    while(1)
	{
		
	    /* pend on message queue */
	    pMessage = (MPPMESSAGE *) OSQPend (queue, 0, &err);
		if (err && APP_TRACE_LEVEL) 
		{
			APP_TRACE("thread_mgr_filesystem OSQPend failed %d\n",err);
		}


		switch(pMessage->uMID)
		{
			case MSGID_NEXT_ENTRY:
				/*move the disk file pointer */
				if ((diskIndex + 1) > (diskList.indexnum) -1)				
				{
					diskIndex = 0;
				}
				else
				{
					diskIndex ++;
				}
				
				/* post a message to mgr_display to update lcd screen */
				MessageToDisplay.uMID = MSGID_NEXT_ENTRY;
				MessageToDisplay.Param1 = diskIndex;
				MessageToDisplay.Param2 = &diskList;
				err = OSQPost(mgr_display_Q, &MessageToDisplay);
				break;
				
			case MSGID_PREV_ENTRY:
				if (diskIndex == 0)
				{
					diskIndex = (diskList.indexnum) -1;
				}
				else
				{
					diskIndex --;	
				}
				
				/* post a message to mgr_display to update lcd screen */
				MessageToDisplay.uMID = MSGID_PREV_ENTRY;
				MessageToDisplay.Param1 = diskIndex;
				MessageToDisplay.Param2 = &diskList;
				err = OSQPost(mgr_display_Q, &MessageToDisplay);
				break;
				
			case MSGID_FILE_SELECT:
			
				/* If entry selection is a volume c:, d:, e: */
				if (diskList.flist[diskIndex].type == FILETYPE_DRIVE)
				{
					
					/* Check to see if file entry is a current directory */
					/* and do nothing 									 */
					if(!strncmp(".\0",diskList.flist[diskIndex].entryname,2))
					{
						break;
					}	
					/* Check to see if file entry is a .. do up a level  */
					/* relog drive volumes and update LCD				 */
					else if(!strncmp("..\0",diskList.flist[diskIndex].entryname,3))
					{
						/* Determine what drive volumes are attached */
						ShowVolumes(true);
						/* reset the file storage */
                		diskIndex = 0;

						/* inform mgr_display to update screen */
						MessageToDisplay.uMID = MSGID_LCD_REFRESH_RESET;
						MessageToDisplay.Param1 = 0;
						MessageToDisplay.Param2 = &diskList;
						err = OSQPost(mgr_display_Q, &MessageToDisplay);
						break;
					}
										
					/* get drive name and add / character to string */
					strcpy(current_path,diskList.flist[diskIndex].entryname);
				    strncat(current_path, "/", 1);

				    /* change to selected directory */
   					Result = chdir(current_path);
   					if (Result && APP_TRACE_LEVEL)
					{
						APP_TRACE("chdir(dir) failed %d\n",Result);
					}
					
 				    /* get the contents of the directory */
                	Result = ListDirectory(".",FILETYPE_DIRECTORY);
					if (Result && APP_TRACE_LEVEL)
					{
						APP_TRACE("ListDirectory(dir) failed %d\n",Result);
					}
		
							
					/* reset the file storage */
                	diskIndex = 0;      	
					/* inform mgr_display to update screen */
					MessageToDisplay.uMID = MSGID_LCD_REFRESH_RESET;
					MessageToDisplay.Param1 = diskIndex;
					MessageToDisplay.Param2 = &diskList;
					err = OSQPost(mgr_display_Q, &MessageToDisplay);
		
				}
				/* if user selected item is a directory */
				else if (diskList.flist[diskIndex].type == FILETYPE_DIRECTORY)
				{
					Result = chdir(diskList.flist[diskIndex].entryname);
					if (Result && APP_TRACE_LEVEL)
                	{
                		APP_TRACE("thread_mgr_filesystem:chdir failed %d\n",Result);
                	}
                		
                	/* get the contents of the sub-directory */
                	Result = ListDirectory(".",FILETYPE_DIRECTORY);
					if (Result && APP_TRACE_LEVEL)
					{
						APP_TRACE("ListDirectory(sub-dir) failed %d\n",Result);
					}
							
					/* reset the file index for new direstory listing */
                	diskIndex = 0;
      	
					/* inform mgr_display to update screen */
					MessageToDisplay.uMID = MSGID_LCD_REFRESH_RESET;
					MessageToDisplay.Param1 = diskIndex;
					MessageToDisplay.Param2 = &diskList;
					err = OSQPost(mgr_display_Q, &MessageToDisplay);
 						
				}
				else  /* if user selected item is a file */
				
				{
					/* update the current working directory*/				
                	getcwd(current_path,MAX_PATH_NAME_LEN);
                	/* include the song title in the current_path */
                	strcat(strcat(current_path, "/"),diskList.flist[diskIndex].entryname );
                	//strcat(strcat(current_path, "/"),diskList.flist[4].entryname );
					MessageToPlayer.uMID = MSGID_PLAYER_PLAY;
					MessageToPlayer.Param2 = current_path;
						
					/* post a message to Player manager */
					err = OSQPost(mgr_player_Q, &MessageToPlayer);

				}

				break;
			
			
			case MSGID_FSS_MEDIA_CHANGE:
				/* now we want to update diskList volumes */
				ShowVolumes(true);
				/* reset the file storage */
                diskIndex = 0;
				/* inform mgr_display to update screen */
				MessageToDisplay.uMID = MSGID_LCD_REFRESH_RESET;
				MessageToDisplay.Param1 = diskIndex;
				MessageToDisplay.Param2 = &diskList;
				err = OSQPost(mgr_display_Q, &MessageToDisplay);
		
				break;
			
						
		
			default:/* ignore all other commands */
				break;
			
		}/* end of switch */
		
		if (err && APP_TRACE_LEVEL)
		{
    		APP_TRACE("thread_mgr_filesystem OSQPost failed %d\n",err);
 			ezErrorCheck(1);/*wait for help*/
   		
		}
		

	}	
}

/*********************************************************************

	Function:	thread_poll_media																			
	
 	Parameters:	None 
																		
 	Return:		None														
																			
 	Description: periodically check for new media.
 					
*********************************************************************/
section ("sdram0_bank2_thread")
void thread_poll_media(void *pEvent)
{
	INT8U tmo,err;
	u32 Result= ADI_DEV_RESULT_SUCCESS;
	int i, num = 0 ;
	MPPMESSAGE	*pMessage;
	MPPMESSAGE	MessageToFileSys;

    while(1)
	{
		
	    // pend on message queue
	    pMessage = (MPPMESSAGE *) OSQPend (pollEvent, 300, &tmo);
	   	if (tmo)/*  10 secs timeout */
		{
			/* poll the fss for connected media */
			//if (Result == ADI_DEV_RESULT_SUCCESS)			
				Result = adi_fss_PollMedia();
			
			/* short delay is needed for 527 between init_fss and PollMedia */	
			for (i=0; i<0xfffff; i++);

			
			/* Create a list of the attached drive volumes */
			num = ShowVolumes(false);
			
			//if ( (num != diskList.numVol) && ( (num != 0) &&  (diskList.numVol !=0))  )
			if ( num != diskList.numVol)
			{

				MessageToFileSys.uMID = MSGID_FSS_MEDIA_CHANGE;
				err = OSQPost(mgr_filesystem_Q, &MessageToFileSys);

			}
			
		}
	}
   
}

/*****************************************************************************
 * ListDirectory
 *		Lists the contents of the named directory 
 *****************************************************************************/
//section ("sdram0_bank3_app")
u32 ListDirectory( char *dirname, int dirtype )
{
	u32 i, Result = ADI_FSS_RESULT_SUCCESS;
    struct dirent *pDirEntry;
    char str[80];

    	
	DIR *pDir = opendir(dirname);
	if (pDir) 
	{
		i = 0;
		
		/* If the directory listing selects a drive volume c:\, d:\, e:\	 */	
		/* insert entries '.' and '..' into the list so that we can navigate */
		/* back up the tree													 */
		if (dirtype == FILETYPE_DRIVE) /* list content of drive */
		{
			/* adding "." and ".." on the diskList */
			strncpy (diskList.flist[i].entryname,".\0",2);
		   	diskList.flist[i].type = FILETYPE_DRIVE;
		   	i++;
		   	strncpy (diskList.flist[i].entryname,"..\0",3);
		   	diskList.flist[i].type = FILETYPE_DRIVE;
		   	i++;	
	
		}		
				
		do 
		{
			pDirEntry = readdir(pDir);
			
			/* If the directory listing is a root directory					   */
			/* insert entries '.' & '..' into the list so that we can navigate */
			/* back up the tree												   */
														  
			if((i==0) && (strncmp(".\0",pDirEntry->d_name,2)))
		   	{
		   		strncpy (diskList.flist[i].entryname,".\0",2);
		   		diskList.flist[i].type = FILETYPE_DRIVE;
		   		i++;
		   		strncpy (diskList.flist[i].entryname,"..\0",3);
		   		diskList.flist[i].type = FILETYPE_DRIVE;
		   		i++;	
	
		   	}
			/* Generate directory lising including files and sub-directories */
		 	if (pDirEntry)
		    {
		    	if (pDirEntry->d_type == DT_DIR)
	    		diskList.flist[i].type = FILETYPE_DIRECTORY;
				else
	    		diskList.flist[i].type = FILETYPE_FILE;
	    		
				diskList.flist[i].size = pDirEntry->d_size;
	    
				strftime(str,80,"%b %d %Y %H:%M:%S",&pDirEntry->DateModified);
				strncpy (diskList.flist[i].date,str,80);
				strncpy (diskList.flist[i].entryname,pDirEntry->d_name,80);
				i++;
		    }
    
		} while (pDirEntry);
		
		diskList.indexnum = i;
	
		closedir(pDir);
	} 
	else 
	{
		Result = ADI_FSS_RESULT_FAILED;
	}
	
		return Result;
}


/*********************************************************************

    Function:       ShowVolumes

    Description:    Writes the definitions of a all mounted volume

*********************************************************************/
u32 ShowVolumes(bool update)
{
    ADI_FSS_VOLUME_INFO Volume;
    
    Volume.Index=0;
    while (adi_fss_Control(ADI_FSS_CMD_GET_VOLUME_INFO,(void*)&Volume)==ADI_FSS_RESULT_SUCCESS)
    {
        Volume.Index++;
        if(update)
        {
        	diskList.flist[Volume.Index-1].type = FILETYPE_DRIVE;
        	diskList.flist[Volume.Index-1].entryname[0] = Volume.Ident;
        	diskList.flist[Volume.Index-1].entryname[1] = ':';
        	diskList.flist[Volume.Index-1].entryname[2] = '\0';
    		diskList.indexnum = Volume.Index;
    		diskList.numVol = Volume.Index;
        }

    }

    if ( Volume.Index ==0 && update == TRUE)
    {   
    	diskList.indexnum = 0;
     	diskList.numVol = 0;
    }
    
	
    
    return Volume.Index;
}

