if(typeof module !== 'undefined'){

    var env = process.argv[3] === 'test' ? '.min' : '';
    var expect = require('chai').expect;
    var BulkSearch = require("../bulksearch" + env + ".js");
}

var bulksearch_default;
var bulksearch_sync;

var bulksearch_icase;
var bulksearch_simple;
var bulksearch_advanced;
var bulksearch_extra;
var bulksearch_custom;

// ------------------------------------------------------------------------
// Acceptance Tests
// ------------------------------------------------------------------------

describe('Initialize', function(){

    it('Should have been initialized successfully', function(){

        bulksearch_default = new BulkSearch();

        bulksearch_sync = new BulkSearch({

            encode: false,
            multi: true,
            strict: false
        });

        bulksearch_icase = new BulkSearch({

            encode: 'icase',
            multi: true,
            strict: false
        });

        bulksearch_simple = BulkSearch.create({

            encode: 'simple',
            multi: true,
            strict: false
        });

        bulksearch_advanced = new BulkSearch({

            encode: 'advanced',
            multi: true,
            strict: false
        });

        bulksearch_extra = BulkSearch.create({

            encode: 'extra',
            multi: true,
            strict: false
        });

        bulksearch_custom = new BulkSearch({

            encode: test_encoder,
            multi: true,
            strict: false
        });

        expect(bulksearch_default).to.be.an.instanceOf(BulkSearch);
        expect(bulksearch_sync).to.be.an.instanceOf(BulkSearch);
    });

    it('Should have all provided methods', function(){

        expect(bulksearch_default).to.respondTo("search");
        expect(bulksearch_default).to.respondTo("add");
        expect(bulksearch_default).to.respondTo("update");
        expect(bulksearch_default).to.respondTo("remove");
        expect(bulksearch_default).to.respondTo("reset");
        expect(bulksearch_default).to.respondTo("init");
        expect(bulksearch_default).to.respondTo("info");
    });

    it('Should have correct uuids', function(){

        expect(bulksearch_default.id).to.equal(0);
        expect(bulksearch_sync.id).to.equal(1);
        expect(bulksearch_icase.id).to.equal(2);
        expect(bulksearch_simple.id).to.equal(3);
        expect(bulksearch_advanced.id).to.equal(4);
        expect(bulksearch_extra.id).to.equal(5);
    });

    it('Should have the correct options', function(){

        expect(bulksearch_default.type).to.equal('integer');
        expect(bulksearch_sync.type).to.equal('integer');
        expect(bulksearch_custom.encoder).to.equal(test_encoder);
    });
});

describe('Add (Sync)', function(){

    it('Should have been added to the index', function(){

        bulksearch_sync.add(0, "foo");
        bulksearch_sync.add(2, "bar");
        bulksearch_sync.add(1, "foobar");

        expect(bulksearch_sync.length).to.equal(3);
        expect(bulksearch_sync.index).to.have.keys([0, 1, 2]);
    });

    it('Should not have been added to the index', function(){

        bulksearch_sync.add("foo");
        bulksearch_sync.add(3);
        bulksearch_sync.add(null, "foobar");
        bulksearch_sync.add(void 0, "foobar");
        bulksearch_sync.add(3, null);
        bulksearch_sync.add(3, false);
        bulksearch_sync.add(3, []);
        bulksearch_sync.add(3, {});
        bulksearch_sync.add(3, function(){});

        expect(bulksearch_sync.length).to.equal(3);
        expect(bulksearch_sync.index).to.have.keys([0, 1, 2]);
    });
});

describe('Search (Sync)', function(){

    it('Should have been matched from index', function(){

        expect(bulksearch_sync.search("foo")).to.have.keys([0, 1]);
        expect(bulksearch_sync.search("bar")).to.include(2);
        expect(bulksearch_sync.search("foobar")).to.include(1);

        expect(bulksearch_sync.search("foo foo")).to.have.keys([0, 1]);
        expect(bulksearch_sync.search("foo  foo")).to.have.keys([0, 1]);
    });

    it('Should have been limited', function(){

        expect(bulksearch_sync.search("foo", 1)).to.include(0);
        expect(bulksearch_sync.search("foo", 1)).to.not.include(1);
    });

    it('Should not have been matched from index', function(){

        expect(bulksearch_sync.search("barfoo")).to.have.lengthOf(0);
        expect(bulksearch_sync.search("")).to.have.lengthOf(0);
        expect(bulksearch_sync.search("  ")).to.have.lengthOf(0);
        expect(bulksearch_sync.search(" o ")).to.have.lengthOf(2);
    });
});

