/**
 * Define a model object.
 * @function serverside.model._defineModel
 * @param {object} config - Model configuration
 * @param {boolean} config.insertable - Insert enabled or not.
 * @param {boolean} config.updatable - Insert enabled or not.
 * @param {boolean} config.removable - Insert enabled or not.
 * @param {boolean} config.singleton - Insert enabled or not.
 * @param {object} config.properties - Model properties.
 * @param {string[]} [config.indices] - Database index configuration.
 * @param {string[]} [config.indexedFields] - Field names to be indexed.
 * @returns {object} - Abstract model object.
 * @protected
 * @ignore
 * @author Taka Okunishi
 *
 */
var lib = require('../../lib'),
    object = lib.object,
    copy = object.copy;
exports = module.exports = function (config) {
    if (!config) config = {};

    var Model = require('../../lib/db/define_model')({
        properties: config.properties || {}
    });

    var insertable = config.insertable !== false,
        updatable = config.updatable !== false,
        destroyable = config.destroyable !== false;

    if (config.singleton) {
        Model.prototype.insertSingleton = Model.prototype.insert;
        copy(exports._singletonFunctions, Model);
        Model.prototype.insert = function (callback) {
            callback(new Error('You can not insert with singleton model.'));
        };
    }

    if (!insertable) Model.prototype.insert = null;
    if (!updatable) Model.prototype.update = null;
    if (!destroyable) Model.prototype.destroy = null;

    Model.indices = [].concat(config.indices || []);

    copy(exports._modelFunctions, Model);
    return Model;
};

exports._modelFunctions = {
    ensureIndices: function (callback) {
        var Model = this, result = [];
        require('async').series(
            Model.indices.map(function (data) {
                return function (callback) {
                    Model.ensureIndex.apply(Model, [].concat(data).concat(function (err, data) {
                        if (data) result.push(data);
                        callback(err);
                    }));
                };
            }),
            function (err) {
                callback(err, result);
            }
        )
    }
};


exports._singletonFunctions = {
    findSingleton: function (callback) {
        var Model = this;
        Model.findOne(function (err, model) {
            if (model) {
                callback(err, model);
            } else {
                model = new Model({});
                model.insertSingleton(function (err) {
                    callback(err, model);
                });
            }
        });
    }
};