const progress = require('cli-progress');
const { spawn } = require('child_process');
const events = require('events');
const emitter = new events.EventEmitter();
const fs = require('fs');
const path = require('path');
const inquirer = require('inquirer');

const posFolder = 'C:/PointOfSales';
const posBackendFolder = 'C:/PointOfSales/POSBackend';

console.log('With arrow keys select peripheral devices that POS will be using and press "Enter" to select.\n');

// LIST OF ALL SUPPORTED PERIPHERALS (device, name, devicename, ids [UDvid, UDpid, HWvid, HWpid], in use, changetimestamp, status)
var peripherals = {
    "camera":           { "device": "camera",           "name": "", "devicename": "", "ids": [], "using": true, "changetimestamp": "", "status": "disconnected" }, // Camera
    "cardreader":       { "device": "cardreader",       "name": "", "devicename": "", "ids": [], "using": true, "changetimestamp": "", "status": "disconnected" }, // Card reader
    "receiptprinter":   { "device": "receiptprinter",   "name": "", "devicename": "", "ids": [], "using": true, "changetimestamp": "", "status": "disconnected" }, // Receipt printer
    "codescanner":      { "device": "codescanner",      "name": "", "devicename": "", "ids": [], "using": true, "changetimestamp": "", "status": "disconnected" }, // Code scanner
    "documentscanner":  { "device": "documentscanner",  "name": "", "devicename": "", "ids": [], "using": true, "changetimestamp": "", "status": "disconnected" }, // Document scanner
    "cardprinter":      { "device": "cardprinter",      "name": "", "devicename": "", "ids": [], "using": true, "changetimestamp": "", "status": "disconnected" }, // Card printer
    "customerdisplay":  { "device": "customerdisplay",  "name": "", "devicename": "", "ids": [], "using": true, "changetimestamp": "", "status": "disconnected" }, // Customer display
    "edcterminal":      { "device": "edcterminal",      "name": "", "devicename": "", "ids": [], "using": true, "changetimestamp": "", "status": "disconnected" }, // EDC terminal
    "luggageprinter":   { "device": "luggageprinter",   "name": "", "devicename": "", "ids": [], "using": true, "changetimestamp": "", "status": "disconnected" }  // Luggage printer
};