describe('Update (Sync)', function(){

    it('Should have been updated to the index', function(){

        bulksearch_sync.update(0, "bar");
        bulksearch_sync.update(2, "foobar");
        bulksearch_sync.update(1, "foo");

        expect(bulksearch_sync.length).to.equal(3);
        expect(bulksearch_sync.search("foo")).to.include(2, 1);
        expect(bulksearch_sync.search("bar")).to.include(0, 2);
        expect(bulksearch_sync.search("foobar")).to.include(2);
    });

    it('Should not have been updated to the index', function(){

        bulksearch_sync.update("foo");
        bulksearch_sync.update(0);
        bulksearch_sync.update(null, "foobar");
        bulksearch_sync.update(void 0, "foobar");
        bulksearch_sync.update(1, null);
        bulksearch_sync.update(2, false);
        bulksearch_sync.update(0, []);
        bulksearch_sync.update(1, {});
        bulksearch_sync.update(2, function(){});

        expect(bulksearch_sync.length).to.equal(3);
        expect(bulksearch_sync.search("foo")).to.include(2, 1);
        expect(bulksearch_sync.search("bar")).to.include(0, 2);
        expect(bulksearch_sync.search("foobar")).to.include(2);
    });
});

describe('Remove (Sync)', function(){

    it('Should have been removed from the index', function(){

        bulksearch_sync.remove(0);
        bulksearch_sync.remove(2);
        bulksearch_sync.remove(1);

        expect(bulksearch_sync.length).to.equal(0);
        expect(bulksearch_sync.search("foo")).to.have.lengthOf(0);
        expect(bulksearch_sync.search("bar")).to.have.lengthOf(0);
        expect(bulksearch_sync.search("foobar")).to.have.lengthOf(0);
    });
});

// ------------------------------------------------------------------------
// Async Tests
// ------------------------------------------------------------------------

describe('Search (Async)', function(){

    it('Should have been matched from index', function(done){

        bulksearch_sync.add(0, "foo");
        bulksearch_sync.add(2, "bar");
        bulksearch_sync.add(1, "foobar");

        bulksearch_sync.search("foo", function(result){

            expect(result).to.have.keys([0, 1]);
        });

        bulksearch_sync.search("bar", function(result){

            expect(result).to.include(2);
        });

        bulksearch_sync.search("foobar", function(result){

            expect(result).to.include(1);
        });

        setTimeout(function(){

            done();

        }, 25);
    });

    it('Should have been limited', function(done){

        bulksearch_sync.search("foo", 1, function(result){

            expect(result).to.include(0);
            expect(result).to.not.include(1);
        });

        setTimeout(function(){

            done();

        }, 25);
    });

    it('Should not have been matched from index', function(done){

        bulksearch_sync.search("barfoo", function(result){

            expect(result).to.have.lengthOf(0);
        });

        bulksearch_sync.search("", function(result){

            expect(result).to.have.lengthOf(0);
        });

        bulksearch_sync.search(" ", function(result){

            expect(result).to.have.lengthOf(0);
        });

        bulksearch_sync.search(" o ", function(result){

            expect(result).to.have.lengthOf(2);
        });

        setTimeout(function(){

            done();

        }, 25);
    });
});

// ------------------------------------------------------------------------
// Phonetic Tests
// ------------------------------------------------------------------------

describe('Encoding', function(){

    it('Should have been encoded properly: iCase', function(){

        expect(bulksearch_icase.encode("Björn-Phillipp Mayer")).to.equal(bulksearch_icase.encode("björn-phillipp mayer"));
    });

    it('Should have been encoded properly: Simple', function(){

        expect(bulksearch_simple.encode("Björn-Phillipp Mayer")).to.equal(bulksearch_simple.encode("bjorn/phillipp mayer"));
    });

    it('Should have been encoded properly: Advanced', function(){

        expect(bulksearch_advanced.encode("Björn-Phillipp Mayer")).to.equal(bulksearch_advanced.encode("bjoern filip mair"));
    });

    it('Should have been encoded properly: Extra', function(){

        expect(bulksearch_extra.encode("Björn-Phillipp Mayer")).to.equal(bulksearch_extra.encode("bjorm filib mayr"));
    });

    it('Should have been encoded properly: Custom Encoder', function(){

        expect(bulksearch_custom.encode("Björn-Phillipp Mayer")).to.equal("-[BJÖRN-PHILLIPP MAYER]-");
    });
});

// ------------------------------------------------------------------------
// Feature Tests
// ------------------------------------------------------------------------

describe('Add Matchers', function(){

    it('Should have been added properly', function(){

        BulkSearch.addMatcher({

            '1': 'a',
            '2': 'b',
            '3': 'c',
            '[456]': 'd'
        });

        bulksearch_icase.add(0, "123456");

        expect(bulksearch_icase.search("123456")).to.include(0);
        expect(bulksearch_icase.search("abcd")).to.include(0);
        expect(bulksearch_icase.encode("123456")).to.equal("abcddd");
    });
});

/* Test Helpers */

function test_encoder(str){

    return ('-[' + str.toUpperCase() + ']-');
}
