export const byteToStr = (v: number) => String.fromCharCode((v & 0xF) + 97, ((v >> 4) & 0xF) + 97)
export const wordToStr = (v: number) => byteToStr(v & 0xFF) + byteToStr((v >> 8) & 0xFF)

// Waveshare 7.5 V2, derived from original source code
export const DisplayCode = `EPD${String.fromCharCode(22 + 97)}_`

type Pixel = 0 | 1 | 2 | 3 // monochrome ePaper display

export function getPixelValue (bitmap: Uint8ClampedArray, index: number): Pixel {
  const px = bitmap[index]
  const px2 = bitmap[index + 1]

  if (px === px2) {
    if (px === 0x00) return 0
    if (px === 0xFF) return 1
    if (px === 0x7F) return 2
  }
  return 3
}

function getImageData (bitmap: Uint8ClampedArray, width: number, height: number): Pixel[] {
  const imageData = Array(width * height) as Pixel[]

  let i = 0
  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++, i++) {
      imageData[i] = getPixelValue(bitmap, i << 2)
    }
  }

  return imageData
}

export default function initializeTransmitter (ip: string) {
  const POST_URL = `http://${ip}/`
  
  let stIndex = 0 // some index
  let pxIndex = 0 // pixel value index
  let rqMsg = ''  // message sent to server
  let imageData: Pixel[]
  let dataLen: number

  async function u_send (cmd: string, next: boolean) {
    try {
      await fetch(`${POST_URL}${cmd}`, {
        method: 'POST',
        body: '',
      })
    } catch {
      /* ignore errors */
    } finally {
      if (stIndex === 0) u_data()
      else if (stIndex === 1) u_done()
    }

    if (next) stIndex++
  }

  function u_done () {
    console.log('Transfer Complete!')
    u_send('SHOW_', true)
  }

  function u_show () {
    const percentage = pxIndex / dataLen * 100
    console.log(`Transfer: ${pxIndex}/${dataLen} (${Math.round(percentage)}%)`)

    const cmd = `${rqMsg}${wordToStr(rqMsg.length)}LOAD_`
    u_send(cmd, pxIndex >= dataLen)
  }

  function u_data () {
    rqMsg = ""

    while ((pxIndex < dataLen) && (rqMsg.length < 1000)) {
      let v = 0;
      for (let i = 0; i < 8; i++) {
        if ((pxIndex < dataLen) && imageData[pxIndex++]) v |= 128 >> i
      }
      rqMsg += byteToStr(v)
    }

    u_show()
  }

  return function uploadImage (bitmap: Uint8ClampedArray, width: number, height: number) {
    imageData = getImageData(bitmap, width, height)
    dataLen = imageData.length
    u_send(DisplayCode, false);
  }
}
