using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Rglib.Interop;

namespace rglib.libtest {
    public partial class BlockReadWriteDialog : Form {

        private byte[] _blockData;

        private Reader _reader;

        public BlockReadWriteDialog() {
            InitializeComponent();

            classicKeyBox.ByteProvider = new FixedByteProvider(new byte[6] {255,255,255,255,255,255});
            plusKeyBox.ByteProvider = new FixedByteProvider(new byte[16]
                {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255});
            _blockData = new byte[16];
            dataBox.ByteProvider = new FixedByteProvider(_blockData);
        }

        public BlockReadWriteDialog(Reader reader) : this() {
            _reader = reader;
        }

        private void OnLoad(object sender, EventArgs e) {
            UpdateControlState();
        }

        private void UpdateControlState() {
            if (authComboBox.SelectedIndex < 0) {
                authComboBox.SelectedIndex = 0;
            }

            if (cryptoOneType.SelectedIndex < 0) {
                cryptoOneType.SelectedIndex = 0;
            }

            if (aesKeyType.SelectedIndex < 0) {
                aesKeyType.SelectedIndex = 0;
            }

            authComboBox.Enabled = byBlock.Checked;
            cryptoOneType.Enabled = byBlock.Checked;
            aesKeyType.Enabled = byBlock.Checked;
            classicKeyBox.Enabled = byBlock.Checked;
            plusKeyBox.Enabled = byBlock.Checked;
            readButton.Enabled = byBlock.Checked;
        }

        private void ByProfileCheckedChanged(object sender, EventArgs e) {
            UpdateControlState();
        }

