/**
 * Created by xiaoqiang on 6/20/16.
 */

var Module =  angular.module('PsMirror', []);
Module.controller('RootController', ['$scope', function($s){
    
    var socket = null;
    $s.isFullscreen = false;
    $s.isTouch = false;
    $s.buffer = null;

    $s.document_list = [];
    $s.selected = "";

    function init() {
        socket = new WebSocket('ws://127.0.0.1:42200');
        socket.binaryType = 'arraybuffer';
        socket.onopen = function () {
            console.log('connection to server opened');
            socket.send(parseSend({id: (new Date()).getTime(), command: 'register', from: 'browser', identity: 'abc@default.com', email: 'abc@default.com', uid: '1', extra:
                JSON.stringify({
                    deviceName: 'browser',
                    deviceType: 'web',
                    dpi: '1024 x 1024',
                    ip: '127.0.0.1',
                    mac: '127.0.0.1',
                    version: '1.0'
                })
            }));
            //socket.send(JSON.stringify({action: 'register', param: ""}));
        };
        socket.onmessage = function (msgEvt) {
            var data = msgEvt.data;
            onMessage(parseReceived(data));
        };
    }

    function onMessage(messages) {
        for (var i=0; i< messages.length; i++) {
            var msg = messages[i];
            switch (msg.command) {
                case "document_list":
                    $s.document_list = [];
                    $s.document_list = JSON.parse(msg.extra);
                    for (var i=0; i<$s.document_list.length; i++) {
                        if ($s.document_list[i]['active'] == 1) {
                            $s.selected = $s.document_list[i]['name'];
                            break;
                        }
                    }
                    $s.$apply();
                    break;
                case "document":
                    var extra = JSON.parse(msg.extra);
                    $s.selected = extra['name'];
                    var tmp = $s.document_list;
                    $s.document_list = [];
                    $s.document_list = tmp;
                    $s.$apply();
                    break;
                case "image":
                    if (msg.binary) {
                        var url = "data:image/jpg;base64,"+ arrayBufferToBase64(msg.binary);
                        //console.log(url);
                        $('#artboard-img').attr('src', url);
                        $('#artboard-img2').attr('src', url);
                        $('#artboard-img').parent().attr('href', url);
                    }
                    socket.send(parseSend({id: (new Date()).getTime(), command: 'image_ack', from: 'browser', identity: 'abc@default.com', email: 'abc@default.com', uid: '1'}));
                    break;
            }
        }
    }
    
    $s.select = function (doc) {
        $s.isTouch = !$s.isTouch;
        var key = doc.parent + '_' + doc.id;
        socket.send(parseSend({id: (new Date()).getTime(), command: 'image', from: 'browser', identity: 'abc@default.com', email: 'abc@default.com', uid: '1', extra: JSON.stringify({key: key, force: 1})}));
        //socket.send(JSON.stringify({action: 'select_document', param: {id: key}}));
    };
    
    $s.toggleFullscreen = function () {
        if ($s.isFullscreen) {
            exitFullscreen();
            $('.document-list').show();
        } else {
            $('.document-list').hide();
            fullscreen();
        }
        $s.isFullscreen = !$s.isFullscreen;
    };
    
    function arrayBufferToBase64(bytes) {
        var binary = '';
        var len = bytes.byteLength;
        for (var i=0; i<len; i++) {
            binary += String.fromCharCode(bytes[i])
        }
        return window.btoa(binary);
    }

    function parseSend(json) {
        var payload = JSON.stringify(json);
        console.log('send msg: ' + payload);
        var data = 'L:' + payload.length + ';' + payload + "\r\n";
        var buffer = new ArrayBuffer(data.length);
        var bufView = new Uint8Array(buffer);
        for (var i=0; i < data.length; i++) {
            bufView[i] = data.charCodeAt(i);
        }
        return buffer;
    }

    /**
     * 接收的数据结构如下
     * L: + message_length + | + binary_length + ; + message + binary + \r\n
     */
    function parseReceived(dataBuf) {
        var data = new Uint8Array(dataBuf);
        if ($s.buffer) {
            data = ArrayBuffer.concat([$s.buffer, data]);
            $s.buffer = null;
        }
        var messages = [];
        var pos = 0;
        var total = data.byteLength;
        while (total - pos > 4) {
            // 检查是否以L:开头
            if (data[pos] !== 76 || data[pos + 1] !== 58) {
                var slice = data.slice(pos, pos + 2);
                throw new Error("Missing length header in received data: " + slice);
            }

            // 找到头部(;位置)长度
            var endOfLengthHeader = _findCarriageSemicolon(data, pos + 2);
            if (endOfLengthHeader === -1 || data.length == endOfLengthHeader) {
                break;
            }

            // L:(messageLengthStr.length|payload.length);(messageLength bytes)(payload bytes)
            var headerBuff = data.slice(pos+2, pos+2+endOfLengthHeader);
            var headerString = String.fromCharCode.apply(null, new Uint8Array(headerBuff)); //data.toString('utf8', pos+2, endOfLengthHeader);
            var messageLength = 0;
            var payloadLength = 0;
            if (headerString.indexOf('|') > 0) {
                var arr = headerString.split('|');
                messageLength = parseInt(arr[0]);
                payloadLength = parseInt(arr[1]);
            } else {
                messageLength = parseInt(headerString);
            }

            // 一个完整的包的长度 最后的2 是\r\n
            var packageLength = endOfLengthHeader + 1 + messageLength + payloadLength + 2;

            if (total < packageLength) {    // 收到的包不完整, 退出
                console.log('package not ready, received:' + total + ' total: ' + packageLength);
                $s.buffer = data.slice(pos, total);
                break;
            }

            // 解析消息结构体
            if (messageLength > 0) {
                var slice = data.slice(endOfLengthHeader + 1,  endOfLengthHeader + 1 + messageLength);
                var sliceStr =  Utf8ArrayToStr(slice); //String.fromCharCode.apply(null, new Uint8Array(slice));
                console.log('receive message string:' + sliceStr);
                var msg = JSON.parse(sliceStr);

                if (payloadLength > 0) {
                    var imgSlice = data.slice(endOfLengthHeader + 1 + messageLength, endOfLengthHeader + 1 + messageLength + payloadLength);
                    console.log('received payload length:' +  imgSlice.length);
                    msg.binary = imgSlice;
                }
                messages.push(msg);
            }
            pos += packageLength;
            $s.buffer = null;
        }
        return messages;
    }

    function _findCarriageSemicolon(buf, startPos) {
        for (var i = startPos; i < buf.length; i++) {
            if (buf[i] === 59) {    // L:44;xxxxxxxxx
                return i;
            }
        }
        return -1;
    }

    function Utf8ArrayToStr(array) {
        var out, i, len, c;
        var char2, char3;

        out = "";
        len = array.length;
        i = 0;
        while(i < len) {
            c = array[i++];
            switch(c >> 4)
            {
                case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
                // 0xxxxxxx
                out += String.fromCharCode(c);
                break;
                case 12: case 13:
                // 110x xxxx   10xx xxxx
                char2 = array[i++];
                out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
                break;
                case 14:
                    // 1110 xxxx  10xx xxxx  10xx xxxx
                    char2 = array[i++];
                    char3 = array[i++];
                    out += String.fromCharCode(((c & 0x0F) << 12) |
                        ((char2 & 0x3F) << 6) |
                        ((char3 & 0x3F) << 0));
                    break;
            }
        }

        return out;
    }

    function fullscreen(){
        elem=document.body;
        if(elem.webkitRequestFullScreen){
            elem.webkitRequestFullScreen();
        }else if(elem.mozRequestFullScreen){
            elem.mozRequestFullScreen();
        }else if(elem.requestFullScreen){
            elem.requestFullscreen();
        }else{
            //浏览器不支持全屏API或已被禁用  
        }
    }
    function exitFullscreen (){
        var elem=document;
        if(elem.webkitCancelFullScreen){
            elem.webkitCancelFullScreen();
        }else if(elem.mozCancelFullScreen){
            elem.mozCancelFullScreen();
        }else if(elem.cancelFullScreen){
            elem.cancelFullScreen();
        }else if(elem.exitFullscreen){
            elem.exitFullscreen();
        }else{
            //浏览器不支持全屏API或已被禁用  
        }
    }

    init();
    
}]);
