var buffalo = require('../buffalo')

var buffaloCommands = buffalo.mongo
var buffaloLong = buffalo.Long

var mongodb = require('mongodb')
var mongoLong = mongodb.Long

var COUNT = 10000

var x, start, end, i

function testCommandsBuffalo() {

    buffaloCommands.serializeUpdate('db.collection', {}, {}, false, false)
    buffaloCommands.serializeUpdate('db.collection', {}, {}, true, false)
    buffaloCommands.serializeUpdate('db.collection', {}, {}, false, true)
    buffaloCommands.serializeUpdate('db.collection', {}, {}, true, true)
    buffaloCommands.serializeUpdate('db.collection', {foo:1}, {bar:2}, false, false)
    buffaloCommands.serializeUpdate('db.collection', {bar:0}, {$set:{bar:1}}, false, false)
    buffaloCommands.serializeUpdate('db.collection', {'bar.bar':0}, {$inc:{'foo.foo':1}}, false, false)
    buffaloCommands.serializeUpdate('db.collection', {foo:1}, {bar:2}, true, false)
    buffaloCommands.serializeUpdate('db.collection', {bar:0}, {$set:{bar:1}}, true, false)
    buffaloCommands.serializeUpdate('db.collection', {'bar.bar':0}, {$inc:{'foo.foo':1}}, false, false)
    buffaloCommands.serializeUpdate('db.col3lection', {}, {}, false, false)
    buffaloCommands.serializeUpdate('db.col4lection', {}, {}, true, false)
    buffaloCommands.serializeUpdate('db.col5lection', {}, {}, false, true)
    buffaloCommands.serializeUpdate('db.col6lection', {}, {}, true, true)
    buffaloCommands.serializeUpdate('db.col7lection', {foo:1}, {bar:2}, false, false)
    buffaloCommands.serializeUpdate('db.col8lection', {bar:0}, {$set:{bar:1}}, false, false)
    buffaloCommands.serializeUpdate('db.col9lection', {'bar.bar':0}, {$inc:{'foo.foo':1}}, false, false)
    buffaloCommands.serializeUpdate('db.col0lection', {foo:1}, {bar:2}, true, false)
    buffaloCommands.serializeUpdate('db.collection', {bar:0}, {$set:{bar:1}}, true, false)
    buffaloCommands.serializeUpdate('db.collection', {'bar.bar':0}, {$inc:{'foo.foo':1}}, false, false)

    buffaloCommands.serializeInsert('db.col', [{one:1,two:2}], false)
    buffaloCommands.serializeInsert('db.col', [{one:1,two:2}], true)
    buffaloCommands.serializeInsert('db.col', [{one:1,two:2},{three:3,four:4}], true)
    buffaloCommands.serializeInsert('db.col', [{one:1,two:2},{three:3,four:4}], false)

    buffaloCommands.serializeQuery('db.foo', 0, 0, 0, {foo:1})
    buffaloCommands.serializeQuery('db.foo', 0, 0, 0, {foo:1}, {foo:1})
    buffaloCommands.serializeQuery('db.foo', 0, 1, 2, {foo:1})
    buffaloCommands.serializeQuery('db.foo', 0, 1, 2, {foo:1}, {foo:1})
    buffaloCommands.serializeQuery('db.foo', 0, 1, 2, {foo:1})
    buffaloCommands.serializeQuery('db.foo', 0, 1, 2, {foo:1}, {foo:1})

    buffaloCommands.serializeGetMore('db.bar', 10, new buffaloLong(0))
    buffaloCommands.serializeGetMore('db.bar', 10, new buffaloLong(10))
    buffaloCommands.serializeGetMore('db.bar', 10, new buffaloLong(10,10))
    buffaloCommands.serializeGetMore('db.bar', 10000, new buffaloLong(0))
    buffaloCommands.serializeGetMore('db.bar', 10000, new buffaloLong(10))
    buffaloCommands.serializeGetMore('db.bar', 10000, new buffaloLong(10,10))

    buffaloCommands.serializeDelete('db.foo', {foo:1})
    buffaloCommands.serializeDelete('db.foo', {})

    buffaloCommands.serializeKillCursors(db, [new buffaloLong(0)])
    buffaloCommands.serializeKillCursors(db, [new buffaloLong(1,10)])
    buffaloCommands.serializeKillCursors(db, [new buffaloLong(0),new buffaloLong(1,10)])
    buffaloCommands.serializeKillCursors(db, [new buffaloLong(0),new buffaloLong(1,10),new buffaloLong(50,50)])

}

