//
// Test binary messages on websockets.
// Only works on slimer for now, due to old websocket impl in phantomjs.
//

casper.notebook_test(function () {
    if (!this.slimerjs) {
        console.log("Can't test binary websockets on phantomjs.");
        return;
    }
    // create EchoBuffers target on js-side.
    // it just captures and echos comm messages.
    this.then(function () {
        var success = this.evaluate(function () {
            IPython._msgs = [];
        
            var EchoBuffers = function(comm) {
                this.comm = comm;
                this.comm.on_msg($.proxy(this.on_msg, this));
            };

            EchoBuffers.prototype.on_msg = function (msg) {
                IPython._msgs.push(msg);
                this.comm.send(msg.content.data, {}, {}, msg.buffers);
            };

            IPython.notebook.kernel.comm_manager.register_target("echo", function (comm) {
                return new EchoBuffers(comm);
            });
        
            return true;
        });
        this.test.assertEquals(success, true, "Created echo comm target");
    });

    // Create a similar comm that captures messages Python-side
    this.then(function () {
        var index = this.append_cell([
            "import os",
            "from IPython.kernel.comm import Comm",
            "comm = Comm(target_name='echo')",
            "msgs = []",
            "def on_msg(msg):",
            "    msgs.append(msg)",
            "comm.on_msg(on_msg)"
        ].join('\n'), 'code');
        this.execute_cell(index);
    });
    
    // send a message with binary data
    this.then(function () {
        var index = this.append_cell([
            "buffers = [b'\\xFF\\x00', b'\\x00\\x01\\x02']",
            "comm.send(data='message 0', buffers=buffers)",
            "comm.send(data='message 1')",
            "comm.send(data='message 2', buffers=buffers)",
        ].join('\n'), 'code');
        this.execute_cell(index);
    });
    
    // wait for capture
    this.waitFor(function () {
        return this.evaluate(function () {
            return IPython._msgs.length >= 3;
        });
    });
    
    // validate captured buffers js-side
    this.then(function () {
        var msgs = this.evaluate(function () {
            return IPython._msgs;
        });
        this.test.assertEquals(msgs.length, 3, "Captured three comm messages");



        // check the messages came in the right order
        this.test.assertEquals(msgs[0].content.data, "message 0", "message 0 processed first");
        this.test.assertEquals(msgs[0].buffers.length, 2, "comm message 0 has two buffers");
        this.test.assertEquals(msgs[1].content.data, "message 1", "message 1 processed second");
        this.test.assertEquals(msgs[1].buffers.length, 0, "comm message 1 has no buffers");
        this.test.assertEquals(msgs[2].content.data, "message 2", "message 2 processed third");
        this.test.assertEquals(msgs[2].buffers.length, 2, "comm message 2 has two buffers");
        
        // extract attributes to test in evaluate,
        // because the raw DataViews can't be passed across
        var buf_info = function (message, index) {
            var buf = IPython._msgs[message].buffers[index];
            var data = {};
            data.byteLength = buf.byteLength;
            data.bytes = [];
            for (var i = 0; i < data.byteLength; i++) {
                data.bytes.push(buf.getUint8(i));
            }
            return data;
        };
        
        var msgs_with_buffers = [0, 2];
        for (var i = 0; i < msgs_with_buffers.length; i++) {
            msg_index = msgs_with_buffers[i];
            buf0 = this.evaluate(buf_info, msg_index, 0);
            buf1 = this.evaluate(buf_info, msg_index, 1);
            this.test.assertEquals(buf0.byteLength, 2, 'buf[0] has correct size in message '+msg_index);
            this.test.assertEquals(buf0.bytes, [255, 0], 'buf[0] has correct bytes in message '+msg_index);
            this.test.assertEquals(buf1.byteLength, 3, 'buf[1] has correct size in message '+msg_index);
            this.test.assertEquals(buf1.bytes, [0, 1, 2], 'buf[1] has correct bytes in message '+msg_index);
        }
    });
    
    // validate captured buffers Python-side
    this.then(function () {
        var index = this.append_cell([
            "assert len(msgs) == 3, len(msgs)",
            "bufs = msgs[0]['buffers']",
            "assert len(bufs) == len(buffers), bufs",
            "assert bufs[0].tobytes() == buffers[0], bufs[0]",
            "assert bufs[1].tobytes() == buffers[1], bufs[1]",
            "1",
        ].join('\n'), 'code');
        this.execute_cell(index);
        this.wait_for_output(index);
        this.then(function () {
            var out = this.get_output_cell(index);
            this.test.assertEquals(out.data['text/plain'], '1', "Python received buffers");
        });
    });
});
