const serial = chrome.serial;
var showDebugLog = false;

var SerialConnection = function() {
    this.connectionId = -1;
    this.boundOnReceive = this.onReceive.bind(this);
    this.boundOnReceiveError = this.onReceiveError.bind(this);
    this.onConnect = new MyEvent();
    this.onReceive = new MyEvent();
    this.onError = new MyEvent();
    this.recvBuffer = new Uint8Array(8*1024);
    this.recvView = new DataView(this.recvBuffer.buffer);
    this.recvCursor = 0;
    this.bitrate = 57600;
};

SerialConnection.prototype.onConnectComplete = function(connectionInfo) {
    if (!connectionInfo) {
        if (chrome.runtime.lastError != undefined) {
            logln('chrome.serial.connect error: ' + chrome.runtime.lastError.message);
        }
        return;
    }
    this.connectionId = connectionInfo.connectionId;
    chrome.serial.onReceive.addListener(this.boundOnReceive);
    chrome.serial.onReceiveError.addListener(this.boundOnReceiveError);
    this.onConnect.dispatch();
};

SerialConnection.prototype.onReceive = function(receiveInfo) {
    
    if (receiveInfo.connectionId !== this.connectionId) {
        return;
    }
    this.recvBuffer.set(new Uint8Array(receiveInfo.data), this.recvCursor);
    this.recvCursor += receiveInfo.data.byteLength;
    //console.log(buf2hex(receiveInfo.data));
    if (this.recvCursor < 6) {
        return;
    }
    this._dispathReceiveData();
};
SerialConnection.prototype.clearRecvData = function() {
    this.recvCursor = 0;
    this.recvBuffer.fill(0);
}
SerialConnection.prototype._dispathReceiveData = function() {
    var dLen = this.recvView.getUint16(7);
    if (this.recvCursor < dLen + 9) {
        return;
    }

    var dataBuffer = new Uint8Array(dLen + 9);
    dataBuffer.set(this.recvBuffer.subarray(0, dLen + 9));
    if (showDebugLog) {
        logln("recv:  " + buf2hex(dataBuffer.buffer));
    }


    var realCrc = calcCRC(dataBuffer, 6, dLen + 7);
    var crc = dataBuffer[dLen+7] * 256 + dataBuffer[dLen+8];
    if (crc != realCrc) {
        logln("invalid crc " + crc + " ,real= " + realCrc);
    }else {
        var packet = new Packet().fromDataBuffer(dataBuffer);
        this.onReceive.dispatch(packet);
    }

    

    if (this.recvCursor > dLen + 9) {
        dataBuffer = new Uint8Array(this.recvCursor - dLen - 6);
        dataBuffer.set(this.recvBuffer.subarray(dLen + 9, this.recvCursor));
        this.recvBuffer.fill(0);
        this.recvBuffer.set(dataBuffer);
        this.recvCursor -= dLen + 9;
        this._dispathReceiveData();
    }else {
        this.recvCursor = 0;
        this.recvBuffer.fill(0);
    }

}


SerialConnection.prototype.onReceiveError = function(errorInfo) {
    if (errorInfo.connectionId === this.connectionId) {
        this.onError.dispatch(errorInfo.error);
    }
};
  
SerialConnection.prototype.update = function(conf, cb) {
    if (!this.connectionId) {return;}
    serial.update(this.connectionId, conf, cb);
}
SerialConnection.prototype.connect = function(path, bitrate=57600) {
    this.clearRecvData();
    this.bitrate = bitrate;
    serial.connect(path,  { bitrate: this.bitrate },this.onConnectComplete.bind(this))
};
  
SerialConnection.prototype.send = function(packet) {
    if (this.connectionId < 0) {
        throw 'Invalid connection';
    }
    var data = packet.getDataBuffer();
    if (showDebugLog) {
        logln("send: " + buf2hex(data));
    }
    serial.send(this.connectionId, data, function() {});
};
  
SerialConnection.prototype.disconnect = function() {
    if (this.connectionId < 0) {
        throw 'Invalid connection';
    }
    serial.disconnect(this.connectionId, function() {});
};

////////////////////////////////////////////////////////
////////////////////////////////////////////////////////


function logln(msg) {
    var buffer = document.querySelector('#buffer');
    buffer.innerHTML += msg + '<br/>';
    var msgEnd = document.querySelector('#msg_end');
    msgEnd.scrollIntoView();
}

