const electron = require('electron');
const url = require ('url');
const path = require('path');
const ipcRenderer = electron.ipcMain;


const {app, BrowserWindow, Menu} = electron;

let mainWindow, secondWindow;

// Listen for app to be ready
app.on('ready', function() {
  console.log("READY");
    //create new window
    mainWindow = new BrowserWindow({
      webPreferences: {
        nodeIntegration: true
      }
    });
    //Load html file into window
    mainWindow.loadURL(url.format({
        pathname: path.join(__dirname, 'mainWindow.html'),
        protocol:'file:',
        slashes: true
    }));

    mainWindow.setFullScreen(true);
    //Build menu from template
    //const mainMenu = null;//Menu.buildFromTemplate(mainMenuTemplate);
    //Insert menu
    Menu.setApplicationMenu(null);
    mainWindow.webContents.openDevTools();

    //create new window
    /*secondWindow = new BrowserWindow({
      x: 1370,
      y: 0,
      webPreferences: {
        nodeIntegration: true
      }
    });
    //Load html file into window
    secondWindow.loadURL(url.format({
        pathname: path.join(__dirname, 'secondWindow.html'),
        protocol:'file:',
        slashes: true
    }));

    secondWindow.setFullScreen(true);
    //Build menu from template
    //const mainMenu = null;//Menu.buildFromTemplate(mainMenuTemplate);
    //Insert menu
    Menu.setApplicationMenu(null);*/
    //secondWindow.webContents.openDevTools();
});

//Create menu template

const mainMenuTemplate = [
    //{
        //label:'File'
    //}
];

const serialport = require('serialport');
var portlist = [];            // = new serialport({ baudRate: 19200 });
var gpsport = null;           // = new serialport({ baudRate: 19200 });
var mainport = null;          // = new serialport({ baudRate: 19200 });
var bufferlist = [];          //data buffer

/*serialport.list((err, ports) => {
  for (var i = 0; i < ports.length; i++) {
    //console.log(ports[i].comName);
    if (ports[i].comName != "COM1" && ports[i].comName != "COM3") {
      if (ports[i].comName == "COM11") { //GPS port
        gpsport = new serialport(ports[i].comName, { baudRate: 38400 });
      } else if (ports[i].comName == "COM7") {//CAN port
        portlist[portlist.length] = new serialport(ports[i].comName, { baudRate: 250000 });
        bufferlist[bufferlist.length] = [0];
      } else if (ports[i].comName == "COM23") {//Main port
        portlist[portlist.length] = new serialport(ports[i].comName, { baudRate: 9600 });
        bufferlist[bufferlist.length] = [0];
        mainport = portlist[portlist.length - 1];
      } else {
        portlist[portlist.length] = new serialport(ports[i].comName, { baudRate: 9600 });
        bufferlist[bufferlist.length] = [0];
      }
    }
  }
  if (portlist.length >= 1) {
    portlist[0].on('data', function(data) {
      filterCOMData(data, 0);
    });
  }
  if (portlist.length >= 2) {
    portlist[1].on('data', function(data) {
      filterCOMData(data, 1);
    });
  }
  if (portlist.length >= 3) {
    portlist[2].on('data', function(data) {
      filterCOMData(data, 2);
    });
  }
});*/

// 0x3A,0xA3,Type,Size,...,0x4A,0xA4 - Size inclued last two verify bits
var filterCOMData = function(data, buffer, idx)
{
  for (var i = 0; i < data.length; i++) {
    buffer.push(data[i]);
  }

  if (idx != 2) {

    while (buffer.length > 1 && (buffer[0] != 0x3A || buffer[1] != 0xA3)) {
      buffer.shift();
    }

    if (buffer.length > 1) {
      //Valid data
      var length = buffer[3];
      while (buffer.length >= (length + 5)) {
        if ((buffer[length + 3] == 0x0A) && (buffer[length + 4] == 0x0D)) {
          CheckDataType(idx, buffer[2]);
          mainWindow.webContents.send('data-message', buffer);
        }
        for (var i = 0; i < (length + 5); i++) {
          buffer.shift();
        }
      }
    }
  } else {
    while (buffer.length > 1 && (buffer[0] != 0x23)) {
      buffer.shift();
    }

    if (buffer.length > 1) {
      //Valid data
      var length = 4;
      if (buffer[1] == 0x9F) length = 19;
      if (buffer[1] == 0x97) length = 11;
      if (buffer[1] == 0x8A) length = 3;
      while (buffer.length >= length) {
        CheckDataType(idx, buffer[2]);
        mainWindow.webContents.send('rain-message', buffer);
        for (var i = 0; i < length; i++) {
          buffer.shift();
        }
      }
    }
  }
}


