var panopticon = require('panopticon'),
    mongoose = require('mongoose');

/*
 *  clearCollections
 *  - Removes documents from collections
 *  - Used after tests to reset db
 *  - https://github.com/elliotf/mocha-mongoose/blob/master/index.js
 */ 
var clearCollections = function(db, callback) {
  db.collections(function(err, collections){
    if (err) return callback(err);

    var todo = collections.length;
    if (!todo) return callback(null);

    collections.forEach(function(collection){
      if (collection.collectionName.match(/^system\./)) return --todo;

      collection.remove({},{safe: true}, function(){
        if (--todo === 0) callback(null);
      });
    });
  });
};

var personSchema = mongoose.Schema({
  name: String,
  email: String,
  address: {
    line1: String
  },
  pets: [{
    name: String
  }]
});
var rules = {
    'name': function() {},
    'email': function() {},
    'pets': {
        'name': function() {}
    }
};
panopticon.watch(personSchema, rules);
var Person = mongoose.model('Person', personSchema);

describe("Panopticon", function() {

    beforeEach(function(done){
        // Connect to the DB
        var mongoUri = 'mongodb://localhost/test';
        mongoose.connect(mongoUri, done);
    });
  
    afterEach(function(done){
        clearCollections(mongoose.connection.db, function(){
            mongoose.connection.close(done);
        });
    });
  
    describe("#watch", function(){
        var person;

        beforeEach(function(done){
            Person.create({
                name: 'Adam'
            }, function(err, p){
                // Get for 'init'
                Person.findById(p.id, function(err, p){
                    person = p;
                    done();
                });
            });
        });

        describe("calls rule handler after", function(){
            it("property addition", function(done){
                spyOn(rules, 'email');
                person.email = 'adam@email.com';
                person.save(function(err, person){
                    expect(rules.email).toHaveBeenCalledWith('adam@email.com');
                    done();
                });
            });
            it("property update", function(done){
                spyOn(rules, 'name');
                person.name = 'Bert';
                person.save(function(err, person){
                    expect(rules.name).toHaveBeenCalledWith('Bert');
                    done();
                });
            });
            it("property deletion", function(done){
                spyOn(rules, 'name');
                person.name = null;
                person.save(function(err, person){
                    expect(rules.name).toHaveBeenCalledWith(null);
                    done();
                });
            });
        });

    });

});


@@ -781,24 +781,43 @@
   line1:
+ String,%0A    line2:
  String%0A
   %7D,%0A  p
@@ -808,16 +808,16 @@
  String%0A
-
   %7D,%0A  p
@@ -915,24 +915,107 @@
 ction() %7B%7D,%0A
+    'address': %7B%0A        line1: function() %7B%7D,%0A        line2: function() %7B%7D%0A    %7D,%0A
     'pets': 
@@ -1655,16 +1655,107 @@
 : 'Adam'
+,%0A                address: %7B%0A                    line1: '123 Street Lane'%0A                %7D
 %0A       
@@ -2850,32 +2850,32 @@
 n(err, person)%7B%0A
-
                 
@@ -2980,32 +2980,1101 @@
 %0A            %7D);
+%0A%0A            it(%22nested property addition%22, function(done)%7B%0A                spyOn(rules.address, 'line2');%0A                person.address.line2 = 'Townville';%0A                person.save(function(err, person)%7B%0A                    expect(rules.address.line2).toHaveBeenCalledWith('Townville');%0A                    done();%0A                %7D);%0A            %7D);%0A            it(%22nested property update%22, function(done)%7B%0A                spyOn(rules.address, 'line1');%0A                person.address.line1 = '56 Another Street';%0A                person.save(function(err, person)%7B%0A                    expect(rules.address.line1).toHaveBeenCalledWith('56 Another Street');%0A                    done();%0A                %7D);%0A            %7D);%0A            it(%22nested property deletion%22, function(done)%7B%0A                spyOn(rules.address, 'line1');%0A                person.address.line1 = null;%0A                person.save(function(err, person)%7B%0A                    expect(rules.address.line1).toHaveBeenCalledWith(null);%0A                    done();%0A                %7D);%0A            %7D);
 %0A        %7D);%0A%0A  

Add tests for nested properties