function log(msg) {
    var buffer = document.querySelector('#buffer');
    buffer.innerHTML += msg;
    var msgEnd = document.querySelector('#msg_end');
    msgEnd.scrollIntoView();
}

function buf2hex(buffer) { 
    return '0x' + Array.prototype.map.call(new Uint8Array(buffer), x => ('0x00' + x.toString(16)).slice(-2)).join(' 0x');
}

function calcCRC(buffer, start, end) {
    var crc = 0;
    for (var i = start; i < end; i++) {
        crc += buffer[i] & 0xff;
    }
    return crc & 0xffff;
}

const PacketTypeCmd         = 0x01;
const PacketTypeData        = 0x02;
const PacketTypeDataEnd     = 0x08;
const PacketTypeCmdResp     = 0x07;
const PacketTypeDataResp    = 0x09;

var Packet = function(data=new Uint8Array([0x35]), dataLen=1, type=PacketTypeCmd) {
    this.dataBuffer = new Uint8Array(512);
    this.dataBuffer.set([0xEF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF]);

    this.type = type;
    this.dataLen = dataLen;
    this.data = data;
    this.result = 0;
}
Packet.prototype.setCmd = function(cmd) {
    this.type = PacketTypeCmd;
    this.data = Uint8Array.of(cmd);
    this.dataLen = 1;
}
Packet.prototype.getDataBuffer = function () {
    var dataView = new DataView(this.dataBuffer.buffer);
    dataView.setUint8(6, this.type);

    var len = this.dataLen + 2;
    dataView.setUint16(7, len);
    this.dataBuffer.set(this.data, 9);

    var crc = calcCRC(this.dataBuffer, 6, this.dataLen + 9);
    dataView.setUint16(9 + this.dataLen, crc);

    return new Uint8Array(this.dataBuffer.buffer, 0, this.dataLen + 11);
}

Packet.prototype.fromDataBuffer = function(buffer) {
    this.dataBuffer.set(buffer);
    var dataView = new DataView(this.dataBuffer.buffer);

    this.type = dataView.getUint8(6);
    var len = dataView.getUint16(7);
    this.dataLen = len - 2;

    this.data = new Uint8Array(buffer.buffer, 9, this.dataLen);

    if (this.type == PacketTypeCmdResp) {
        this.result = this.data[0];
    }
    return this;
}


////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
var curDevice = null;

function tryHandshake(device) {

    return new Promise((resolve, reject) =>{
        logln("try handshake with " + device.path);
        var connection = new SerialConnection();
        var isValidDevice = 0;
        device.bitrate = 57600;
        connection.onConnect.addListener(function() {
            logln("device " + device.path + " connected");
            connection.send(new Packet());

        });
        connection.onReceive.addListener(function(packet) {
            if (packet.type == PacketTypeCmdResp && packet.result == 0) {
                isValidDevice = 1;
                connection.disconnect();
                resolve(1)
            }
        });
        connection.connect(device.path, device.bitrate);
        
        setTimeout(() => {
            if (isValidDevice) {
            }else {
                device.bitrate = 115200;
                connection.update({
                    bitrate: device.bitrate
                }, (result) => {
                    if (result) {
                        connection.send(new Packet());
                        setTimeout(() => {
                            connection.disconnect();
                            if (!isValidDevice) {
                                resolve(0);
                            }
                        }, 500);
                    }else {
                        connection.disconnect();
                        resolve(0);
                    }
                })
            }
            
        }, 500);
    })
    
}

async function checkDevices(devices) {
    for (var device of devices) {
        logln("found device, path = " + device.path);
        var res = await tryHandshake(device);
        if (res) {
            curDevice = device;
            logln("found valid device " + device.path);
            break;
        }
    }
}
////////////////////////////////////////////////////////
var EnrollSchedule = function(device, enrollCount=6, callback=((err=null, step=0, state=0, data=null)=>{}), timeout = 60 * 1000) {
    this.step = 0;
    this.enrollCount = enrollCount;
    this.callback = callback;
    this.device = device;
    this.connection = null;
    this.timeout = timeout;
    this.timeoutFlag = 0;
    this.responseTime = 1000;
    this.responseTimeout = 0;
    this.responseCallback = null;
    this.canceled = false;
    
}
const STATE_WAIT_FINGER_DOWN = 1;
const STATE_WAIT_FINGER_LEAVE = 2;
const STATE_FINGER_DOWN = 3;
const STATE_FINGER_LEAVE = 4;
const STATE_EXTRACT_TEMPLATE = 5;
const STATE_DOWNLOAD_TEMPLATE = 6;
const STATE_EXTRACT_TEMPLATE_FAIL = 100;
const STATE_EXTRACT_TEMPLATE_DIRTY = 101;
const STATE_EXTRACT_TEMPLATE_POINTS_FEW = 102;
const STATE_EXTRACT_TEMPLATE_MERGE_FAIL = 103;