function MongoResponse(buffer, offset, size) {
    offset = offset || 0
    var reply = new mongodb.MongoReply
    var message = buffer.slice(offset,size)
    reply.parseHeader(message, mongodb.BSONPure)
    reply.parseBody(message, mongodb.BSONPure, null)
    return {
        requestId:reply.requestId,
        responseTo:reply.responseTo,
        flags:reply.responseFlag,
        cursor:reply.cursorId,
        index:reply.startingFrom,
        documents:reply.documents
    }
}


var db = {
    bson_serializer:mongodb.BSONPure,
    bson_deserializer:mongodb.BSONPure
}

function serializeUpdate(fullCollectionName, spec, document, upsert, multiUpdate) {
    return new mongodb.UpdateCommand(db, fullCollectionName, spec, document, {
        upsert: upsert,
        multi: multiUpdate
    }).toBinary()
}
function serializeInsert(fullCollectionName, documents, continueOnError) {
    var checkKeys = false
    var insert = new mongodb.InsertCommand(db, fullCollectionName, checkKeys, {
        keepGoing:continueOnError
    })
    insert.documents = documents
    return insert.toBinary()
}
function testCommandsMongoNative() {
    serializeUpdate('db.collection', {}, {}, false, false)
    serializeUpdate('db.collection', {}, {}, true, false)
    serializeUpdate('db.collection', {}, {}, false, true)
    serializeUpdate('db.collection', {}, {}, true, true)
    serializeUpdate('db.collection', {foo:1}, {bar:2}, false, false)
    serializeUpdate('db.collection', {bar:0}, {$set:{bar:1}}, false, false)
    serializeUpdate('db.collection', {'bar.bar':0}, {$inc:{'foo.foo':1}}, false, false)
    serializeUpdate('db.collection', {foo:1}, {bar:2}, true, false)
    serializeUpdate('db.collection', {bar:0}, {$set:{bar:1}}, true, false)
    serializeUpdate('db.collection', {'bar.bar':0}, {$inc:{'foo.foo':1}}, false, false)
    serializeUpdate('db.col3lection', {}, {}, false, false)
    serializeUpdate('db.col4lection', {}, {}, true, false)
    serializeUpdate('db.col5lection', {}, {}, false, true)
    serializeUpdate('db.col6lection', {}, {}, true, true)
    serializeUpdate('db.col7lection', {foo:1}, {bar:2}, false, false)
    serializeUpdate('db.col8lection', {bar:0}, {$set:{bar:1}}, false, false)
    serializeUpdate('db.col9lection', {'bar.bar':0}, {$inc:{'foo.foo':1}}, false, false)
    serializeUpdate('db.col0lection', {foo:1}, {bar:2}, true, false)
    serializeUpdate('db.collection', {bar:0}, {$set:{bar:1}}, true, false)
    serializeUpdate('db.collection', {'bar.bar':0}, {$inc:{'foo.foo':1}}, false, false)

    serializeInsert('db.col', [{one:1,two:2}], false)
    serializeInsert('db.col', [{one:1,two:2}], true)
    serializeInsert('db.col', [{one:1,two:2},{three:3,four:4}], true)
    serializeInsert('db.col', [{one:1,two:2},{three:3,four:4}], false)

    new mongodb.QueryCommand(db, 'db.foo', 0, 0, 0, {foo:1}).toBinary()
    new mongodb.QueryCommand(db, 'db.foo', 0, 0, 0, {foo:1}, {foo:1}).toBinary()
    new mongodb.QueryCommand(db, 'db.foo', 0, 1, 2, {foo:1}).toBinary()
    new mongodb.QueryCommand(db, 'db.foo', 0, 1, 2, {foo:1}, {foo:1}).toBinary()
    new mongodb.QueryCommand(db, 'db.foo', 0, 1, 2, {foo:1}).toBinary()
    new mongodb.QueryCommand(db, 'db.foo', 0, 1, 2, {foo:1}, {foo:1}).toBinary()

    new mongodb.GetMoreCommand(db, 'db.bar', 10, new mongoLong(0)).toBinary()
    new mongodb.GetMoreCommand(db, 'db.bar', 10, new mongoLong(10)).toBinary()
    new mongodb.GetMoreCommand(db, 'db.bar', 10, new mongoLong(10,10)).toBinary()
    new mongodb.GetMoreCommand(db, 'db.bar', 10000, new mongoLong(0)).toBinary()
    new mongodb.GetMoreCommand(db, 'db.bar', 10000, new mongoLong(10)).toBinary()
    new mongodb.GetMoreCommand(db, 'db.bar', 10000, new mongoLong(10,10)).toBinary()

    new mongodb.DeleteCommand(db,'db.foo', {foo:1}).toBinary()
    new mongodb.DeleteCommand(db,'db.foo', {}).toBinary()

    new mongodb.KillCursorCommand(db, [new mongoLong(0)]).toBinary()
    new mongodb.KillCursorCommand(db, [new mongoLong(1,10)]).toBinary()
    new mongodb.KillCursorCommand(db, [new mongoLong(0),new mongoLong(1,10)]).toBinary()
    new mongodb.KillCursorCommand(db, [new mongoLong(0),new mongoLong(1,10),new mongoLong(50,50)]).toBinary()
}



