+#include <msp/time/utils.h>
+#include "resourcemanager.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+ResourceManager::ResourceManager():
+ policy(LOAD_ON_DEMAND),
+ async_loads(true),
+ thread(*this)
+{ }
+
+ResourceManager::~ResourceManager()
+{
+ thread.terminate();
+}
+
+void ResourceManager::add_resource(Resource &r)
+{
+ insert_unique(resources, &r, ManagedResource(r));
+}
+
+void ResourceManager::set_resource_location(Resource &r, DataFile::Collection &c, const string &n)
+{
+ ManagedResource &managed = get_item(resources, &r);
+ managed.collection = &c;
+ managed.name = n;
+
+ if(policy==LOAD_IMMEDIATELY)
+ load_resource(r);
+}
+
+void ResourceManager::load_resource(const Resource &r)
+{
+ ManagedResource &managed = get_item(resources, &r);
+ if(!managed.collection)
+ throw runtime_error("no location");
+
+ if(managed.loader)
+ return;
+
+ managed.io = managed.collection->open_raw(managed.name);
+ managed.loader = managed.resource->load(*managed.io);
+
+ queue.push_back(&managed);
+}
+
+void ResourceManager::remove_resource(Resource &r)
+{
+ ManagedResource *loading = thread.get_resource();
+ if(loading && loading->resource==&r)
+ thread.set_resource(0);
+
+ remove_existing(resources, &r);
+}
+
+void ResourceManager::tick()
+{
+ LoadingThread::State thread_state = thread.get_state();
+ if(thread_state==LoadingThread::SYNC_PENDING)
+ thread.sync();
+ else if(thread_state==LoadingThread::IDLE && !queue.empty())
+ {
+ ManagedResource *managed = queue.front();
+ queue.pop_front();
+ thread.set_resource(managed);
+ }
+}
+
+
+ResourceManager::ManagedResource::ManagedResource(Resource &r):
+ resource(&r),
+ collection(0),
+ io(0),
+ loader(0)
+{ }
+
+
+ResourceManager::LoadingThread::LoadingThread(ResourceManager &m):
+ manager(m),
+ sem(1),
+ resource(0),
+ state(IDLE)
+{
+ launch();
+}
+
+void ResourceManager::LoadingThread::main()
+{
+ while(state!=TERMINATING)
+ {
+ sem.wait();
+
+ if(state==BUSY)
+ {
+ Resource::AsyncLoader *ldr = resource->loader;
+ bool finished = false;
+ while(!finished && !ldr->needs_sync())
+ finished = ldr->process();
+
+ if(finished)
+ state = LOAD_FINISHED;
+ else
+ state = SYNC_PENDING;
+ }
+ }
+}
+
+void ResourceManager::LoadingThread::set_resource(ManagedResource *r)
+{
+ if(state!=IDLE)
+ {
+ while(state==BUSY) ;
+ // Force finish to clean up the loader
+ state = LOAD_FINISHED;
+ sync();
+ }
+
+ resource = r;
+ state = BUSY;
+ sem.signal();
+}
+
+void ResourceManager::LoadingThread::sync()
+{
+ State s = state;
+ bool finished = (s==LOAD_FINISHED);
+ if(s==SYNC_PENDING)
+ {
+ Resource::AsyncLoader *ldr = resource->loader;
+ while(!finished && ldr->needs_sync())
+ finished = ldr->process();
+
+ if(!finished)
+ {
+ state = BUSY;
+ sem.signal();
+ return;
+ }
+ }
+
+ if(finished)
+ {
+ delete resource->loader;
+ resource->loader = 0;
+ delete resource->io;
+ resource->io = 0;
+ resource = 0;
+ state = IDLE;
+ }
+}
+
+void ResourceManager::LoadingThread::terminate()
+{
+ while(state==BUSY) ;
+ state = TERMINATING;
+ sem.signal();
+ join();
+}
+
+} // namespace GL
+} // namespace Msp