const ErrorReceiveDataErr         = 1;
const ErrorEnrollTimeout          = 2;
const ErrorDeviceNotFound         = 3;
const ErrorEmptyFail              = 4;

function printError(err) {
    logln( "enroll err with code: " + err);
}


EnrollSchedule.prototype.start = async function() {
    
    this.step = 0;
    this.canceled = false;
    try {
        await this._connect();
        if(this.canceled) { return this._disConnect(); }

        var ret = await this._sendAndWaitRecvCmd(0x0d);
        if (ret == 0x11) {
            throw ErrorEmptyFail;
        }

        while(this.step < this.enrollCount) {
            this.step += 1;
            ret = await this._enrollOne(this.step);

            if (ret) {
                let stateErr = STATE_EXTRACT_TEMPLATE_FAIL;
                if(ret == 0x06) {
                    stateErr = STATE_EXTRACT_TEMPLATE_DIRTY;
                }else if (ret == 0x07) {
                    stateErr = STATE_EXTRACT_TEMPLATE_POINTS_FEW;
                }else if (ret == 0x0a) {
                    stateErr = STATE_EXTRACT_TEMPLATE_MERGE_FAIL;
                }
                this.callback(null, this.step, stateErr, null);
                this.step -= 1;
            }
            if(this.canceled) { return this._disConnect(); }
        }
        logln("receive tempalte");

        this.callback(null, this.step, STATE_DOWNLOAD_TEMPLATE, null);
        
        var ret = await this._mergeTemplate();
        if(this.canceled) { return this._disConnect(); }
        var recvBuffer = await this._receiveTemplate();
        if(this.canceled) { return this._disConnect(); }
        this.callback(null, this.step, 0, recvBuffer);

    }catch(e) {
        this.callback(e, this.step, 0, null);
    }
    this._disConnect();
}

EnrollSchedule.prototype._mergeTemplate = function() {
    return this._sendAndWaitRecvCmd(0x05);
}
EnrollSchedule.prototype._receiveTemplate = function() {
    
    return new Promise((resolve, reject) => {
        var that = this;
        var data = Uint8Array.of(0x08, 0x01);
        var packet = new Packet(data, 2);
        var recvDataLen = 4 * 1024 * 1024;
        var recvData = new Uint8Array(recvDataLen);
        var recvDataCursor = 0;
        var resetTimeoutCheck = function() {
            if (that.responseTimeout) {
                clearTimeout(that.responseTimeout);
            }
            that.responseTimeout = setTimeout(() => {
                var dummy = new Packet();
                that.connection.send(dummy);
                that.responseTimeout = setTimeout(() => {
                    reject(ErrorReceiveDataErr);
                }, that.responseTime);
            }, that.responseTime);
        }
        this.responseCallback = (packet) => {
            resetTimeoutCheck();
            if (packet.type == PacketTypeCmdResp) {

            }else if (packet.type == PacketTypeData || packet.type == PacketTypeDataEnd) {
                if (recvDataCursor + packet.dataLen < recvDataLen) {
                    recvData.set(packet.data, recvDataCursor);
                    recvDataCursor += packet.dataLen;
                }else {
                    if (that.responseTimeout) {
                        clearTimeout(that.responseTimeout);
                    }
                    reject("recv buffer full");
                }
            }

            if (packet.type == PacketTypeDataEnd) {
                if (that.responseTimeout) {
                    clearTimeout(that.responseTimeout);
                }
                resolve(recvData.slice(0, recvDataCursor));
            }
        }
    
        this.connection.send(packet);
        resetTimeoutCheck();
    });
    
}

