/**
{file:
    {name: LmiDirectory.h}
    {description: Objects to provide access to directories on disk or other persistent storage.}
    {copyright:
    	(c) 2018 Vidyo, Inc.,
    	433 Hackensack Avenue,
    	Hackensack, NJ 07601.

    	All rights reserved.

    	The information contained herein is proprietary to Vidyo, Inc.
    	and shall not be reproduced, copied (in whole or in part), adapted,
    	modified, disseminated, transmitted, transcribed, stored in a retrieval
    	system, or translated into any language in any form by any means
    	without the express written consent of Vidyo, Inc.
    	                  ***** CONFIDENTIAL *****
    }
}
*/
#ifndef LMI_DIRECTORY_H_
#define LMI_DIRECTORY_H_

#include <Lmi/Utils/LmiTypes.h>
#include <Lmi/Utils/LmiString.h>
#include <Lmi/Os/LmiPath.h>
#include <Lmi/Os/LmiDirectoryEntry.h>

#if (defined(LMI_HAVE_WINDOWS_H) || defined (LMI_HAVE_WINSOCK2_H)) && !defined(__CYGWIN__)
#if defined(LMI_HAVE_WINSOCK2_H)
#include <winsock2.h>
#else
#include <windows.h>
#endif
typedef HANDLE LmiDirectoryHandle;
#else
#include <dirent.h>
typedef DIR* LmiDirectoryHandle;
#endif

/**
{type:
	{name: LmiDirectoryOptions}
	{parent: LmiDirectory}
	{include: Lmi/Os/LmiDirectory.h}
	{description: A type that can hold a bit mask of directory related options.
 		types of directory entries.}
 		{value: {name: LMI_DIRECTORY_OPTIONS_None} {description: Indicates no options are demanded.}}
		{value: {name: LMI_DIRECTORY_OPTIONS_Recurse} {description: Indicates the operation should recurse into sub-directories.}}
 		{value: {name: LMI_DIRECTORY_OPTIONS_CreateIntermediateDirectories} {description: Indicates the operation should recurse into sub-directories.}}
 		{value: {name: LMI_DIRECTORY_OPTIONS_Directories} {description: Indicates the operation should apply to directories.}}
 		{value: {name: LMI_DIRECTORY_OPTIONS_Files} {description: Indicates the operation should apply to files.}}
}
*/
enum {
	LMI_DIRECTORY_OPTIONS_None = 0,
	LMI_DIRECTORY_OPTIONS_Recurse = 1 << 0,
	LMI_DIRECTORY_OPTIONS_CreateIntermediateDirectories = 1 << 2,
	/* Insert future enumeration options here */
	LMI_DIRECTORY_OPTIONS_Directories = LMI_DIRECTORYENTRY_TYPE_Directory,
	LMI_DIRECTORY_OPTIONS_Files = LMI_DIRECTORYENTRY_TYPE_File,
	LMI_DIRECTORY_OPTIONS_Others = LMI_DIRECTORYENTRY_TYPE_Other
	/* Insert future entry types here */
};
typedef int LmiDirectoryOptions;

/**
{type:
	{name: LmiDirectory}
	{parent: Os}
	{include: Lmi/Os/LmiDirectory.h}
	{description: A type representing a file system directory.}
}
*/
typedef struct {
	LmiDirectoryEntry base;
	LmiDirectoryHandle handle;
} LmiDirectory;

/**
{callback:
	{name: LmiDirectoryEnumerationCallback}
	{parent: LmiDirectory}
	{description: A callback used by LmiDirectoryEnumerate to notify the application of each directory entry matching the desired criteria.}
	{prototype: void LmiDirectoryEnumerationCallback(LmiDirectory* x, LmiDirectoryEntryType type, LmiDirectoryEntry* entry, LmiVoidPtr userData)}
	{parameter:
		{name: x}
		{description: The directory object from which the LmiDirectoryEnumerate was initiated.}}
	{parameter:
		{name: type}
		{description: The type of the directory entry.}}
 	{parameter:
		{name: entry}
 		{description: The directory entry.  Use the {code:type} argument to determine to what type (LmiDirectory*, LmiFile*) to cast this argument.}}
 	{parameter:
		{name: userData}
		{description: The user data passed to LmiDirectoryEnumerate.}}
}
*/
typedef void (*LmiDirectoryEnumerationCallback)(LmiDirectory* x, LmiDirectoryEntryType type, LmiDirectoryEntry* entry, LmiVoidPtr userData);

