#!/usr/bin/env node
var assert = require('assert');

var async = require('async');
var mongoose = require('mongoose');
var funkit = require('funkit');
var equals = funkit.ops.equals;
var is = require('is-js');

var sugar = require('../lib/mongoose-sugar');
var models = require('./models');

var log = console.log.bind(console);

main();

// TODO: test getAll
// TODO: test getAll with filtering

function main() {
    var address = 'mongodb://localhost/mongoose-sugar-test';

    mongoose.connect(address, function(err) {
        if(err) log('Make sure mongod is running!');
    });

    log('Executing tests!');

    async.series(setup([
        createAuthor,
        updateAuthor,
        removeAuthor,
        getAuthor,
        getAuthorName,
        getMeta
    ], function(t) {
        return function(cb) {
            async.series([
                removeAuthors,
                removeLibraries
            ], t.bind(undefined, cb));
        };
    }), function() {
        log('Tests executed!');

        process.exit();
    });
}

function setup(tests, fn) {
    return tests.map(function(t) {
        return fn(t);
    });
}

// TODO: figure out why bind doesn't work for these!
function removeAuthors(cb) {
    removeAll(models.Author, cb);
}

function removeLibraries(cb) {
    removeAll(models.Library, cb);
}

function getAuthorName(cb) {
    createAuthor(function(err, author) {
        sugar.get(models.Author, author._id, ['name'], function(err, d) {
            assert.equal(d.name, author.name);
            assert.equal(d._id, author._id.toString()); // XXX. toString needed

            cb(err, d);
        });
    });
}

function getAuthor(cb) {
    createAuthor(function(err, author) {
        sugar.get(models.Author, author._id, function(err, d) {
            // XXX: figure out why d._id.toString() is needed (different encoding?)
            //assert.ok(equals(author, d));
            assert.equal(author._id, d._id.toString());

            cb(err, d);
        });
    });
}

function updateAuthor(cb) {
    createAuthor(function(err, d) {
        var name = d.name + d.name;

        d.name = name;

        sugar.update(models.Author, d._id, d, function(err, d) {
            assert.equal(d.name, name);

            cb(err, d);
        });
    });
}

function removeAuthor(cb) {
    createAuthor(function(err, d) {
        sugar.remove(models.Author, d._id, function(err, d) {
            assert.ok(d.deleted);

            sugar.count(models.Author, function(err, d) {
                assert.equal(d, 0);

                cb(err, d);
            });
        });
    });
}

function createAuthor(cb) {
    var name= 'Joe';
    var extra = ['foobar', 'barbar'];
    var data = {
        name: name,
        extra: extra
    };

    sugar.create(models.Author, data, function(err, d) {
        assert.equal(d.name, name);
        assert.ok(equals(d.extra, extra));

        cb(err, d);
    });
}

function removeAll(model, cb) {
    sugar.removeAll(model, function(err, d) {
        cb(err, d);
    });
}

function getMeta(cb) {
    sugar.getMeta(models.Author, function(err, d) {
        assert.ok(is.object(d));

        cb(err, d);
    });
}

@@ -645,32 +645,34 @@
     createAuthor
+()
 ,%0A        update
@@ -1361,32 +1361,34 @@
    createAuthor(
+)(
 function(err, au
@@ -1678,32 +1678,34 @@
    createAuthor(
+)(
 function(err, au
@@ -2045,32 +2045,34 @@
    createAuthor(
+)(
 function(err, d)
@@ -2333,16 +2333,18 @@
 eAuthor(
+)(
 function
@@ -2605,32 +2605,103 @@
  %7D);%0A    %7D);%0A%7D%0A%0A
+// XXX: using factory here since bind does not seem to work with async%0A
 function createA
@@ -2698,34 +2698,36 @@
 on createAuthor(
-cb
+data
 ) %7B%0A    var name
@@ -2726,16 +2726,141 @@
 var name
+, extra; // TODO: tidy up%0A    if(data) %7B%0A        name = data.name;%0A        extra = data.extra;%0A    %7D%0A    else %7B%0A        name 
 = 'Joe';
@@ -2864,19 +2864,19 @@
 e';%0A    
-var
+   
  extra =
@@ -2902,19 +2902,19 @@
 '%5D;%0A    
-var
+   
  data = 
@@ -2919,24 +2919,28 @@
 = %7B%0A        
+    
 name: name,%0A
@@ -2935,24 +2935,28 @@
 name: name,%0A
+    
         extr
@@ -2972,12 +2972,52 @@
     
+ 
-%7D;%0A%0A
+   %7D;%0A    %7D%0A%0A    return function(cb) %7B%0A    
     
@@ -3069,32 +3069,36 @@
 r, d) %7B%0A        
+    
 assert.equal(d.n
@@ -3109,32 +3109,36 @@
  name);%0A        
+  
+  
 assert.ok(equals
@@ -3157,32 +3157,36 @@
 tra));%0A%0A        
+    
 cb(err, d);%0A    
@@ -3177,32 +3177,36 @@
 cb(err, d);%0A
+    
     %7D);%0A
 %7D%0A%0Afunction 
@@ -3185,32 +3185,39 @@
 d);%0A        %7D);%0A
+    %7D;%0A
 %7D%0A%0Afunction remo

Move createAuthor as a factory