using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WinRT.BxlComponent.Plugin.BxlMpXamarinSDK.Abstractions
{
    internal enum BgateDeviceReadMode { ONETIME = 0, AUTO_ENABLE, AUTO_DISABLE }
    internal enum BgateMultiConnectionPage { START = 0x70, END }
    internal enum BgateDeviceId
    {
        COMMAND = 0x00,
        LOCAL_PRINTER = 0x0A,
        PNP_COMMAND = 0xFF
    }
    internal class MPosBgateCmdBuilder
    {
        public static byte[] getUsbIdListCmd()
        {
            // Peripheral Register
            return addMPosHeaderData((uint)BgateDeviceId.COMMAND, new byte[] { 0x44 });
        }
        public static byte[] addMPosHeaderData(uint deviceId, byte[] data)
        {
            // BXL  <Device ID> <Data Length 2 bytes> + Data
            byte[] cmdHeader = new byte[] { 0x42, 0x58, 0x4C, 0x0a, 0x00, 0x00 };
            cmdHeader[3] = (byte)deviceId;
            cmdHeader[4] = (byte)((data.Length) / 256);
            cmdHeader[5] = (byte)((data.Length) % 256);
            return MPosByteArrayHelper.concat(cmdHeader, data);
        }
        public static byte[] getPnpEnableDisableCmd(bool enable)
        {
            // PnP (Plug and Play)
            if (enable)
                return addMPosHeaderData((uint)BgateDeviceId.PNP_COMMAND, new byte[] { 0x01 });
            return addMPosHeaderData((uint)BgateDeviceId.PNP_COMMAND, new byte[] { 0x00 });
        }
        public static byte[] getPageStartEndCmd(uint deviceId, BgateMultiConnectionPage page)
        {
            // Multiple Connection
            byte[] pageStartEnd = new byte[] { 0x70, 0x0a };
            pageStartEnd[pageStartEnd.Length-1] = (byte)deviceId;

            switch (page)
            {
                case BgateMultiConnectionPage.START:    pageStartEnd[pageStartEnd.Length-2] = 0x70; break;
                case BgateMultiConnectionPage.END:      pageStartEnd[pageStartEnd.Length-2] = 0x71; break;
            }

            return addMPosHeaderData((uint)BgateDeviceId.COMMAND, pageStartEnd);
        }
        public static byte[] getReadModeCmd(uint deviceId, BgateDeviceReadMode mode)
        {
            // Multiple Connection
            var mPOsReadMode = new byte[] { 0x72, 0x00, 0X01 };

            mPOsReadMode[mPOsReadMode.Length-2] = (byte)deviceId;

            switch (mode)
            {
                case BgateDeviceReadMode.ONETIME:       mPOsReadMode[mPOsReadMode.Length-1] = 0x00; break;
                case BgateDeviceReadMode.AUTO_ENABLE:   mPOsReadMode[mPOsReadMode.Length-1] = 0x01; break;
                case BgateDeviceReadMode.AUTO_DISABLE:  mPOsReadMode[mPOsReadMode.Length-1] = 0x02; break;
                default:
                    mPOsReadMode[mPOsReadMode.Length-1] = 0x01;
                    break;
            }

            return addMPosHeaderData((uint)BgateDeviceId.COMMAND, mPOsReadMode);
        }
        public static byte[] getTTYUSBSerialConfigWriteCmd(int targetTTYUSBDevId, int baudrate, int databit, int stopbit, int paritybit, int flowcontrol)
        {
            byte[] serialConfigWriteCmd = new byte[] { 0x0c, 0x00/*targetId*/, 0x00/*baudrate*/, 0x00/*databit*/, 0x00/*stopbit*/, 0x00/*paritybit*/};
            serialConfigWriteCmd[1] = (byte)targetTTYUSBDevId;
            serialConfigWriteCmd[2] = (byte)baudrate;
            serialConfigWriteCmd[3] = (byte)databit;
            serialConfigWriteCmd[4] = (byte)stopbit;
            serialConfigWriteCmd[5] = (byte)paritybit;
            serialConfigWriteCmd[6] = (byte)flowcontrol;
            return addMPosHeaderData((uint)BgateDeviceId.COMMAND, serialConfigWriteCmd);
        }
        public static byte[] getTTYUSBSerialConfigReadCmd(int targetTTYUSBDevId)
        {
            byte[] serialConfigReadCmd = new byte[] { 0x0d, 0x00/*targetId*/};
            serialConfigReadCmd[1] = (byte)targetTTYUSBDevId;
            return addMPosHeaderData((uint)BgateDeviceId.COMMAND, serialConfigReadCmd);
        }
        public static byte[] getBgateSerialNumberReadCmd()
        {
            return addMPosHeaderData((uint)BgateDeviceId.COMMAND, new byte[] { 0x18 });
        }
        public static byte[] getUSBDeviceReadCmd(int deviceId)
        {
            byte[] usbDeviceReadCmd = new byte[] { 0x45, (byte)deviceId/*targetId*/};
            return addMPosHeaderData((uint)BgateDeviceId.COMMAND, usbDeviceReadCmd);
        }
        public static byte[] getCustomDevicesReadCmd(int deviceType)
        {
            int devType = convertDeviceType((MPosDeviceType)deviceType);

            byte[] getCustomDeviceCmd = new byte[] { 0x40, (byte)devType };
            return addMPosHeaderData((uint)BgateDeviceId.COMMAND, getCustomDeviceCmd);
        }
        public static byte[] getAddCustomDeviceWriteCmd(int deviceType, string vid, string pid)
        {
            byte[] _vid = hexStringToByte(vid);
            byte[] _pid = hexStringToByte(pid);
            int devType = convertDeviceType((MPosDeviceType)deviceType);
            byte[] addCustomDeviceCmd = new byte[] { 0x41, (byte)devType, _vid[0], _vid[1], _pid[0], _pid[1] };
            return addMPosHeaderData((uint)BgateDeviceId.COMMAND, addCustomDeviceCmd);
        }
        public static byte[] getDeleteCustomDeviceWriteCmd(int deviceType, string vid, string pid)
        {
            byte[] _vid = hexStringToByte(vid);
            byte[] _pid = hexStringToByte(pid);
            int devType = convertDeviceType((MPosDeviceType)deviceType);
            byte[] deleteCustomDeviceCmd = new byte[] { 0x42, (byte)devType, _vid[0], _vid[1], _pid[0], _pid[1] };
            return addMPosHeaderData((uint)BgateDeviceId.COMMAND, deleteCustomDeviceCmd);
        }
        public static byte[] getReInitCustomDevicesTypeWriteCmd(int deviceType)
        {
            int devType = convertDeviceType((MPosDeviceType)deviceType);
            byte[] reInitCustomDeviceTypeCmd = new byte[] { 0x43, (byte)devType };
            return addMPosHeaderData((uint)BgateDeviceId.COMMAND, reInitCustomDeviceTypeCmd);
        }
        private static int convertDeviceType(MPosDeviceType deviceType)
        {
            switch (deviceType)
            {
                case MPosDeviceType.MPOS_DEVICE_PRINTER: return 0;
                case MPosDeviceType.MPOS_DEVICE_LABEL_PRINTER: return 1;
                case MPosDeviceType.MPOS_DEVICE_MSR: return 2;
                case MPosDeviceType.MPOS_DEVICE_SCANNER: return 3;
                case MPosDeviceType.MPOS_DEVICE_RFID: return 4;
                case MPosDeviceType.MPOS_DEVICE_DALLAS_KEY: return 5;
                case MPosDeviceType.MPOS_DEVICE_NFC: return 6;
                case MPosDeviceType.MPOS_DEVICE_DISPLAY: return 7;
                case MPosDeviceType.MPOS_DEVICE_USB_TO_SERIAL: return 8;
                case MPosDeviceType.MPOS_DEVICE_SCALE: return 9;
            }
            return 0;
        }
        private static byte[] hexStringToByte(string hexString)
        {
            byte[] bytes = new byte[2];
            bytes[0] = (byte)Int32.Parse(hexString.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
            bytes[1] = (byte)Int32.Parse(hexString.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
            return bytes;
        }
    }
}
