#ifndef __ResourceManager__
#define __ResourceManager__

#ifndef CORE_DLL 
    #ifdef CORE_BUILD
	    #define CORE_DLL __declspec(dllexport)
    #else
	    #define CORE_DLL __declspec(dllimport)
        #pragma comment(lib, "Core.lib")
    #endif
#endif

#include "types.h"
#include "Thread.h"
#include "SharedResource.h"
#include "RenderDevice.h"
#include "SceneGraph/Texture.h"
#include "SceneGraph/Geode.h"
#include "SceneGraph/Shader.h"
#include <list>
#include <hash_map>

#include <assimp.hpp>
#include <aiMesh.h>
#include <aiMaterial.h>
#include <aiAnim.h>
#include <aiScene.h>
#include <aiPostProcess.h>


#pragma warning(push)
#pragma warning(disable:4251)

class CORE_DLL ResourceManager {
    friend class LoaderThread;
public:
    static int MAX_THREAD_NUM;

    ~ResourceManager();

    static ResourceManager& instance();

    void setRenderDevice(RenderDevice* renderDevice);

    Texture* loadTexture(uint32 width, uint32 height, float* data);

    Texture* loadTexture(const wchar_t* fileName);
    Node*    loadNode(const wchar_t* fileName);

    void loadTextureNonBlocking(const wchar_t* fileName, Texture** texture);
    void loadNodeNonBlocking(const wchar_t* fileName, Node** node);

    Shader* createShader(const wchar_t* fileName);

    RenderTarget* createRenderTarget(uint32 width, uint32 height, uint32 sampleCount);
    DepthStencilBuffer* createDepthStencilBuffer(uint32 width, uint32 height, uint32 sampleCount);

    // this is just for debugging, shouldnt really expose such details...
    bool* getActivityMask() {
        return _activityMask;
    }

protected:
    ResourceManager();

    void addToTextureLoadQueue(const wchar_t* fileName, Texture** texture);
    void addToNodeLoadQueue(const wchar_t* fileName, Node** node);


    RenderDevice* _renderDevice;

    class LoaderThread;
    LoaderThread** _loaderThread;

    bool* _activityMask;

   
    struct TextureLoadTask {
        std::wstring fileName; 
        Texture** texture; 
    };

    struct NodeLoadTask {
        std::wstring fileName;
        Node** node;
    };

    class TextureLoadQueue : public std::list<TextureLoadTask>, public SharedResource { public: TextureLoadQueue() : SharedResource() {} };
    TextureLoadQueue _textureLoadQueue;
    
    class NodeLoadQueue : public std::list<NodeLoadTask>, public SharedResource { public: NodeLoadQueue() : SharedResource() {} };
    NodeLoadQueue _nodeLoadQueue;


    class TextureHashMap : public stdext::hash_map<std::wstring, Texture*>, public SharedResource { public: TextureHashMap() : SharedResource() {} };
    TextureHashMap _textures;

    class NodeHashMap : public stdext::hash_map<std::wstring, Node*>, public SharedResource { public: NodeHashMap() : SharedResource() {} };
    NodeHashMap _nodes;
};

#pragma warning(pop)

#endif