//----------------------------------------- mkterminal
/*
small program for sending apa packets along a serial line
*/

// check that we have portname
if (process.argv.length < 3) {
    logAdvice()
    process.exit(-1)
}

if (process.argv[2] == '-h' || process.argv[2] == 'help') {
    logAdvice()
    process.exit(-1)
}

var SerialPort = require('serialport');

var ByteLengthParser = SerialPort.parsers.ByteLength;

var port = new SerialPort(process.argv[2], {
    baudRate: 250000,
/*    dataBits: 8,
    parity: 'none',
    flowControl: false,
    */
});

//----------------------------------------- readline
/*
key input from terminal
*/

const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

rl.on('line', parseLineIn);

function parseLineIn(data) {
    /*
    packet like "packet port,port,etc,ptr,byte,byte,byte..."
    does like "len,int,int,int,254?,byte,byte,byte,etc"
    next do key:type:values
    apa_end_addr_delimiter 255
    apa_addr_pointer 254
    apa_addr_flood 253
    key_position_float 127
    key_speed_float 128
    key_position_steps 129
    key_speed_steps 130
    */
    if (data.includes('packet')) {
        var argstring = data.split(' ')[1]; // everything following 'packet '
        var args = argstring.split(',');
        var packet = new Array();
        var i = 0; // args
        var u = 0; // packet
        while (i < args.length) {
            switch (args[i]) {
                case 'ptr':
                    packet[u] = 254;
                    i++;
                    u++;
                    break;

                case 'end':
                    packet[u] = 255;
                    i++;
                    u++;
                    break;

                case 'test':
                    packet[u] = 127;
                    i++;
                    u++;
                    break;

                case 'reset':
                    packet[u] = 128;
                    i++;
                    u++;
                    break;

                case 'setPos':
                    packet[u] = 129
                    var newPos = parseInt(args[i + 1])
                    packet[u + 1] = (newPos >> 8) & 255
                    packet[u + 2] = newPos & 255
                    i += 2
                    u += 3
                    break

                case 'getPos':
                	packet[u] = 130
                	i ++
                	u++
                	break

                case 'block':
                    packet[u] = 131;
                    // a linked acceleration planned segment
                    // we'll be going betwee float-space for steps in the higher levels, so
                    var steps = parseInt(args[i + 1])
                    packet = packet.concat(pack32(steps))
                    // but accel and speeds need to be in floats
                    var entry = parseInt(args[i + 2])
                    packet = packet.concat(pack32(entry))
                    // pack 64 bit float to 32 bit?
                    var accel = parseInt(args[i + 3])
                    packet = packet.concat(pack32(accel))

                    var accelLength = parseInt(args[i + 4])
                    packet = packet.concat(pack32(accelLength))

                    var deccelLength = parseInt(args[i + 5])
                    packet = packet.concat(pack32(deccelLength))

                    i += 6
                    u += 21
                    break;

                case 'wait':
                    packet[u] = 132;
                    // a linked acceleration planned segment
                    // this one flagged as a wait period via the delimiter
                    // we'll be going betwee float-space for steps in the higher levels, so
                    var steps = parseInt(args[i + 1])
                    packet = packet.concat(pack32(steps))
                    // but accel and speeds need to be in floats
                    var entry = parseInt(args[i + 2])
                    packet = packet.concat(pack32(entry))
                    // pack 64 bit float to 32 bit?
                    var accel = parseInt(args[i + 3])
                    packet = packet.concat(pack32(accel))

                    var accelLength = parseInt(args[i + 4])
                    packet = packet.concat(pack32(accelLength))

                    var deccelLength = parseInt(args[i + 5])
                    packet = packet.concat(pack32(deccelLength))

                    i += 6
                    u += 21
                    break;

                case 'speed':
                    packet[u] = 141;
                    var speed = parseInt(args[i +1])
                    packet = packet.concat(pack32(speed))
                    var duty = parseInt(args[i + 2])
                    packet = packet.concat(pack32(duty))
                    i += 3;
                    u += 9;
                    break;

                default:
                    packet[u] = parseInt(args[i]);
                    u++;
                    i++;
                    break;
            }
        }
        packet.unshift(packet.length + 1); // push the length into header
        data_out(packet);
        // now through bytes
    } else if (data.includes('dummy packet')) {
        var packet = Buffer.from([12, 3, 1, 254, 4, 255, 1, 2, 3, 4, 5, 6]);
        data_out(packet);
    } else if (data.includes('help')) {
        logAdvice();
    } else if (data.includes('exit')) {
        process.exit(0);
    } else {
        data_out(data);
    }
}

function pack32(val) {
    var pack = new Array();
    pack[0] = (val >> 24) & 255;
    pack[1] = (val >> 16) & 255;
    pack[2] = (val >> 8) & 255;
    pack[3] = val & 255;

    return pack;
}

function packFloat(val) {
    var pack; // the array of bytes
    // as a view into a typed array
    var view = new DataView(new ArrayBuffer(4));
    view.setFloat32(0, val);

    pack = Array.apply(null, { length: 4 }).map((_, i) => view.getUint8(i))
    console.log('packed', val, 'as', pack)

    return pack
}

function logAdvice() {
    console.log('use serialport-list to find ports')
    console.log("command line: node serialterminal portname");
    console.log('route,ptr,end,command,args')
    console.log('test: sends byte 128 to network test')
    console.log('steps: {steps uint32_t, speed steps/s float, dir uint8_t}')
    console.log('block: steps, entry, accel, accelLength, deccelLength')
}

//----------------------------------------- parsing
/*
does the business
*/

var parser = port.pipe(new ByteLengthParser({ length: 1 }));

parser.on('data', data_in);

function data_in(data) {
    console.log(data[0]);
}

function data_out(data) {
    console.log('sent: ', data);
    port.write(data, function(err) {
        if (err) {
            return console.log('port error on write: ', err.message);
        }
    });
}

port.on('open', function(err) {
    console.log('port open');
});

port.on('error', function(err) {
    console.log('port error: ', err.message);
});