function testResponse(base64, requestId, responseTo, flags, cursor, index, documents) {
    var buffer = new Buffer(base64,'base64')
    exports['testing response: '+base64] = function(test) {
        var a = new buffalo1.Response(buffer)
        var b = new buffalo2.Response(buffer)
        test.done()
    }
}

var replies = [
  "CwEAAJNdBQABAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAA5wAAAAJzZXROYW1lAAYAAABtb25nbwAIaXNtYXN0ZXIAAQhzZWNvbmRhcnkAAARob3N0cwAzAAAAAjAAEAAAAGxvY2FsaG9zdDoyNzAxNwACMQAQAAAAbG9jYWxob3N0OjI3MDE4AAAEYXJiaXRlcnMAHAAAAAIwABAAAABsb2NhbGhvc3Q6MjcwMTkAAAJwcmltYXJ5ABAAAABsb2NhbGhvc3Q6MjcwMTcAAm1lABAAAABsb2NhbGhvc3Q6MjcwMTcAEG1heEJzb25PYmplY3RTaXplAAAAAAEBb2sAAAAAAAAA8D8A",
  "CwEAAG1WBQACAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAA5wAAAAJzZXROYW1lAAYAAABtb25nbwAIaXNtYXN0ZXIAAAhzZWNvbmRhcnkAAQRob3N0cwAzAAAAAjAAEAAAAGxvY2FsaG9zdDoyNzAxOAACMQAQAAAAbG9jYWxob3N0OjI3MDE3AAAEYXJiaXRlcnMAHAAAAAIwABAAAABsb2NhbGhvc3Q6MjcwMTkAAAJwcmltYXJ5ABAAAABsb2NhbGhvc3Q6MjcwMTcAAm1lABAAAABsb2NhbGhvc3Q6MjcwMTgAEG1heEJzb25PYmplY3RTaXplAAAAAAEBb2sAAAAAAAAA8D8A",
  "UQAAAJRdBQADAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAALQAAAAJkcm9wcGVkAA8AAABtb25nb2xpYW5fdGVzdAABb2sAAAAAAAAA8D8A",
  "YwAAAJpdBQAEAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAAPwAAABBuAAAAAAASbGFzdE9wAAEAAAAIuO5OEGNvbm5lY3Rpb25JZADhAAAACmVycgABb2sAAAAAAAAA8D8A",
  "UAAAAJxdBQAFAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAALAAAAAJuYW1lAAwAAABoZWxsbyB3b3JsZAAHX2lkAE7uuAfJLuEAAAAAAQA=",
  "nQAAAKhdBQARAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAADAAAAIwAAAAJuYW1lABQAAABtb25nb2xpYW5fdGVzdC50ZXN0AAAtAAAAAm5hbWUAHgAAAG1vbmdvbGlhbl90ZXN0LnN5c3RlbS5pbmRleGVzAAApAAAAAm5hbWUAGgAAAG1vbmdvbGlhbl90ZXN0LnRlc3QuJF9pZF8AAA==",
  " ",
  "QAAAAMpdBQAaAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAAHAAAAAFuAAAAAAAAQI9AAW9rAAAAAAAAAPA/AA==",
  "QAAAAMtdBQAbAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAAHAAAAAFuAAAAAAAAQI9AAW9rAAAAAAAAAPA/AA==",
  "QAAAAMxdBQAcAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAAHAAAAAFuAAAAAAAAQI9AAW9rAAAAAAAAAPA/AA==",
  "QAAAAM1dBQAdAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAAHAAAAAFuAAAAAAAAAElAAW9rAAAAAAAAAPA/AA==",
  "sgAAAGJeBQBIAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAAjgAAAAdfaWQATu64Qsku4QAAACsJEGNodW5rU2l6ZQAAAAQAEGxlbmd0aAAMAAAAAmZpbGVuYW1lAAQAAABmb28AAm1kNQAhAAAAODZmYjI2OWQxOTBkMmM4NWY2ZTA0NjhjZWNhNDJhMjAACmNvbnRlbnRUeXBlAAl1cGxvYWREYXRlAEHCf1Q0AQAAAA==",
  "YwAAAIZeBQBVAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAAPwAAABBuAAAAAAASbGFzdE9wAAIAAABWuO5OEGNvbm5lY3Rpb25JZADnAAAACmVycgABb2sAAAAAAAAA8D8A",
  "RQAAAKBeBQBeAAAAAQAAAAgAAAAAAAAAAAAAAAAAAAABAAAAIQAAAAFyZXR2YWwAAAAAAAAAJkABb2sAAAAAAAAA8D8A"
].map(function(base64) {
    return new Buffer(base64, 'base64')
})


