var M = process.mono;
var fs = require('fs');
var modelCollection = 'm_models';

// read available store adapters to adapter cache
var adapatersPath = __dirname + '/adapters/';
var adapters = fs.readdirSync(adapatersPath);

// save adapter paths in adapter cache
for (var i = 0; i < adapters.length; ++i) {
    adapters[adapters[i]] = adapatersPath + adapters[i] + '/' + adapters[i] + '.js';
}

module.exports = setup;

function setup (instance) {
    
    // listen for message events
    instance.on('model_req>', messageHandler);
    instance.on('model>', factoryService);
    
    // return model factory
    return factory;
}

function factory (config, callback) {
    
    // create cache key
    var cacheKey = (config.project || '') + config.name;
    
    // check cache
    var model = M.cache.models.get(cacheKey);
    if (model) {
        return callback(null, model);
    }
    
    // get system store to fetch models
    M.store(M.config.store.systemStoreName, config.project, function (err, systemStore) {
        
        if (err) {
            return callback(err);
        }
        
        // get module entity
        // TODO check access self.link.session.role
        systemStore.collection(modelCollection).findOne({name: config.name}, {fields: {_id: 0}}, function (err, dbModel) {
            
            if (err || !dbModel) {
                return callback(err || 'Model not found');
            }
            
            M.store(dbModel.store, config.project, function (err, store) {
                
                if (err) {
                    return callback(err);
                }
                
                if (err || !adapters[dbModel.adapter]) {
                    return callback(err || 'Model adapter "' + dbModel.adapter + '" not available.');
                }
                
                // require adapter
                if (typeof adapters[dbModel.adapter] === 'string') {
                    adapters[dbModel.adapter] = require(adapters[dbModel.adapter]);
                }
                
                // save model in cache
                model = adapters[dbModel.adapter].model(store, dbModel);
                M.cache.models.save(cacheKey, model);
                
                callback(null, model);
            });
        });
    });
}

function factoryService (err, message) {
    var self = this;
    
    // check message
    if (!message) {
        return self.emit('<model', 'Bad message'); 
    }
    
    // create factory config
    if (typeof message === 'string') {
        message = {name: message};
    } else {
        message = {
            name: message[0],
            project: message[1]
        };
    }
    
    // create model
    factory(message, function (err, model) {
        
        if (err) {
            return self.emit('<model', err);
        }
        
        var clientModel = {
            name: model.name,
            schema: model.schema
        };
        
        self.emit('<model', null, clientModel);
    });
}

// TODO check access here
function messageHandler (err, message) {
    var self = this;
    
    // check message
    if (!message || !message.m || !message.d) {
        return self.emit('<model_res', 'Bad message');
    }

    // get model from cache
    var model = M.cache.models.get(message.m);
    if (!model) {
        return self.emit('<model_res', 'Model not found.');
    }
    
    // do model request
    model.request(message.d, function (err, data) {
        self.emit('<model_res', err, data);
    });
}

@@ -2710,20 +2710,43 @@
  // 
-create model
+send the model schema to the client
 %0A   
@@ -2799,248 +2799,45 @@
     
-%0A        if (err) %7B%0A            return self.emit('%3Cmodel', err);%0A        %7D%0A        %0A        var clientModel = %7B%0A            name: model.name,%0A            schema: model.schema%0A        %7D;%0A        %0A        self.emit('%3Cmodel', null, clientModel
+self.emit('%3Cmodel', err, model.schema
 );%0A 

return only schema to the client