        private void ReadButtonClick(object sender, EventArgs e) {
            try
            {
                RG_ENDPOINT portEndpoin = _reader.Endpoint;
                RG_CARD_MEMORY memory = new RG_CARD_MEMORY();
                memory.ProfileOrBlockNum = Convert.ToByte(profileBlockBox.Value);

                RG_CARD_AUTH_PARAMS authParams = new RG_CARD_AUTH_PARAMS();

                authParams.Flags = 0;
                authParams.Flags |= cryptoOneType.SelectedIndex == 1 ? (byte)RG_CARD_AUTH_FLAGS.CAF_CLASSIC_KEY_B : (byte)0;
                authParams.Flags |= aesKeyType.SelectedIndex == 1 ? (byte)RG_CARD_AUTH_FLAGS.CAF_PLUS_KEY_B : (byte)0;
                authParams.Flags |= authComboBox.SelectedIndex == 1 ? (byte)RG_CARD_AUTH_FLAGS.CAF_PLUS_SL3 : (byte)0;

                authParams.ClassicKey = new byte[6];
                authParams.PlusKey = new byte[16];

                Buffer.BlockCopy(((FixedByteProvider) classicKeyBox.ByteProvider).Bytes.ToArray(), 0, authParams.ClassicKey, 0,
                    authParams.ClassicKey.Length);
                Buffer.BlockCopy(((FixedByteProvider) plusKeyBox.ByteProvider).Bytes.ToArray(), 0, authParams.PlusKey, 0,
                    authParams.PlusKey.Length);

                uint errorCode = 0;
                errorCode = Methods.RG_ReadBlockDirect(ref portEndpoin, _reader.Address, ref memory, ref authParams);

                if (errorCode != 0)
                {
                    throw new InvalidOperationException(
                        $"Ошибка при выполнении инициализации устройства. {errorCode} {ApiErrorHelper.GetErrorDescription(errorCode)}");
                }

                Buffer.BlockCopy(memory.BlockData, 0, _blockData,0, memory.BlockData.Length);
                dataBox.ByteProvider = new FixedByteProvider(_blockData);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void button1_Click(object sender, EventArgs e) {
            _blockData[0] = 1;
            var provider = dataBox.ByteProvider;
            dataBox.ByteProvider = null;
            dataBox.ByteProvider = provider;
        }

        private void writeButton_Click(object sender, EventArgs e) {
            try {
                RG_ENDPOINT portEndpoin = _reader.Endpoint;
                RG_CARD_MEMORY memory = new RG_CARD_MEMORY();

                Buffer.BlockCopy(((FixedByteProvider) dataBox.ByteProvider).Bytes.ToArray(), 0, _blockData, 0, _blockData.Length);
                memory.ProfileOrBlockNum = Convert.ToByte(profileBlockBox.Value);
                memory.BlockData = _blockData;

                if (byProfile.Checked) {
                    uint errorCode =
                        Methods.RG_WriteBlock(ref portEndpoin, _reader.Address, ref memory);

                    if (errorCode != 0) {
                        throw new InvalidOperationException(
                            $"Ошибка при записи блока по профилю. {errorCode} {ApiErrorHelper.GetErrorDescription(errorCode)}");
                    }
                }
                else {
                    RG_CARD_AUTH_PARAMS authParams = new RG_CARD_AUTH_PARAMS();
                    authParams.Flags = 0;
                    authParams.ClassicKey = new byte[6];
                    authParams.PlusKey = new byte[16];

                    authParams.Flags = 0;
                    authParams.Flags |= cryptoOneType.SelectedIndex == 1 ? (byte)RG_CARD_AUTH_FLAGS.CAF_CLASSIC_KEY_B : (byte)0;
                    authParams.Flags |= aesKeyType.SelectedIndex == 1 ? (byte)RG_CARD_AUTH_FLAGS.CAF_PLUS_KEY_B : (byte)0;
                    authParams.Flags |= authComboBox.SelectedIndex == 1 ? (byte)RG_CARD_AUTH_FLAGS.CAF_PLUS_SL3 : (byte)0;

                    Buffer.BlockCopy(((FixedByteProvider) classicKeyBox.ByteProvider).Bytes.ToArray(), 0,
                        authParams.ClassicKey, 0,
                        authParams.ClassicKey.Length);
                    Buffer.BlockCopy(((FixedByteProvider) plusKeyBox.ByteProvider).Bytes.ToArray(), 0,
                        authParams.PlusKey, 0,
                        authParams.PlusKey.Length);

                    uint errorCode = 0;                  
                    errorCode = Methods.RG_WriteBlockDirect(ref portEndpoin, _reader.Address, ref memory, ref authParams);

                    if (errorCode != 0) {
                        throw new InvalidOperationException(
                            $"Общ Ошибка при записи блока. {errorCode} {ApiErrorHelper.GetErrorDescription(errorCode)}");
                    }
                }
            }
            catch (Exception ex) {
                MessageBox.Show(this, ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void RasButtonClick(object sender, EventArgs e) {
            ushort sak = 0;
            ushort atqa = 0;
            byte[] uid = new byte[10];
            RG_ENDPOINT portEndpoin = _reader.Endpoint;
            try {
                uint errorCode = Methods.RG_Iso_Ras(ref portEndpoin, _reader.Address, ref sak, ref atqa, uid, 10);

                if (errorCode != 0) {
                    throw new InvalidOperationException(
                        $"Ошибка при выполнении RAS. {errorCode} {ApiErrorHelper.GetErrorDescription(errorCode)}");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void RatsButtonClick(object sender, EventArgs e) {
            byte[] uid = new byte[10];
            byte[] ats = new byte[16]; 
            int atsSize = 0;
            RG_ENDPOINT portEndpoin = _reader.Endpoint;
            try {
                var errorCode = Methods.RG_Iso_Rats(ref portEndpoin, _reader.Address, ats, 16, ref atsSize);

                if (errorCode != 0) {
                    throw new InvalidOperationException(
                        $"Ошибка при выполнении RATS. {errorCode} {ApiErrorHelper.GetErrorDescription(errorCode)}");
                }
            }
            catch (Exception ex) {
                MessageBox.Show(this, ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void RfButtonClick(object sender, EventArgs e)
        {
            RG_ENDPOINT portEndpoin = _reader.Endpoint;
            var errorCode = Methods.RG_ResetField(ref portEndpoin, _reader.Address);
            if (errorCode != 0) {
                throw new InvalidOperationException(
                    $"Ошибка при выполнении Reset Field. {errorCode} {ApiErrorHelper.GetErrorDescription(errorCode)}");
            }
        }

        private void AuthButtonClick(object sender, EventArgs e) {
            var key = new byte[]
                {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
            RG_ENDPOINT portEndpoin = _reader.Endpoint;
            try {
                var errorCode = Methods.RG_Iso_Auth(ref portEndpoin, _reader.Address, 0x4000, key, key.Length);
                if (errorCode != 0)
                {
                    throw new InvalidOperationException(
                        $"Ошибка при выполнении Auth. {errorCode} {ApiErrorHelper.GetErrorDescription(errorCode)}");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}
