import _ from 'lodash';
import pubsub from 'pubsub-js';
import socket from './socket';
import log from './log';

class CNCController {
    port = '';
    callbacks = {
        'serialport:list': [],
        'serialport:open': [],
        'serialport:close': [],
        'serialport:error': [],
        'serialport:read': [],
        'serialport:write': [],
        'grbl:status': [],
        'grbl:parserstate': [],
        'gcode:statuschange': []
    };

    constructor() {
        pubsub.subscribe('port', (msg, port) => {
            this.port = port || this.port;
        });

        Object.keys(this.callbacks).forEach((eventName) => {
            socket.on(eventName, (...args) => {
                this.callbacks[eventName].forEach((callback) => {
                    callback.apply(callback, args);
                });
            });
        });
    }
    on(eventName, callback) {
        let callbacks = this.callbacks[eventName];
        if (!callbacks) {
            log.error('Undefined event name:', eventName);
            return;
        }
        if (_.isFunction(callback)) {
            callbacks.push(callback);
        }
    }
    off(eventName, callback) {
        let callbacks = this.callbacks[eventName];
        if (!callbacks) {
            log.error('Undefined event name:', eventName);
            return;
        }
        if (_.isFunction(callback)) {
            callbacks.splice(callbacks.indexOf(callback), 1);
        }
    }
    openPort(port, baudrate) {
        socket.emit('open', port, baudrate);
    }
    closePort(port) {
        socket.emit('close', port);
    }
    listAllPorts() {
        socket.emit('list');
    }
    // @param {string} cmd The command string
    // @example Example Usage
    // - Load G-code
    //   controller.command('load', name, gcode, callback)
    // - Unload G-code
    //   controller.command('unload')
    // - Start sending G-code
    //   controller.command('start')
    // - Stop sending G-code
    //   controller.command('stop')
    // - Pause
    //   controller.command('pause')
    // - Resume
    //   controller.command('resume')
    // - Feed Hold
    //   controller.command('feedhold')
    // - Cycle Start
    //   controller.command('cyclestart')
    // - Reset
    //   controller.command('reset')
    // - Homing
    //   controller.command('homing')
    // - Unlock
    //   controller.command('unlock')
    command(cmd, ...args) {
        const { port } = this;
        if (!port) {
            return;
        }
        socket.emit.apply(socket, ['command', port, cmd].concat(args));
    }
    // @param {string} data The data to write
    write(data) {
        const { port } = this;
        if (!port) {
            return;
        }
        socket.emit('write', port, data);
    }
    // @param {string} data The data to write
    writeln(data) {
        data = ('' + data).trim() + '\n';
        this.write(data);
    }
}

const controller = new CNCController();

export default controller;

@@ -4,22 +4,30 @@
 ort 
-_
+pubsub
  from '
-lodash
+pubsub-js
 ';%0Ai
@@ -32,37 +32,60 @@
 %0Aimport 
-pubsub from 'pubsub-j
+%7B WORKFLOW_STATE_UNKNOWN %7D from '../constant
 s';%0Aimpo
@@ -395,18 +395,25 @@
   'g
-rbl
+code
 :status
+change
 ': %5B
@@ -433,14 +433,8 @@
 rbl:
-parser
 stat
@@ -454,38 +454,183 @@
    '
-gcode:statuschange': %5B%5D%0A    %7D;
+tinyg:state': %5B%5D%0A    %7D;%0A    controller = %7B%0A        type: 'Grbl',%0A        state: %7B%7D // FIXME: Grbl or TinyG defaults%0A    %7D;%0A    workflowState = WORKFLOW_STATE_UNKNOWN; // FIXME
 %0A%0A  
@@ -858,24 +858,371 @@
 .args) =%3E %7B%0A
+                if (eventName === 'grbl:state') %7B%0A                    this.controller.type = 'Grbl';%0A                    this.controller.state = args%5B0%5D;%0A                %7D%0A                if (eventName === 'tinyg:state') %7B%0A                    this.controller.type = 'TinyG';%0A                    this.controller.state = args%5B0%5D;%0A                %7D%0A%0A
             
@@ -1589,38 +1589,46 @@
     if (
-_.isFunction(callback)
+typeof callback === 'function'
 ) %7B%0A    
@@ -1890,30 +1890,38 @@
 if (
-_.isFunction(callback)
+typeof callback === 'function'
 ) %7B%0A

Rework CNC controller