const { ipcMain } = require('electron');

ipcMain.on('gps-message', (event, arg) => {
  //console.log(arg);// prints "ping"
  //console.log(portGPS);
  if (deviceList[4].port != null) {
    deviceList[4].port.write(arg);
  }
});

ipcMain.on('rain-message', (event, arg) => {
  //console.log(arg);// prints "ping"
  //console.log(portGPS);
  if (deviceList[2].port != null) {
    deviceList[2].port.write(arg);
  }
});

ipcMain.on('rain-export-message', (event, arg) => {
  var fs = require('fs');

  fs.writeFile('rain_meter_export.txt', arg, function (err) {
    if (err) throw err;
    console.log('Saved!');
  });
});

ipcMain.on('can-message', (event, arg) => {
  //console.log(arg.length);// prints "ping"

  if (deviceList[5].port != null) {
    var data = [];
    for (var i = 0; i < arg.length; i++) data[i] = arg.charCodeAt(i);
    //console.log(data);
    deviceList[5].port.write(arg);
  }
});

ipcMain.on('main-message', (event, arg) => {
  //console.log(arg);// prints "ping"
  //console.log(portGPS);
  if (deviceList[3].port != null) {
    deviceList[3].port.write(arg);
  }
});

ipcMain.on('main-unit-message', (event, arg) => {
  if (deviceList[3].port != null) {
    deviceList[3].port.write(arg);
  }
});

var porthistory = [];
for (var i = 0; i < 32; i++) {
  porthistory[i] = [0,0,0,0,0,0];
}

//Main program
setInterval(function() {

  serialport.list((err, ports) => {

    //For each port
    for (var i = 0; i < ports.length; i++) {
      if ((ports[i].comName != 'COM1') && (ports[i].comName != 'COM3')) {

        //For each port
        var idx = comPortInUse(ports[i].comName);   //Check if comport is being used

        //IDX
        if (idx != -1) {
          if (deviceList[idx].reply_received == 0) {
            deviceList[idx].reply_counter--;
            if (deviceList[idx].reply_counter <= 0) {
              //Device is not working correctly try another option
              
              deviceList[idx].port.close(function (err) {
                /*console.log('port closed', err);
                var comport = deviceList[idx].com;
                var history = deviceList[idx].history;

                var portNum = getPortNumber(comport);

                for (var j = 0; j < deviceList.length; j++) {
                  if (deviceList[j].com == '' && deviceList[j].port == null && porthistory[portNum][j] == 0) {
                    //Register new device here
                    deviceList[j] = RegisterNewDevice(deviceList[j], comport, j);
                    porthistory[portNum][j] = 1;
                    break;
                  }
                }*/
              });
            } else {
              //Try to solicit a response
              if (idx == 2) {
                var buffer = Buffer.from([0x24, 0x5F, 0x00, 0xA1]);
                deviceList[idx].port.write(buffer);
                //deviceList[idx].port.write(String.fromCharCode(0x24) + String.fromCharCode(0x7F) + String.fromCharCode(0x04) + String.fromCharCode(0x00) + String.fromCharCode(0x00) + String.fromCharCode(0x85));
              } else if (idx == 3) {
                deviceList[idx].port.write("Ping" + String.fromCharCode(13));
              } else if (idx == 4) {
                deviceList[idx].port.write("$RESPOND" + String.fromCharCode(13));
              }
            }
          }
        } else {

          var portNum = getPortNumber(ports[i].comName);
          for (var j = 0; j < deviceList.length; j++) {
            if (deviceList[j].com == '' && deviceList[j].port == null && porthistory[portNum][j] == 0) {
              //Register new device here
              deviceList[j] = RegisterNewDevice(deviceList[j], ports[i].comName, j);
              porthistory[portNum][j] = 1;
              break;
            }
          }
        }
      }
    }
  });
  //connectDevice();
}, 500);

