/*!
    \file  Fat12FileSystem.h
    \brief Fat12FileSystem

    Copyright (c) 2005 HigePon
    WITHOUT ANY WARRANTY

    \author  HigePon
    \version $Revision$
    \date   create:2005/03/26 update:$Date$
*/

#ifndef _FAT12_FILE_SYSTEM_
#define _FAT12_FILE_SYSTEM_

#include "FileSystem.h"
#include "IStorageDevice.h"
#include "FileSystemEntry.h"
#include "Fat12File.h"
#include "Fat12Directory.h"
#include "Fat12.h"

namespace FatFS
{

class Fat12File;

/*----------------------------------------------------------------------
    Fat12FileSystem
----------------------------------------------------------------------*/
class Fat12FileSystem : public FileSystem
{
public:
    Fat12FileSystem(IStorageDevice* cd);
    virtual ~Fat12FileSystem();

public:
    enum
    {
        SECTOR_SIZE = 512,
        NO_ERROR = 0,
        READ_ERROR,
        WRITE_ERROR,
        MEMORY_ALLOCATE_ERROR,
    };

    enum
    {
        ATTR_ARCHIVE   = 0x20,
        ATTR_DIRECTORY = 0x10,
        ATTR_VOLUME    = 0x08,
        ATTR_SYSTEM    = 0x04,
        ATTR_HIDDEN    = 0x02,
        ATTR_READONLY  = 0x01,
        ATTR_VFAT      = 0x0f
    };

public:
    virtual bool Initialize();
    virtual bool Read(dword lba, byte* buffer, dword size);
    bool ReadClusterChain(dword startCluster, dword postion, void* buffer, dword size);

public:
    virtual File* Open(const MonAPI::CString& path, int mode);
    virtual bool Close(File* file);
    virtual bool CreateFile(const MonAPI::CString& path);
    virtual bool RemoveFile(const MonAPI::CString& path);
    virtual bool CreateDirectory(const MonAPI::CString& path);
    virtual bool RemoveDirectory(const MonAPI::CString& path);
    virtual _A<FileSystemEntry*> GetFileSystemEntries(const MonAPI::CString& path);
    virtual int GetLastError() {return this->lastError;}

private:
    bool RemoveFileFromRootDirectory(Fat12File* file);
    bool RemoveFileFromDirectory(Fat12Directory* directory, Fat12File* file);


    Fat12Directory* FindDirectoryEntry(Fat12Directory* root, const MonAPI::CString& path);
    Fat12File* Fat12FileSystem::FindFileEntry(Fat12Directory* directory, const MonAPI::CString& fileName);
    int ReadAtOnce(dword lba, void* buffer, dword size);
    bool ReadRootDirectory();
    void SetupDate(FileDate* date, DirectoryEntry* entry);
    FileSystemEntry* SetupFileSystemEntryInformation(Fat12Directory* parent, DirectoryEntry* entry, dword cluster);
    MonAPI::CString Trim(const char* str, int maxLength);
    MonAPI::CString GetProperName(const char* filename, const char* extension);
    bool CreateDirectoryCache(Fat12Directory* startDirectory, dword cluster);
    bool CreateDirectoryCache();
    void DeleteEntry(FileSystemEntry* entry);
    dword GetDirectoryBufferSize(Fat12Directory* directory);
    bool ReadDirectoryAtOnce(Fat12Directory* directory, void* buffer);
    byte* ReadRootDirectoryIntoBuffer();

private:

    enum
    {
        CHAIN_MAX = 1000,
    };

private:
    int lastError;
    Fat12* fat;
    IStorageDevice* fd;
    Fat12Directory* rootDirectory;
    byte* sectorBuffer;
    byte* rootEntryBuffer;
    dword rootEntryStart;


};

}

#endif
