#ifndef ANDROID_RESOURCE_LOADER_H
#define ANDROID_RESOURCE_LOADER_H

#include <sys/types.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <algorithm>
#include "Atmosphere.h"
#include "ResourceLoader.h"

class AndroidResourceLoader : public SilverLining::ResourceLoader
{
public:
    AndroidResourceLoader(AAssetManager *assetManager) : SilverLining::ResourceLoader(), mgr(assetManager) {}

    virtual ~AndroidResourceLoader() {
    }

    static SL_STRING ScrubPath(SL_STRING& path)
    {
        SL_STRING newPath;

        bool prevCharWasSlash = false;

        for (unsigned int i = 0; i < path.length(); i++)
        {
            if (path[i] == '\\')
            {
                if (!prevCharWasSlash)
                {
                    newPath += '/';
                }
            }
            else
            {
                if (path[i] == '/' || path[i] == '\\')
                {
                    if (!prevCharWasSlash)
                    {
                        newPath += path[i];
                    }
                }
                else
                {
                    newPath += path[i];
                }
            }

            prevCharWasSlash = (path[i] == '/' || path[i] == '\\');
        }

        return newPath;
    }

    virtual bool SILVERLINING_API LoadResource(const char *pathName, char*& data, unsigned int& dataLen, bool text)
    {
        SL_STRING filePath(resourcePath);
        filePath += "/";
        filePath += pathName;
        SL_STRING scrubbedPath = ScrubPath(filePath);

        AAsset *asset = 0;
        if (mgr) {
            asset = AAssetManager_open(mgr, scrubbedPath.c_str(), AASSET_MODE_UNKNOWN);
            if (asset) {
                const void *buffer = AAsset_getBuffer(asset);
                if (buffer) {
                    off_t assetSize = AAsset_getLength(asset);
                    off_t buffLen = text ? assetSize + 1 : assetSize;
                    data = SL_NEW char[buffLen];
                    memcpy(data, buffer, assetSize);
                    if (text) {
                        data[assetSize] = '\0';
                    }
                    dataLen = (int)buffLen;
                    AAsset_close(asset);
                    asset = 0;
                    return true;
                }
            }
        }
        if (asset) AAsset_close(asset);
        return false;
    }

    virtual void SILVERLINING_API FreeResource(char *data)
    {
        SL_DELETE[] data;
    }

    virtual bool SILVERLINING_API GetFilesInDirectory(const char *pathName, SL_VECTOR(SL_STRING)& dirContents)
    {
        SL_STRING dirPath(resourcePath);
        dirPath += "/";
        dirPath += pathName;
        dirPath += "/";

        dirContents.clear();

        SL_STRING scrubbedDir = ScrubPath(dirPath);

        AAssetDir *dir = AAssetManager_openDir(mgr, scrubbedDir.c_str());
        if (dir)
        {
            const char* fname;
            
            do {
                fname = AAssetDir_getNextFileName(dir);
                if (fname)
                {
                    dirContents.push_back(SL_STRING(fname));
                }
            } while (fname);

            AAssetDir_close(dir);

            std::sort(dirContents.begin(), dirContents.end());

            return true;
        }
        else
        {
            return false;
        }
    }

protected:
    AAssetManager *mgr;
};

#endif