EnrollSchedule.prototype._sendAndWaitRecvCmd = function(cmd) {
    return new Promise((resolve, reject) =>{
        var packet = new Packet();
        packet.setCmd(cmd);
        this._sendAndWaitRecv(packet).then(packet => {
            if (packet.type == PacketTypeCmdResp) {
                resolve(packet.result);
            }
        }).catch(err => {
            reject(err);
        });
    });
}

EnrollSchedule.prototype._enrollOne = async function(step) {

    var down = false;
    var leave = false;
    var isTimeout = false;
    this.timeoutFlag = setTimeout(() => {
        if (!down) {
            isTimeout = true;
        }
    }, this.timeout);
    //wait finger leave
    logln("wait leave")
    this.callback(null, this.step, STATE_WAIT_FINGER_LEAVE, null);
    while  (leave == false && !isTimeout) {
        if(this.canceled) { return; }
        leave = !(await this.captureOne());
    }
    this.callback(null, this.step, STATE_FINGER_LEAVE, null);

    
    if (isTimeout) {
        throw ErrorEnrollTimeout;
    }
    this.callback(null, this.step, STATE_WAIT_FINGER_DOWN, null);
    //wait finger down
    logln("wait down")

    while  (!down && !isTimeout) {
        if(this.canceled) { return; }
        down = await this.captureOne();
    }

    if (isTimeout) {
        throw ErrorEnrollTimeout;
    }
    this.callback(null, this.step, STATE_FINGER_DOWN, null);

    logln("finger down step = " + step);
    if(this.canceled) { return; }
    this.callback(null, this.step, STATE_EXTRACT_TEMPLATE, null);
    var ret = await this.extractOne(step);
    if (ret != 0) {
        logln("extract tempate err " + ret);
        return ret;
    }
    return 0;
}
EnrollSchedule.prototype.extractOne = function(step) {
    return new Promise((resolve, reject) =>{
        var data = Uint8Array.of(0x02, step);
        var packet = new Packet(data, 2);
        this._sendAndWaitRecv(packet).then(packet => {
            if (packet.type == PacketTypeCmdResp) {
                resolve(packet.result);
            }
        }).catch(err => {
            reject(err);
        });
    });
}
EnrollSchedule.prototype.captureOne = function() {
    return new Promise((resolve, reject) => {
        var packet = new Packet();
        packet.setCmd(0x01);
        this._sendAndWaitRecv(packet).then(packet => {
            if (packet.type == PacketTypeCmdResp) {
                resolve(packet.result == 0);
            }
        }).catch(err => {
            reject(err);
        });
    });
}
EnrollSchedule.prototype._sendAndWaitRecv = function(packet) {
    return new Promise((resolve, reject) => {
        var that = this;
        this.responseCallback = (packet) => {
            if (packet.type == PacketTypeCmdResp) {
                if (that.responseTimeout) {
                    clearTimeout(that.responseTimeout);
                    that.responseTimeout = 0;
                }
                if (packet.result == 0x01) {
                    reject(ErrorReceiveDataErr);
                }else {
                    resolve(packet);
                }
            }
        }
        this.connection.send(packet);

        this.responseTimeout = setTimeout(() => {
            that.connection.send(packet);
            this.responseTimeout = setTimeout(() => {
                reject(ErrorReceiveDataErr);
            }, this.responseTime);
        }, this.responseTime);
    });
}


EnrollSchedule.prototype._resolvePacket = function(packet) {
    if (this.responseCallback) {
        this.responseCallback(packet);
    }
}
EnrollSchedule.prototype._connect = function() {
    return new Promise((resolve, reject) => {
        var that = this;
        this.connection = new SerialConnection();
        this.connection.onConnect.addListener(function() {
            logln("device " + that.device.path + " connected");
            resolve();
        });
        this.connection.onReceive.addListener(function(packet) {
            that._resolvePacket(packet);
        });
        
        this.connection.connect(this.device.path, this.device.bitrate);
        setTimeout(() => {
            reject("connect timeout");
        }, 500);
    });
}
EnrollSchedule.prototype._disConnect = function() {
    if (this.connection) {
        this.connection.disconnect();
        this.connection = null;
    }
    if (this.responseTimeout) {
        clearTimeout(this.responseTimeout);
        this.responseTimeout = 0;
    }
    if (this.timeoutFlag) {
        clearTimeout(this.timeoutFlag);
        this.timeoutFlag = 0;
    }
}

