export default class SerialPortHandler {
  constructor(options, onConnect, onDisconnect) {
    this.onConnect = onConnect
    this.onDisconnect = onDisconnect
    this.options = options
    this.port = null
    this.isOpened = false
    this.setupListeners()
  }

  async open() {
    try {
      const port = await navigator.serial.requestPort()
      await port.open(this.options)

      this.port = port
      this.isOpened = true

      return this.port.getInfo()
    } catch (error) {
      console.error(error)
      throw error
    }
  }

  async close() {
    await this.port.close()
    this.isOpened = false
  }

  async write(data) {
    if (this.port.writable) {
      let writer = this.port.writable.getWriter()
      await writer.write(data)
      writer.releaseLock()
    }
  }

  async read() {
    let decoder = new TextDecoder();

    while (this.port.readable) {
      if (this.port.readable.locked == true) {
        return new Uint8Array(0)
      }
      let reader = this.port.readable.getReader()
      let result
      let len = 0

      try {
        while (true) {
          let { value, done } = await reader.read()

          len = len +value.length
          
          if (typeof result == 'undefined') {
            result = value
          } else {
            result = new Uint8Array([ ...result, ...value])
          }
         
          let str = decoder.decode(result);
          if (str.includes('ok') || str.includes('error') ||  str.includes('ALARM') || done) {
            reader.releaseLock()
            break
          }
        }

        if (result.length > 2048) {
          return result.slice(result.length - 2048)
        } else {
          return result
        }
      } catch (error) {
        console.error(error)
        throw error
      } finally {
        reader.releaseLock()
      }
    }
  }

  setupListeners() {
    navigator.serial.addEventListener('connect', this.onConnect)
    navigator.serial.addEventListener('disconnect', this.onDisconnect)
  }

}