/**
{function:
	{name: LmiDirectoryConstruct}
	{parent: LmiDirectory}
	{description: Construct a directory object.}
	{prototype: LmiDirectory* LmiDirectoryConstruct(LmiDirectory* x, const LmiPath* path)}
	{parameter:
		{name: x}
		{description: The directory object.}}
	{parameter:
		{name: path}
		{description: The path on disk to the directory.  The syntax of this path is platform-dependent.}}
	{return: Returns a pointer to the directory object on success, or NULL otherwise.}
}
*/
LmiDirectory* LmiDirectoryConstruct(LmiDirectory* x, const LmiPath* path);

/**
{function:
	{name: LmiDirectoryConstructAndCreate}
	{parent: LmiDirectory}
	{description: Construct a directory object and create it on the file system.}
 	{prototype: LmiDirectory* LmiDirectoryConstructAndCreate(LmiDirectory* x, const LmiPath* path, LmiDirectoryOptions options)}
	{parameter:
		{name: x}
		{description: The directory object.}}
	{parameter:
		{name: path}
		{description: The path on disk to the directory.  The syntax of this path is platform-dependent.}}
  	{parameter:
		{name: options}
		{description: The options to apply.  See LMI_DIRECTORY_OPTIONS_CreateIntermediaDirectories.}}
	{return: Returns a pointer to the directory object on success, or NULL otherwise.}
}
*/
LmiDirectory* LmiDirectoryConstructAndCreate(LmiDirectory* x, const LmiPath* path, LmiDirectoryOptions options);

/**
{function:
	{name: LmiDirectoryConstructHome}
	{parent: LmiDirectory}
	{description: Construct a directory object to the user's home directory.}
	{prototype: LmiDirectory* LmiDirectoryConstructHome(LmiDirectory* x, LmiAllocator* alloc)}
	{parameter:
		{name: x}
		{description: The directory object.}}
	{parameter:
		{name: alloc}
		{description: An allocator.}}
	{return: Returns a pointer to the directory object on success, or NULL otherwise.}
}
*/
LmiDirectory* LmiDirectoryConstructHome(LmiDirectory* x, LmiAllocator* alloc);

/**
{function:
	{name: LmiDirectoryConstructWorking}
	{parent: LmiDirectory}
	{description: Construct a directory object to the user's working directory.}
	{prototype: LmiDirectory* LmiDirectoryConstructWorking(LmiDirectory* x, LmiAllocator* alloc)}
	{parameter:
		{name: x}
		{description: The directory object.}}
	{parameter:
		{name: alloc}
		{description: An allocator.}}
	{return: Returns a pointer to the directory object on success, or NULL otherwise.}
}
*/
LmiDirectory* LmiDirectoryConstructWorking(LmiDirectory* x, LmiAllocator* alloc);

/**
{function:
	{name: LmiDirectoryConstructDownloads}
	{parent: LmiDirectory}
	{description: Construct a directory object to the user's downloads directory.}
	{prototype: LmiDirectory* LmiDirectoryConstructDownloads(LmiDirectory* x, LmiAllocator* alloc)}
	{parameter:
		{name: x}
		{description: The directory object.}}
	{parameter:
		{name: alloc}
		{description: An allocator.}}
	{return: Returns a pointer to the directory object on success, or NULL otherwise.}
}
*/
LmiDirectory* LmiDirectoryConstructDownloads(LmiDirectory* x, LmiAllocator* alloc);

/**
{function:
	{name: LmiDirectoryConstructPictures}
	{parent: LmiDirectory}
	{description: Construct a directory object to the user's pictures directory.}
	{prototype: LmiDirectory* LmiDirectoryConstructPictures(LmiDirectory* x, LmiAllocator* alloc)}
	{parameter:
		{name: x}
		{description: The directory object.}}
	{parameter:
		{name: alloc}
		{description: An allocator.}}
	{return: Returns a pointer to the directory object on success, or NULL otherwise.}
}
*/
LmiDirectory* LmiDirectoryConstructPictures(LmiDirectory* x, LmiAllocator* alloc);