EnrollSchedule.prototype.stop = function() {
    this.canceled = true;
}



var enrollSchedule = null;
var tempData = null;
function startEnroll(enrollCount=6, timeout=10*1000, cb) {
    if (!curDevice) {
        logln("device not found");
        cb.call(null, {
            err: ErrorDeviceNotFound
        }, 0, null);
        return;

    }

    enrollSchedule = new EnrollSchedule(curDevice, enrollCount, (err, step, state, data) => {
        if (err) {
            printError(status.err);
        }
        
        if(cb) {
            cb.call(null, {
                err: err,
                state: state,
                step: step,
                data: data
            });
        }
        if (data) {
            tempData = data;
        }
    }, timeout);
    logln("start enroll");
    enrollSchedule.start();
}
function stopEnroll() {
    if (enrollSchedule) {
        enrollSchedule.stop();
        enrollSchedule = null;
    }
}

////////////////////////////////////////////////////////
//test
EnrollSchedule.prototype.sleep = function(time) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve();
        }, time);
    });
}
EnrollSchedule.prototype.downloadTemplate = async function(data) {
    var cmdData = Uint8Array.of(0x09, 0x02);
    var packet = new Packet(cmdData, 2);
    this.connection.send(packet);

    await this.sleep(1000);
    var dataLength = data.length;
    var packetLen = 256;
    var sendCursor = 0;
    var sendLen = 0;
    var sendType = PacketTypeData;
    logln("downloading");
    while (sendCursor < dataLength) {
        sendLen = (dataLength-sendCursor > packetLen) ? packetLen :  (dataLength-sendCursor);
        sendType = (dataLength-sendCursor > packetLen) ? PacketTypeData : PacketTypeDataEnd;
        var sendData = new Uint8Array(data.buffer, sendCursor, sendLen);
        var dataPack = new Packet(sendData, sendLen, sendType);
        this.connection.send(dataPack);
        console.log("send "+ sendLen)
        log('.');
        sendCursor += sendLen;
        await this.sleep(100);
    }
    cmdData = Uint8Array.of(0x06, 0x02, 0x00, 0x03);
    packet = new Packet(cmdData, 4);
    this.connection.send(packet);
    logln('.');
    await this.sleep(500);

}

async function downloadTemplate() {
    if (!curDevice) {
        var err = "device not found";
        logln(err);
        return;
    }
    if (!tempData) {
        var err = "please enroll";
        logln(err);
        return;
    }
    var enroll = new EnrollSchedule(curDevice);
    try {
        await enroll._connect();
        await enroll.downloadTemplate(tempData);
        logln("download complete");
    }catch(err) {
        logln("download err: " + err);
    }
    
    await enroll._disConnect();

}