var getPortNumber = function(comport)
{
  var num = parseInt(comport.substr(3, (comport.length - 3)));
  return num;
}

var existsRes = false;
//Check if port still exists
function exists(comName) {
  serialport.list(function (err, ports) {
      ports.forEach(function (port) {
          if (port.comName == comName) {
            existsRes = true;
          }
      });
  });
}

var sendClosePort = function(idx, com)
{
  if (idx == 0) {
    mainWindow.webContents.send('control-message', "C" + "PE" + idx.toString() + com);
  } else if (idx == 1) {
    mainWindow.webContents.send('control-message', "C" + "PE" + idx.toString() + com);
  } else if (idx == 2) {
    mainWindow.webContents.send('control-message', "C" + "RAI" + com);
  } else if (idx == 3) {
    mainWindow.webContents.send('control-message', "C" + "MAI" + com);
  } else if (idx == 4) {
    mainWindow.webContents.send('control-message', "C" + "GPS" + com);
  } else if (idx == 5) {
    mainWindow.webContents.send('control-message', "C" + "CAN" + com);
  }
}

var sendOpenPort = function(idx, com)
{
  if (idx == 0) {
    mainWindow.webContents.send('control-message', "O" + "PE" + idx.toString() + com);
  } else if (idx == 1) {
    mainWindow.webContents.send('control-message', "O" + "PE" + idx.toString() + com);
  } else if (idx == 2) {
    mainWindow.webContents.send('control-message', "O" + "RAI" + com);
  } else if (idx == 3) {
    mainWindow.webContents.send('control-message', "O" + "MAI" + com);
  } else if (idx == 4) {
    mainWindow.webContents.send('control-message', "O" + "GPS" + com);
  } else if (idx == 5) {
    mainWindow.webContents.send('control-message', "O" + "CAN" + com);
  }
}

var sendTestPort = function(idx, com)
{
  if (idx == 0) {
    mainWindow.webContents.send('control-message', "T" + "PE" + idx.toString() + com);
  } else if (idx == 1) {
    mainWindow.webContents.send('control-message', "T" + "PE" + idx.toString() + com);
  } else if (idx == 2) {
    mainWindow.webContents.send('control-message', "T" + "RAI" + com);
  } else if (idx == 3) {
    mainWindow.webContents.send('control-message', "T" + "MAI" + com);
  } else if (idx == 4) {
    mainWindow.webContents.send('control-message', "T" + "GPS" + com);
  } else if (idx == 5) {
    mainWindow.webContents.send('control-message', "T" + "CAN" + com);
  }
}