/**
{function:
	{name: LmiDirectoryConstructMovies}
	{parent: LmiDirectory}
	{description: Construct a directory object to the user's movies directory.}
	{prototype: LmiDirectory* LmiDirectoryConstructMovies(LmiDirectory* x, LmiAllocator* alloc)}
	{parameter:
		{name: x}
		{description: The directory object.}}
	{parameter:
		{name: alloc}
		{description: An allocator.}}
	{return: Returns a pointer to the directory object on success, or NULL otherwise.}
}
*/
LmiDirectory* LmiDirectoryConstructMovies(LmiDirectory* x, LmiAllocator* alloc);
/**
{function:
	{name: LmiDirectoryConstructMusic}
	{parent: LmiDirectory}
	{description: Construct a directory object to the user's music directory.}
	{prototype: LmiDirectory* LmiDirectoryConstructMusic(LmiDirectory* x, LmiAllocator* alloc)}
	{parameter:
		{name: x}
		{description: The directory object.}}
	{parameter:
		{name: alloc}
		{description: An allocator.}}
	{return: Returns a pointer to the directory object on success, or NULL otherwise.}
}
*/
LmiDirectory* LmiDirectoryConstructMusic(LmiDirectory* x, LmiAllocator* alloc);

/**
{function:
	{name: LmiDirectoryDestruct}
	{parent: LmiDirectory}
	{description: Destruct a directory object.}
	{prototype: void LmiDirectoryDestruct(LmiDirectory* x)}
	{parameter:
		{name: x}
		{description: The directory object.}}
}
*/
void LmiDirectoryDestruct(LmiDirectory* x);

/**
{function:
	{name: LmiDirectoryGetPath}
	{parent: LmiDirectory}
	{description: Get the path of the directory object.}
	{prototype: const LmiPath* LmiDirectoryGetPath(const LmiDirectory* x)}
	{parameter:
		{name: x}
		{description: The directory object.}}
	{return: Returns a pointer to the directory\'s path.}
}

*/
const LmiPath* LmiDirectoryGetPath(const LmiDirectory* x);

/**
{function:
	{name: LmiDirectoryExists}
	{parent: LmiDirectory}
	{description: Determines whether the directory exists on the file system.}
	{prototype: LmiBool LmiDirectoryExists(LmiDirectory* x)}
	{parameter:
		{name: x}
		{description: The directory object.}}
	{return: Returns LMI_TRUE if the directory exists or LMI_FALSE otherwise.}
}
*/
LmiBool LmiDirectoryExists(LmiDirectory* x);

/**
{function:
	{name: LmiDirectoryCreate}
	{parent: LmiDirectory}
	{description: Create the directory on the file system.}
	{prototype: LmiBool LmiDirectoryCreate(LmiDirectory* x, LmiDirectoryOptions options)}
	{parameter:
		{name: x}
		{description: The directory object.}}
 	{parameter:
		{name: options}
		{description: The options to apply.  See LMI_DIRECTORY_OPTIONS_CreateIntermediaDirectories.}}
	{return: Returns LMI_TRUE on success or LMI_FALSE otherwise.}
}
*/
LmiBool LmiDirectoryCreate(LmiDirectory* x, LmiDirectoryOptions options);

/**
{function:
	{name: LmiDirectoryEnumerate}
	{parent: LmiDirectory}
	{description: Enumerate directory entries (files, directories, etc).}
	{prototype: LmiBool LmiDirectoryEnumerate(LmiDirectory* x, LmiDirectoryOptions options, const LmiString* nameFilter, LmiDirectoryEnumerationCallback callback, LmiVoidPtr userData)}
	{parameter:
		{name: x}
		{description: The directory object.}}
 	{parameter:
		{name: options}
		{description: The options to apply.}}
  	{parameter:
		{name: nameFilter}
		{description: A wildcard expression limiting the directory entries enumerated to those whose names match the expression.}}
   	{parameter:
		{name: callback}
		{description: A function to call for each directory entry.}}
	{parameter:
		{name: userData}
 		{description: User data passed to the {code:callback}.}}
	{return: Returns LMI_TRUE on success or LMI_FALSE otherwise.}
}
*/
LmiBool LmiDirectoryEnumerate(LmiDirectory* x, LmiDirectoryOptions options, const LmiString* nameFilter, LmiDirectoryEnumerationCallback callback, LmiVoidPtr userData);

/**
{function:
	{name: LmiDirectoryRemove}
	{parent: LmiDirectory}
	{description: Remove directory entries (files, directories, etc).}
	{prototype: LmiBool LmiDirectoryRemove(LmiDirectory* x, LmiDirectoryOptions options)}
	{parameter:
		{name: x}
		{description: The directory object.}}
 	{parameter:
		{name: options}
		{description: The options to apply.}}
	{return: Returns LMI_TRUE on success or LMI_FALSE otherwise.}
}
*/
LmiBool LmiDirectoryRemove(LmiDirectory* x, LmiDirectoryOptions options);

//TODO: Implement Move
LmiBool LmiDirectoryMove(LmiDirectory* x, const LmiPath* newPath);


#endif /* LMI_DIRECTORY_H_ */
