using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using everdrive3x.Misc;

namespace everdrive3x.Hardware
{
    internal class Communication
    {
        public static int BAUDRATE_BOOTLOADER = 19200;
        public static int BAUDRATE_WORK = 921600;
        public static int BUFF_SIZE = 1024;

        SerialPort port;
        byte[] tx_buff;
        byte[] rx_buff;
        int tx_ptr;
        int rx_len;
        int rx_prt;

        public Communication(String port_name)
        {
            port = new SerialPort(port_name);
            port.BaudRate = BAUDRATE_BOOTLOADER;
            port.WriteTimeout = 1000;
            tx_buff = new byte[BUFF_SIZE * 2];
            rx_buff = new byte[BUFF_SIZE * 2];
            tx_ptr = 2;
            rx_len = 0;
            rx_prt = 0;
         }

        public SerialPort Port
        {
            get { return port; }
        }

        public void txCmd(int cmd_code)
        {
            byte []buff = new byte[2];
            buff[0] = CmdTable.CMD_NEW;
            buff[1] = (byte)cmd_code;
            port.Write(buff, 0, buff.Length);
        }

        public int rxCmd()
        {
            return port.ReadByte();
        }

        public void rxOk()
        {
            int response = port.ReadByte();
            if (response != CmdTable.CMD_OK) throw new Exception("unknown cmd: " + (char)response);
        }

        public void txData(int cmd_code)
        {
            tx_buff[0] = CmdTable.CMD_NEW;
            tx_buff[1] = (byte)cmd_code;
            port.Write(tx_buff, 0, tx_ptr);
            tx_ptr = 2;
        }

        public void rxData(int len)
        {
            rx_len = len;
            rx_prt = 0;
            while (len != 0)
            {
                len -= port.Read(rx_buff, rx_len - len, len);
            }
            
        }

        public void write8(int data)
        {
            tx_buff[tx_ptr++] = (byte)data;
        }
        public void write16(int data)
        {
            DataTool.write16(tx_buff, tx_ptr, data);
            tx_ptr += 2;
        }
        public void write32(int data)
        {
            DataTool.write32(tx_buff, tx_ptr, data);
            tx_ptr += 4;
        }

        public void write(byte[] src, int offset, int len)
        {
            System.Array.Copy(src, offset, tx_buff, tx_ptr, len);
            tx_ptr += len;
        }

        public int read8()
        {
            return rx_buff[rx_prt++];
        }

        public int read16()
        {
            rx_prt += 2;
            return DataTool.read16(rx_buff, rx_prt - 2);
        }
        public int read32()
        {
            rx_prt += 4;
            return DataTool.read32(rx_buff, rx_prt - 4);
        }

        public int readAvailable()
        {
            return rx_len - rx_prt;
        }

        public void read(byte[] src, int offset, int len)
        {
            System.Array.Copy(rx_buff, rx_prt, src, offset, len);
            rx_prt += len;
        }

        public byte[] read(int len)
        {
            byte[] buff = new byte[len];
            System.Array.Copy(rx_buff, rx_prt, buff, 0, len);
            rx_prt += len;
            return buff;
        }

        public void read(byte[] src, int offset)
        {
            int len = Math.Min(src.Length - offset, readAvailable());
            System.Array.Copy(rx_buff, rx_prt, src, offset, len);
            rx_prt += len;
        }
    }
}