// PROMPT FOR PERIPHERALS LIST
inquirer.prompt([
    {
        type: 'list',
        name: 'camera',
        message: 'Please select which Camera will be used:',
        choices: [ 'None', 'Logitech HD Pro Webcam C920', 'Logitech C920 HD Pro Webcam', 'Robaxo RC100', 'Logitech HD Pro Webcam C920' ],
        default: 'None'
    },
    {
        type: 'list',
        name: 'cardReader',
        message: 'Please select which Card reader will be used:',
        choices: [ 'None', 'uTrust CLOUD 3700 F Contactless Reader', 'Omnikey 5022 build in card reader', 'Identiv uTrust 4711 F CL + SAM Reader', 'Elatec TWN4 Legic NFC' ],
        default: 'None'
    },
    {
        type: 'list',
        name: 'receiptPrinter',
        message: 'Please select which Receipt printer will be used:',
        choices: [ 'E-PoS TEP-220MC', 'E-PoS TEP-300', 'WINTEC WIN91PT', 'Zebra GK420d', 'Epson TM-T20III', 'WINTEC WIN91PT v7' ],
        default: 'E-PoS TEP-220MC'
    },
    {
        type: 'list',
        name: 'codeScanner',
        message: 'Please select which Code scanner will be used:',
        choices: [ 'None', 'Honeywell Genesis 7580g', 'Zebra DS2278', 'Honeywell Genesis 7980', 'Honeywell HF680' ],
        default: 'None'
    },
    {
        type: 'list',
        name: 'documentScanner',
        message: 'Please select which Document scanner will be used:',
        choices: [ 'None', 'HP DeskJet 2600', 'Canon LiDE 300', 'HP ScanJet Pro 2500 f1' ],
        default: 'None'
    },
    {
        type: 'list',
        name: 'cardPrinter',
        message: 'Please select which Card printer will be used:',
        choices: [ 'None', 'Zebra ZC300', 'Zebra ZXP Series 7', 'Zebra ZC350' ],
        default: 'None'
    },
    {
        type: 'list',
        name: 'customerDisplay',
        message: 'Please select which Customer display will be used:',
        choices: [ 'None', 'POS build in customer display CD220', 'POS build in customer display DL097', 'Epson DM-D110' ],
        default: 'None'
    },
    {
        type: 'list',
        name: 'edcTerminal',
        message: 'Please select which EDC Terminal will be used:',
        choices: [ 'None', 'Newland N910 Pro' ],
        default: 'None'
    },
    {
        type: 'list',
        name: 'luggagePrinter',
        message: 'Please select which Luggage printer will be used:',
        choices: [ 'None', 'WINTEC WIN91PT', 'Zebra ZD220' ],
        default: 'None'
    }
])
.then(function (answers) {
    var pendingInstall = [];
    // Camera
    peripherals.camera.name = answers.camera;
    peripherals.camera.devicename = (answers.camera).split(' ')[0];
    switch (answers.camera) {
        case 'None':
            peripherals.camera.using = false;
        break;
        case 'Logitech HD Pro Webcam C920':
            peripherals.camera.ids = [1133, 2093, "0x046D", "0x082D"];          // Logitech HD Pro Webcam C920
        break;
        case 'Logitech C920 HD Pro Webcam':
            peripherals.camera.ids = [1133, 2194, "0x046D", "0x0892"];          // Logitech C920 HD Pro Webcam
        break;
        case 'Logitech HD Pro Webcam C920':
            peripherals.camera.ids = [1133, 2277, "0x046D", "0x08E5"];          // Logitech HD Pro Webcam C920
        break;
        case 'Robaxo RC100':
            peripherals.camera.ids = [4644, 10789, "0x1224", "0x2A25"];         // Robaxo RC100
        break;
    }

    // Card reader
    peripherals.cardreader.name = answers.cardReader;
    peripherals.cardreader.devicename = (answers.cardReader).split(' ')[0];
    switch (answers.cardReader) {
        case 'None':
            peripherals.cardreader.using = false;
        break;
        case 'uTrust CLOUD 3700 F Contactless Reader':
            peripherals.cardreader.ids = [1254, 22416, "0x04E6", "0x5790"];     // uTrust CLOUD 3700 F Contactless Reader
        break;
        case 'Omnikey 5022 build in card reader':
            peripherals.cardreader.ids = [1899, 20514, "0x076B", "0x5022"];     // Omnikey 5022 build in
        break;
        case 'Identiv uTrust 4711 F CL + SAM Reader':
            peripherals.cardreader.ids = [1254, 22309, "0x04E6", "0x5725"];     // Identiv uTrust 4711 F CL + SAM Reader
        break;
        case 'Elatec TWN4 Legic NFC':
            peripherals.cardreader.ids = [2520, 1040, "0x09D8", "0x0410"];      // Elatec TWN4 Legic NFC
        break;
    }

    // Receipt printer
    peripherals.receiptprinter.name = answers.receiptPrinter;
    peripherals.receiptprinter.devicename = (answers.receiptPrinter).split(' ')[0];
    switch (answers.receiptPrinter) {
        case 'E-PoS TEP-220MC':
            peripherals.receiptprinter.ids = [1137, 85, "0x0471", "0x0055"];    // E-PoS TEP-220MC
        break;
        case 'E-PoS TEP-300':
            peripherals.receiptprinter.ids = [4070, 33054, "0x0FE6", "0x811E"]; // E-PoS TEP-300
        break;
        case 'WINTEC WIN91PT':
            peripherals.receiptprinter.ids = [8137, 8214, "0x1FC9", "0x2016"];  // WINTEC WIN91PT
        break;
        case 'Zebra GK420d':
            peripherals.receiptprinter.ids = [2655, 128, "0x0A5F", "0x0080"];   // Zebra GK420d
            peripherals.receiptprinter.devicename = 'ZDesigner GK420d';
            // install zebra printing libraries ( npm install qz-tray@2.2.3 jsrsasign@11.1.0 pngjs@7.0.0 zpl-image@0.2.0 )
            pendingInstall.push('qz-tray@2.2.3', 'jsrsasign@11.1.0'); // , 'pngjs@7.0.0', 'zpl-image@0.2.0'
        break;
        case 'Epson TM-T20III':
            peripherals.receiptprinter.ids = [1208, 3624, "0x04B8", "0x0E28"];  // Epson TM-T20III
        break;
        case 'WINTEC WIN91PT v7':
            peripherals.receiptprinter.ids = [1155, 22339, "0x0483", "0x5743"]; // WINTEC WIN91PT v7 HAFIL
        break;
    }

    // Barcode scanner
    peripherals.codescanner.name = answers.codeScanner;
    peripherals.codescanner.devicename = (answers.codeScanner).split(' ')[0];
    switch (answers.codeScanner) {
        case 'None':
            peripherals.codescanner.using = false;
        break;
        case 'Honeywell Genesis 7580g':
            peripherals.codescanner.ids = [3118, 3041, "0x0C2E", "0x0BE1"];     // Honeywell Genesis 7580g
        break;
        case 'Zebra DS2278':
            peripherals.codescanner.ids = [1504, 4608, "0x05E0", "0x1200"];     // Zebra DS2278
        break;
        case 'Honeywell Genesis 7980':
            peripherals.codescanner.ids = [3118, 3713, "0x0C2E", "0x0E81"];     // Honeywell Genesis 7980
        break;
        case 'Honeywell HF680':
            peripherals.codescanner.ids = [3118, 4225, "0x0C2E", "0x1081"];     // Honeywell HF680
        break;
    }

    // Document scanner
    peripherals.documentscanner.name = answers.documentScanner;
    peripherals.documentscanner.devicename = (answers.documentScanner).split(' ')[0];
    switch (answers.documentScanner) {
        case 'None':
            peripherals.documentscanner.using = false;
        break;
        case 'HP DeskJet 2600':
            peripherals.documentscanner.ids = [1008, 83, "0x03F0", "0x0053"];       // HP DeskJet 2600
            peripherals.documentscanner.devicename = 'WIA-HP DeskJet 2600 (USB)';
        break;
        case 'Canon LiDE 300':
            peripherals.documentscanner.ids = [1193, 6419, "0x04A9", "0x1913"];     // Canon LiDE 300
            peripherals.documentscanner.devicename = 'WIA-CanoScan LiDE 300';
        break;
        case 'HP ScanJet Pro 2500 f1':
            peripherals.documentscanner.ids = [1008, 24581, "0x03F0", "0x6005"];    // HP ScanJet Pro 2500 f1
            peripherals.documentscanner.devicename = 'WIA-HP ScanJet Pro 2500 f1';
        break;
    }

    // Card printer
    peripherals.cardprinter.name = answers.cardPrinter;
    peripherals.cardprinter.devicename = (answers.cardPrinter).split(' ')[0];
    switch (answers.cardPrinter) {
        case 'None':
            peripherals.cardprinter.using = false;
        break;
        case 'Zebra ZC300':
            peripherals.cardprinter.ids = [2655, 328, "0x0A5F", "0x0148"];      // Zebra ZC300
            peripherals.cardprinter.devicename = 'Zebra ZC300 USB Card Printer';
            // install zebra printing and canvas libraries ( npm install qz-tray@2.2.3 jsrsasign@11.1.0 fabric@5.3.0 )
            pendingInstall.push('qz-tray@2.2.3', 'jsrsasign@11.1.0', 'fabric@5.3.0');
        break;
        case 'Zebra ZXP Series 7':
            peripherals.cardprinter.ids = [2655, 167, "0x0A5F", "0x00A7"];      // Zebra ZXP Series 7
            peripherals.cardprinter.devicename = 'Zebra ZXP Series 7 USB Card Printer';
            // install zebra printing and canvas libraries ( npm install qz-tray@2.2.3 jsrsasign@11.1.0 fabric@5.3.0 )
            pendingInstall.push('qz-tray@2.2.3', 'jsrsasign@11.1.0', 'fabric@5.3.0');
        break;
        case 'Zebra ZC350':
            peripherals.cardprinter.ids = [2655, 329, "0x0A5F", "0x0149"];      // Zebra ZC350
            peripherals.cardprinter.devicename = 'Zebra ZC350 USB Card Printer';
            // install zebra printing and canvas libraries ( npm install qz-tray@2.2.3 jsrsasign@11.1.0 fabric@5.3.0 )
            pendingInstall.push('qz-tray@2.2.3', 'jsrsasign@11.1.0', 'fabric@5.3.0');
        break;
    }

    // Customer display
    peripherals.customerdisplay.name = answers.customerDisplay;
    peripherals.customerdisplay.devicename = (answers.customerDisplay).split(' ')[0];
    switch (answers.customerDisplay) {
        case 'None':
            peripherals.customerdisplay.using = false;
        break;
        case 'POS build in customer display CD220':
            peripherals.customerdisplay.ids = [0, 0, "0x0000", "0x0000"];       // POS build in CD220 (20 columns x 2 lines Dot Matrix)
            peripherals.customerdisplay.devicename = 'COM6';
        break;
        case 'POS build in customer display DL097':
            peripherals.customerdisplay.ids = [0, 0, "0x0000", "0x0000"];       // POS build in DL097 (9.7" - 1024 x 768 LCD)
            peripherals.customerdisplay.devicename = 'VGA2662';
        break;
        case 'Epson DM-D110':
            peripherals.customerdisplay.ids = [4616, 1920, "0x0780", "0x0780"]; // Epson DM-D110 (20 columns x 2 lines Dot Matrix)
            peripherals.customerdisplay.devicename = 'COM3';
        break;
    }

    // EDC terminal
    peripherals.edcterminal.name = answers.edcTerminal;
    peripherals.edcterminal.devicename = (answers.edcTerminal).split(' ')[0];
    switch (answers.edcTerminal) {
        case 'None':
            peripherals.edcterminal.using = false;
        break;
        case 'Newland N910 Pro':
            peripherals.edcterminal.ids = [7694, 36907, "0x1E0E", "0x902B"];    // Newland N910 Pro
            peripherals.edcterminal.devicename = 'COM15';
        break;
    }

    // Luggage printer
    peripherals.luggageprinter.name = answers.luggagePrinter;
    peripherals.luggageprinter.devicename = (answers.luggagePrinter).split(' ')[0];
    switch (answers.luggagePrinter) {
        case 'None':
            peripherals.luggageprinter.using = false;
        break;
        case 'WINTEC WIN91PT':
            peripherals.luggageprinter.ids = [8137, 8214, "0x1FC9", "0x2016"];  // WINTEC WIN91PT
        break;
        case 'Zebra ZD220':
            peripherals.luggageprinter.ids = [2655, 356, "0x0A5F", "0x0164"];   // Zebra ZD220
            peripherals.luggageprinter.devicename = 'Zebra ZTC ZD220 ZPL';
            // install zebra printing and canvas libraries ( npm install qz-tray@2.2.3 jsrsasign@11.1.0 fabric@5.3.0 )
            pendingInstall.push('qz-tray@2.2.3', 'jsrsasign@11.1.0', 'fabric@5.3.0');
        break;
    }

    // GENERATE PERIPHERALS CONFIG FILE
    fs.writeFile(path.join(posBackendFolder, 'configs', 'peripherals.json'), JSON.stringify(peripherals, null, 4), function (err) {
        if (err) { return console.log(err); }
        console.log('Peripherals configuration file generated.');
        emitter.emit('config-done');
    });

    // INSTALL NEDED LIBRARIES
    emitter.on('config-done', () => {
        if (pendingInstall.length > 0) {
            console.log('\nAll necessary libraries are being installed, please wait...\n');

            const bar = new progress.SingleBar({format: '{bar} {percentage}% || Duration: {duration}s || ETA: {eta}s', barCompleteChar: '\u2588', barIncompleteChar: '\u2591', hideCursor: true}, progress.Presets.shades_classic);
            bar.start(pendingInstall.length, 0);

            // install peripherals libraries
            pendingInstall.forEach(async function (install) {
                const peripheralsLibraries = await spawn('npm.cmd', ['install', install], {cwd: posBackendFolder});
                peripheralsLibraries.on('close', (code) => {
                    if (parseInt(code) !== 0) { console.log(install, `exited with code ${code}`); }
                    bar.increment(1);
                    pendingInstall.splice(pendingInstall.indexOf(install), 1);
                    if (pendingInstall.length == 0) {
                        bar.stop();
                        emitter.emit('pendingInstall-done');
                    }
                });
            });
        } else {
            emitter.emit('pendingInstall-done');
        }
    });

    // LINK NODE WINDOWS
    emitter.on('pendingInstall-done', () => {
        // link node-windows ( npm link node-windows )
        const linkNodeWindows = spawn('npm.cmd', ['link', 'node-windows'], {cwd: posBackendFolder});
        linkNodeWindows.on('close', (code) => {
            if (parseInt(code) !== 0) { console.log(`linkNodeWindows exited with code ${code}`); }
            emitter.emit('linkNodeWindows-done');
        });
    });

    // RESTART LIT POS SOFTWARE BACKEND
    emitter.on('linkNodeWindows-done', () => {
        // restart application ( npm run service )
        const nwLitPosSoftware = spawn('npm.cmd', ['run', 'service'], {cwd: posBackendFolder});
        nwLitPosSoftware.on('close', (code) => {
            if (parseInt(code) !== 0) { console.log(`nwLitPosSoftware exited with code ${code}`); }
            emitter.emit('nwLitPosSoftware-done');
        });
    });

    emitter.on('nwLitPosSoftware-done', () => {
        console.log('\nSetup is completed.');
    });
});