function testReplyBuffalo() {
    for (var i=replies.length; --i>=0;) {
        new buffaloCommands.Response(replies[i])
    }
}
function testReplyMongoNative() {
    for (var i=replies.length; --i>=0;) {
        var reply = new mongodb.MongoReply
        var message = replies[i]
        reply.parseHeader(message, mongodb.BSONPure)
        reply.parseBody(message, mongodb.BSONPure, null, function(){})
    }
}

start = Date.now()
for (i=COUNT; --i>=0; ) {
    testCommandsBuffalo()
}
end = Date.now()
console.log(COUNT + "x serialize sample commands with buffalo         time = ", end - start, "ms -", COUNT * 1000 / (end - start), " ops/sec")


start = Date.now()
for (i=COUNT; --i>=0; ) {
    testCommandsMongoNative()
}
end = Date.now()
console.log(COUNT + "x serialize sample commands with mongodbnative   time = ", end - start, "ms -", COUNT * 1000 / (end - start), " ops/sec")


start = Date.now()
for (i=COUNT; --i>=0; ) {

    testReplyBuffalo()
}
end = Date.now()
console.log(COUNT + "x parse sample replies with buffalo              time = ", end - start, "ms -", COUNT * 1000 / (end - start), " ops/sec")


start = Date.now()
for (i=COUNT; --i>=0; ) {

    testReplyMongoNative()
}
end = Date.now()
console.log(COUNT + "x parse sample replies with mongodbnative        time = ", end - start, "ms -", COUNT * 1000 / (end - start), " ops/sec")