var CheckDataType = function(idx, type)
{
  if (idx == 2) {
    deviceList[idx].reply_received = true;
    mainWindow.webContents.send('control-message', "O" + "RAI" + deviceList[idx].com);
  } else if (type == 0xA5 || type == 0xFC || type == 0xC7) {
    //Flow control/hydraulic board
    if (deviceList[idx].name == 'Main Unit') {
      deviceList[idx].port.close(function (err) {
        console.log('port closed', err);
        var comport = deviceList[idx].com;
        sendClosePort(idx, comport);
        var history = deviceList[idx].history;
        deviceList[idx].com = '';
        deviceList[idx].port = null;

        if (deviceList[0].com == '' && deviceList[0].port == null) {
          deviceList[0].history = history;
          RegisterNewDevice(deviceList[0], comport, 0);
        } else if (deviceList[1].com == '' && deviceList[1].port == null) {
          deviceList[1].history = history;
          RegisterNewDevice(deviceList[1], comport, 1);
        } else {
          console.log('too many ports', err);
        }
      });
      //Change from main unit to flow control boards
    } else {
      deviceList[idx].reply_received = true;
      mainWindow.webContents.send('control-message', "O" + "PE" + idx.toString() + deviceList[idx].com);
    }
  } else if (type == 0xCA) {
    //CANBus board
    deviceList[idx].reply_received = true;
    mainWindow.webContents.send('control-message', "O" + "CAN" + deviceList[idx].com);
  } else if (type < 27 || type == 0x99 || type == 0xDA) {
    //Main unit
    if (deviceList[idx].name != 'Main Unit') {
      deviceList[idx].port.close(function (err) {
        console.log('port closed', err);
        var comport = deviceList[idx].com;
        sendClosePort(idx, comport);
        var history = deviceList[idx].history;
        deviceList[idx].com = '';
        deviceList[idx].port = null;

        if (deviceList[3].com == '' && deviceList[3].port == null) {
          deviceList[3].history = history;
          RegisterNewDevice(deviceList[3], comport, 3);
        } else {
          console.log('too many ports', err);
        }
      });
      //Change from main unit to flow control boards
    } else {
      deviceList[idx].reply_received = true;
      mainWindow.webContents.send('control-message', "O" + "MAI" + deviceList[idx].com);
    }
  } else if (type == 0x98) {
    //GPS board
    deviceList[idx].reply_received = true;
    mainWindow.webContents.send('control-message', "O" + "GPS" + deviceList[idx].com);

  } else if (type == 0x4A) {
    //GPS board
    deviceList[idx].reply_received = true;
    mainWindow.webContents.send('control-message', "O" + "RAI" + deviceList[idx].com);

  }
}

var comPortInUse = function(com)
{
  for (var i = 0; i < deviceList.length; i++) {
    if (deviceList[i].com == com) {
      return i;
    }
  }
  return -1;
}

var deviceList = [
  { default_baud: 9600, com: '', port: null, name: 'Peripheral Device 1', buffer: [], reply_received: 0, reply_counter: 5, history: [0,0,0,0,0,0]},
  { default_baud: 9600, com: '', port: null, name: 'Peripheral Device 2', buffer: [], reply_received: 0, reply_counter: 5, history: [0,0,0,0,0,0]},
  { default_baud: 38400, com: '', port: null, name: 'Rain Meter', buffer: [], reply_received: 0, reply_counter: 5, history: [0,0,0,0,0,0]},
  { default_baud: 9600, com: '', port: null, name: 'Main Unit', buffer: [], reply_received: 0, reply_counter: 5, history: [0,0,0,0,0,0]},
  { default_baud: 38400, com: '', port: null, name: 'External GPS', buffer: [], reply_received: 0, reply_counter: 5, history: [0,0,0,0,0,0]},
  { default_baud: 250000, com: '', port: null, name: 'CANBus monitor', buffer: [], reply_received: 0, reply_counter: 5, history: [0,0,0,0,0,0]},
]

var RegisterNewDevice = function(device, comport, idx)
{
  device.port = new serialport(comport, {
    baudRate: device.default_baud,
    disconnectedCallback: function() {console.log('You pulled the plug!');}         
  });
  
  device.reply_received = 0;
  device.reply_counter = 5;
  device.com = comport;
  console.log("TYPE: " + idx + ":" + comport);
  sendTestPort(idx, comport);

  // do something with incoming data
  device.port.on('data', function (data) {
    filterCOMData(data, device.buffer, idx)
  });

  device.port.on('close', function(){
      console.log('PORT CLOSED IDX: ' + idx);
      sendClosePort(idx, comport);
      deviceList[idx].com = '';
      deviceList[idx].port = null;
      device.port = null;
      device.com = '';
  });

  device.port.on('error', function (err) {
      console.log("ERROR");
      console.error("error", err);
      device.port = null;
      device.com = '';
  });

  device.port.on('disconnected', function (err) {
      console.log('on.disconnect');
      sendClosePort(idx, comport);
      device.port = null;
      device.com = '';
  });
  return device;
}