var util = require('util');
var assert = require('assert');
var EventEmitter = require('events').EventEmitter;
var mongodb = require('mongodb');

function SingletonProcess(name, mongoUri) {
    var self = this;

    assert(mongoUri, "Missing required parameter 'mongoUri'.");

    self._name = name;
    self._isSigterm = false;

    self.getCollection = function (callback) {
        mongodb.MongoClient.connect(mongoUri, function (err, db) {
            if (err) { return callback(err); }

            db.on('error', function (err) {
                self.emit('error', err);
            });

            var collection = db.collection('singletons');

            collection.ensureIndex('name', { unique: true }, function (err) {
                if (err) { return callback(err); }

                return callback(null, collection);
            });
        });
    }
}
util.inherits(SingletonProcess, EventEmitter);

module.exports = SingletonProcess;

function closeConnection(collection, callback) {
    collection.db.on('close', function() {
        return callback();
    });

    collection.db.close();
}

SingletonProcess.prototype.lock = function () {
    var self = this;

    self.emit('locking', "Attempting lock for singleton '" + self._name + "'.");

    self.getCollection(function (err, collection) {
        if (err) { return self.emit('error', err); }

        var doc = { 
            name: self._name, 
            created: new Date(),
        };
        collection.insert(doc, function (err, docs) {
            if (err) {
                if (err.name == 'MongoError' && err.code == 11000) {
                    collection.findOne({ name: self._name }, function (err, existing) {
                        if (err) { return self.emit('error', err); }

                        closeConnection(collection, function() {
                            var message = existing
                                          ? "A singleton already exists and was created on " + existing.created
                                          : "A singleton existed at the moment this one was being locked but is no longer there.";
                            return self.emit('conflict', message);
                        });
                    });
                } else {
                    return self.emit('error', err);
                }
            } else {
                closeConnection(collection, function() {
                    self.emit('locked', "Lock successfully obtained for singleton '" + self._name + "'.");

                    // automatically release lock if process is signaled to be shut down
                    process.on('SIGTERM', function() {
                        self._isSigterm = true;
                        self.release();
                    });
                });
            }
        });
    });
};

SingletonProcess.prototype.release = function () {
    var self = this;

    var message = self._isSigterm
                  ? "Attempting automatic lock release of singleton  '" + self._name + "' since the process received a SIGTERM event."
                  : "Attempting lock release of singleton '" + self._name + "'.";
    self.emit('releasing', message);

    self.getCollection(function (err, collection) {
        if (err) { return self.emit('error', err); }

        collection.remove({ name: self._name }, function (err) {
            if (err) { return self.emit('error', err); }

            closeConnection(collection, function() {
                self.emit('released', "Lock successfully released for singleton '" + self._name + "'.");

                if (self._isSigterm) {
                    // exit so process doesn't keep processing
                    process.exit();
                }
            });
        });
    });
};

@@ -157,23 +157,16 @@
 ingleton
-Process
 (name, m
@@ -172,24 +172,24 @@
 mongoUri) %7B%0A
+
     var self
@@ -879,23 +879,16 @@
 ingleton
-Process
 , EventE
@@ -901,44 +901,8 @@
 );%0A%0A
-module.exports = SingletonProcess;%0A%0A
 func
@@ -1056,39 +1056,32 @@
 ();%0A%7D%0A%0ASingleton
-Process
 .prototype.lock 
@@ -2792,15 +2792,8 @@
 eton
-Process
 .pro
@@ -3694,31 +3694,76 @@
     %7D);%0A        %7D);%0A    %7D);%0A
-
 %7D;%0A
+%0Amodule.exports = %7B %0A%09Singleton: Singleton%0A%7D%0A

Rename SingletonProcess class to just Singleton