/* jslint node:true */

'use strict';

exports = module.exports = {
    getAllActiveUserIds: getAllActiveUserIds,

    getAll: getAll,
    getAllLean: getAllLean,
    get: get,
    add: add,
    addFull: addFull,
    put: put,
    del: del,
    setPublic: setPublic
};

var assert = require('assert'),
    ObjectId = require('mongodb').ObjectID,
    config = require('../config.js');

var g_collections = {};

function getAllActiveUserIds() {
    return Object.keys(g_collections);
}

function postProcess(userId, thing) {
    thing._id = String(thing._id);
    thing.public = !!thing.public;
}

function getCollection(userId) {
    assert.strictEqual(typeof userId, 'string');

    if (!g_collections[userId]) {
        console.log('Opening collection for', userId);

        config.db.createCollection(userId + '_things');
        g_collections[userId] = config.db.collection(userId + '_things');
        g_collections[userId].createIndex({ content: 'text' }, { default_language: 'none' });
    }

    return g_collections[userId];
}

function getAll(userId, query, skip, limit, callback) {
    assert.strictEqual(typeof userId, 'string');
    assert.strictEqual(typeof query, 'object');
    assert.strictEqual(typeof skip, 'number');
    assert.strictEqual(typeof limit, 'number');
    assert.strictEqual(typeof callback, 'function');

    getCollection(userId).find(query).skip(skip).limit(limit).sort({ modifiedAt: -1 }).toArray(function (error, result) {
        if (error) return callback(error);
        if (!result) return callback(null, []);

        result.forEach(postProcess.bind(null, userId));

        callback(null, result);
    });
}

function getAllLean(userId, callback) {
    assert.strictEqual(typeof userId, 'string');
    assert.strictEqual(typeof callback, 'function');

    getCollection(userId).find({}).toArray(function (error, result) {
        if (error) return callback(error);
        if (!result) return callback(null, []);

        result.forEach(postProcess.bind(null, userId));

        callback(null, result);
    });
}

function get(userId, thingId, callback) {
    assert.strictEqual(typeof userId, 'string');
    assert.strictEqual(typeof thingId, 'string');
    assert.strictEqual(typeof callback, 'function');

    getCollection(userId).find({ _id: new ObjectId(thingId) }).toArray(function (error, result) {
        if (error) return callback(error);
        if (result.length === 0) return callback(new Error('not found'));

        postProcess(userId, result[0]);

        callback(null, result[0]);
    });
}

function add(userId, content, tags, attachments, externalContent, callback) {
    addFull(userId, content, tags, attachments, externalContent, Date.now(), Date.now(), callback);
}

function addFull(userId, content, tags, attachments, externalContent, createdAt, modifiedAt, callback) {
    assert.strictEqual(typeof userId, 'string');
    assert.strictEqual(typeof content, 'string');
    assert(Array.isArray(tags));
    assert(Array.isArray(attachments));
    assert(Array.isArray(externalContent));
    assert.strictEqual(typeof createdAt, 'number');
    assert.strictEqual(typeof modifiedAt, 'number');
    assert.strictEqual(typeof callback, 'function');

    var doc = {
        content: content,
        createdAt: createdAt,
        modifiedAt: modifiedAt,
        tags: tags,
        externalContent: externalContent,
        attachments: attachments,
        public: false
    };

    getCollection(userId).insert(doc, function (error, result) {
        if (error) return callback(error);
        if (!result) return callback(new Error('no result returned'));

        get(userId, String(result.ops[0]._id), callback);
    });
}

function put(userId, thingId, content, tags, attachments, externalContent, isPublic, callback) {
    assert.strictEqual(typeof userId, 'string');
    assert.strictEqual(typeof thingId, 'string');
    assert.strictEqual(typeof content, 'string');
    assert(Array.isArray(tags));
    assert(Array.isArray(attachments));
    assert(Array.isArray(externalContent));
    assert.strictEqual(typeof isPublic, 'boolean');
    assert.strictEqual(typeof callback, 'function');

    var data = {
        content: content,
        tags: tags,
        modifiedAt: Date.now(),
        externalContent: externalContent,
        attachments: attachments,
        public: isPublic
    };

    getCollection(userId).update({_id: new ObjectId(thingId) }, { $set: data }, function (error) {
        if (error) return callback(error);

        get(userId, thingId, callback);
    });
}

function setPublic(userId, thingId, isPublic, callback) {
    assert.strictEqual(typeof userId, 'string');
    assert.strictEqual(typeof thingId, 'string');
    assert.strictEqual(typeof isPublic, 'boolean');
    assert.strictEqual(typeof callback, 'function');

    var data = {
        public: isPublic
    };

    getCollection(userId).update({_id: new ObjectId(thingId) }, { $set: data }, function (error) {
        if (error) return callback(error);

        get(userId, thingId, callback);
    });
}

function del(userId, thingId, callback) {
    assert.strictEqual(typeof userId, 'string');
    assert.strictEqual(typeof thingId, 'string');
    assert.strictEqual(typeof callback, 'function');

    getCollection(userId).deleteOne({ _id: new ObjectId(thingId) }, function (error) {
        if (error) return callback(error);
        callback(null);
    });
}

@@ -236,34 +236,8 @@
  del
-,%0A    setPublic: setPublic
 %0A%7D;%0A
@@ -4534,515 +4534,8 @@
 %0A%7D%0A%0A
-function setPublic(userId, thingId, isPublic, callback) %7B%0A    assert.strictEqual(typeof userId, 'string');%0A    assert.strictEqual(typeof thingId, 'string');%0A    assert.strictEqual(typeof isPublic, 'boolean');%0A    assert.strictEqual(typeof callback, 'function');%0A%0A    var data = %7B%0A        public: isPublic%0A    %7D;%0A%0A    getCollection(userId).update(%7B_id: new ObjectId(thingId) %7D, %7B $set: data %7D, function (error) %7B%0A        if (error) return callback(error);%0A%0A        get(userId, thingId, callback);%0A    %7D);%0A%7D%0A%0A
 func

Remove unused setPublic()