async function matchTemplate() {
    if (!curDevice) {
        var err = "device not found";
        logln(err);
        return;
    }
    var enroll = new EnrollSchedule(curDevice);
    try {
        await enroll._connect();
        await enroll._enrollOne(1);
        var packData = Uint8Array.of(0x04, 0x01, 0x00, 0x03, 0x00, 0x03);
        var packet = new Packet(packData, 6);
        await new Promise((resolve, reject) =>{
            enroll._sendAndWaitRecv(packet).then(packet => {
                if (packet.type == PacketTypeCmdResp) {
                    if(packet.result) {
                        logln("match fail");
                    }else {
                        logln("match success score " + (packet.data[3] * 256 + packet.data[4]));

                    }
                    resolve();
                }
            }).catch(err => {
                reject("match err: " + err);
            });
        })
        

    }catch(err) {
        logln("download err: " + err);
    }
    
    await enroll._disConnect();
}
////////////////////////////////////////////////////////
////////////////////////////////////////////////////////
function disableAll() {
    document.querySelector("#enroll").disabled = true;
    document.querySelector("#down").disabled = true;
    document.querySelector("#match").disabled = true;
    document.querySelector("#refresh").disabled = true;
    document.querySelector("#export").disabled = true;
    document.querySelector("#import").disabled = true;

}
function enableAll() {
    document.querySelector("#enroll").disabled = false;
    document.querySelector("#down").disabled = false;
    document.querySelector("#match").disabled = false;
    document.querySelector("#refresh").disabled = false;
    document.querySelector("#export").disabled = false;
    document.querySelector("#import").disabled = false;

}
var server = null;
onload = function() {
    document.querySelector('#show-log').checked = showDebugLog;
    
    document.querySelector('#show-log').onchange = function(e) {
        showDebugLog = e.target.checked;
    }
    document.querySelector('#enroll').onclick = function(e) {
        if (e.currentTarget.innerText == "Enroll") {
            e.currentTarget.innerText = "Stop";
            startEnroll(6, 10* 1000, (status) => {
                console.log(status.step);
                if (status.err) {
                    console.log(status.err);
                }
                if (status.err || status.data) {
                    document.querySelector('#enroll').innerText = "Enroll";
                }
                if (status.data) {
                    // console.log(data);
                    // console.log(buf2hex(data.buffer));
                }
            });
        }else {
            e.currentTarget.innerText = "Enroll";
            stopEnroll();
        }
        
    }
    document.querySelector('.msg').style="height:" + (window.innerHeight - 70) + "px";

    chrome.serial.getDevices((devices) => {
        checkDevices(devices);
    });
    document.querySelector("#down").onclick = async function(e) {
        disableAll();
        try {
            await downloadTemplate();
        }catch(err) {
            logln("download err: " + err);
        }
        enableAll();
    }
    document.querySelector("#match").onclick = async function(e) {
        disableAll();
        try {
            await matchTemplate();
        }catch(err) {
            logln("match err: " + err);
        }
        enableAll();
    }

    document.querySelector("#refresh").onclick = function(e) {
        disableAll();
        chrome.serial.getDevices(async function(devices) {
            try {
                await checkDevices(devices);
            }catch (e) {
                console.log(e)
            }
            enableAll();
        });
    }
    document.querySelector("#export").onclick = function(e) {
        if (!tempData) {
            logln("please enroll");
            return;
        }
        let reader = new FileReader();
        reader.onload = function(eve) {
            if (eve.target.readyState == FileReader.DONE)
            {
                let a = document.createElement('a');
                a.download = "mafp_template.bin";
                a.href = this.result;
                a.click();
            }
        }
        reader.readAsDataURL(new Blob([tempData]));
    }

    document.querySelector("#import").onclick = function(e) {
        let fileInput = document.querySelector("#import-file");
        fileInput.value = "";
        fileInput.click();
    }
    document.querySelector("#import-file").onchange = function(e) {
        let files = e.target.files;
        if (files && files.length) {
            let reader = new FileReader();
            reader.onload = async function(ev) {
                if (ev.total == 4096) {
                    tempData = new Uint8Array(this.result);
                    disableAll();
                    try {
                        await downloadTemplate();
                    }catch(err) {
                        logln("download err: " + err);
                    }
                    enableAll();
                }else {
                    logln("invalid file length " + ev.total);
                }
            }
            reader.readAsArrayBuffer(files[0]);
        }
    }

    const port = 9897;
    if (http.Server && http.WebSocketServer) {
        server = new http.Server();
        var wsServer = new http.WebSocketServer(server);
        server.listen(port);
        logln("ws socket server listen at " + port);
        var connectedSocket = null;
        wsServer.addEventListener('request', function(req) {
            if (connectedSocket) {
                req.reject();
                return;
            }
            console.log('Client connected');
            var socket = req.accept();
            connectedSocket = socket;

            socket.addEventListener('message', function(e) {
                var reqData = JSON.parse(e.data);
                if (reqData.cmd == "enrollStart") {
                    startEnroll(reqData.config.enrollCount, 
                        reqData.config.enrollTimeout, 
                        (status) =>{
                        var resp = {
                            err: status.err ? status.err : "",
                            state: status.state ? status.state : 0,
                            step: status.step
                        }
                        if (status.data) {
                            resp.data = Array.from(status.data);
                        }
                        connectedSocket.send(JSON.stringify(resp));
                    });
                }else if (reqData.cmd == "enrollCancel") {
                    stopEnroll();
                }
            });
        
            socket.addEventListener('close', function() {
                connectedSocket = null;
                stopEnroll();
                console.log('Client disconnected');
                if (chrome.runtime.lastError != undefined) {
                    console.log(chrome.runtime.lastError.message);
                }
            });
            return true;
          });
    }
};


onresize = function(e) {
    document.querySelector('.msg').style="height:" + (e.currentTarget.innerHeight - 70) + "px";
    document.querySelector('#msg_end').scrollIntoView();

}