var assert = require('assert');
var debug = require('debug')('arango-lock');
var Promise = require('bluebird');
var shortid = require('shortid');
var util = require('arango-util');

exports.acquire = function (options) {
    assert.ok(options, 'options is required');

    var expiration = options.expiration || 5000;
    var func = String(dbFunc);
    var lockId = shortid();
    var name = options.name;
    var server = options.server;
    var ping = true;

    assert.ok(name, 'name is required');
    assert.ok(expiration >= 5000, 'expiration should be greater or equal to 5000ms');
    assert.ok(server, 'server should be an arangodb database object');

    function acquireLock(resolve, reject) {
        debug(`acquiring lock '${name}'`);

        util.ensureCollectionExists({ server: server, name: 'locks' })
            .then(() => updateLockInDb('acquire'))
            .catch(reject)
            .then(function (acquired) {
                if (acquired) {
                    debug(`lock '${name}' acquired`);
                    resolve();
                } else {
                    debug(`lock '${name}' is in used, will reattempt to acquire the lock.`);
                    setTimeout(() => acquireLock(resolve, reject), 500);
                }
            });
    }

    function hearBeat() {
        setTimeout(function () {
            if (ping)
                updateLockInDb('hearBeat').then(hearBeat);
        }, expiration / 2);
    }

    function releaseLock() {
        if (ping) {
            debug(`attempting to release lock '${name}'`);
            ping = false;
            return updateLockInDb('release').then(function (v) {
                debug(`lock '${name}' released`);
                return v;
            });
        }
    }

    function updateLockInDb(action) {
        return server.transaction({ write: ['locks'] }, func, { action, name, lockId, expiration });
    }

    var promise = new Promise(acquireLock);

    return promise.then(function () {
        hearBeat();
        return releaseLock;
    });
}

function dbFunc(params) {
    var locks = require('org/arangodb').db.locks;
    var lock = locks.documents([params.name]).documents[0];
    var isExpired = lock && (new Date() - new Date(lock.date)) >= params.expiration;
    var isValid = lock && lock.lockId === params.lockId;

    function checkErrors() {
        if (isExpired) throw new Error('Lock expired.');
        if (!isValid) throw new Error('Lock invalid.');
    }

    switch (params.action) {
        case 'acquire':
            if (lock && !isExpired) return false;

            var doc = { lockId: params.lockId, date: new Date() };

            if (lock) {
                locks.replace(params.name, doc);
            } else {
                doc._key = params.name;
                locks.save(doc);
            }
            return true;

        case 'hearBeat':
            checkErrors();
            locks.replace(params.name, { date: new Date() });
            return true;

        case 'release':
            checkErrors();
            locks.remove(params.name);
            return true;
    }

    throw new Error('Invalid action');
}
@@ -1292,24 +1292,25 @@
 unction hear
+t
 Beat() %7B%0A   
@@ -1302,24 +1302,24 @@
 artBeat() %7B%0A
-
         setT
@@ -1360,16 +1360,70 @@
 f (ping)
+ %7B%0A                debug(%60heartBeat lock '$%7Bname%7D''%60);
 %0A       
@@ -1447,24 +1447,25 @@
 ckInDb('hear
+t
 Beat').then(
@@ -1472,15 +1472,30 @@
 hear
+t
 Beat);%0A
+            %7D%0A
     
@@ -2070,24 +2070,25 @@
         hear
+t
 Beat();%0A    
@@ -2947,16 +2947,17 @@
 se 'hear
+t
 Beat':%0A 

add loggin of heartBeat