using NFC;
using NFC.Crypto;
using NFC.Mifare_DESFire;
using NFC.Mifare_DESFire.Enums;
using NFC.Readers.PCSC;
using NUnit.Framework;
using System;
using System.Text;

namespace NFC_Real_Test
{
    /// <summary>
    /// Test all DESFire Commands with an Empty Card
    /// The Test are ordered to check the Commands one by one
    /// </summary>
    [TestFixture, Explicit]
    public class REAL_DESFireCommands
    {
        /// <summary>
        /// Set ReaderID for PCSC Interface
        /// You can get the ID from REAL_Reader_PCSC
        /// </summary>
        public readonly string ReaderID = "ACS ACR122U PICC Interface 0";

        #region Fixed Config Properties
        public readonly UInt32 ApplicationID = 0xAAFFEE;
        public readonly string ApplicationMasterKey = "25432A462D4A614E645267556B587032";
        public readonly string ApplicationKey_1 = "25432A462D4A614E645267556B587032";
        public readonly byte FileID = 0x01;
        public readonly byte FileSize = 0xF0;
        #endregion

        [Test, Order(1)]
        public void SelectApplication()
        {
            IHardware hardware = new PCSC_Hardware();
            IReader reader = hardware.OpenReader(ReaderID);

            bool test_successfully = false;

            ReaderEventHandler handler = (sender, card) =>
            {
                card.Connect();

                MIFARE_DESFire desfire = new MIFARE_DESFire(card);

                desfire.SelectApplication(0x000000);

                test_successfully = true;

                card.Disconnect();
            };

            reader.CardDiscovered += handler;
            reader.Start();

            Assert.AreEqual(true, test_successfully);

            reader.Stop();
            reader.CardDiscovered -= handler;
        }

        [Test, Order(2)]
        public void Authenticate_DES()
        {
            IHardware hardware = new PCSC_Hardware();
            IReader reader = hardware.OpenReader(ReaderID);

            bool test_successfully = false;

            ReaderEventHandler handler = (sender, card) =>
            {
                card.Connect();

                MIFARE_DESFire desfire = new MIFARE_DESFire(card);

                desfire.SelectApplication(0x000000);

                CipherKey key = new CipherKey(CipherType.TDES);
                desfire.AuthenticateISO_DES(0x00, key._Key);

                test_successfully = true;

                card.Disconnect();
            };

            reader.CardDiscovered += handler;
            reader.Start();

            Assert.AreEqual(true, test_successfully);

            reader.Stop();
            reader.CardDiscovered -= handler;
        }

        [Test, Order(3)]
        public void Format()
        {
            IHardware hardware = new PCSC_Hardware();
            IReader reader = hardware.OpenReader(ReaderID);

            bool test_successfully = false;

            ReaderEventHandler handler = (sender, card) =>
            {
                card.Connect();

                MIFARE_DESFire desfire = new MIFARE_DESFire(card);

                desfire.SelectApplication(0x000000);

                CipherKey key = new CipherKey(CipherType.TDES);
                desfire.AuthenticateISO_DES(0x00, key._Key);

                desfire.Format();

                test_successfully = true;

                card.Disconnect();
            };

            reader.CardDiscovered += handler;
            reader.Start();

            Assert.AreEqual(true, test_successfully);

            reader.Stop();
            reader.CardDiscovered -= handler;
        }

        [Test, Order(4)]
        public void CreateApplication()
        {
            IHardware hardware = new PCSC_Hardware();
            IReader reader = hardware.OpenReader(ReaderID);

            bool test_successfully = false;

            ReaderEventHandler handler = (sender, card) =>
            {
                card.Connect();

                MIFARE_DESFire desfire = new MIFARE_DESFire(card);

                desfire.SelectApplication(0x000000);

                CipherKey key = new CipherKey(CipherType.TDES);
                desfire.AuthenticateISO_DES(0x00, key._Key);

                desfire.Format();

                desfire.AuthenticateISO_DES(0x00, key._Key);

                byte keysetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.ONLYMASTERKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
                byte keysetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 2);

                desfire.CreateApplication(ApplicationID, keysetting1, keysetting2);

                test_successfully = true;

                card.Disconnect();
            };

            reader.CardDiscovered += handler;
            reader.Start();

            Assert.AreEqual(true, test_successfully);

            reader.Stop();
            reader.CardDiscovered -= handler;
        }

        [Test, Order(5)]
        public void Authenticate_AES()
        {
            IHardware hardware = new PCSC_Hardware();
            IReader reader = hardware.OpenReader(ReaderID);

            bool test_successfully = false;

            ReaderEventHandler handler = (sender, card) =>
            {
                card.Connect();

                MIFARE_DESFire desfire = new MIFARE_DESFire(card);

                desfire.SelectApplication(0x000000);

                CipherKey key = new CipherKey(CipherType.TDES);
                desfire.AuthenticateISO_DES(0x00, key._Key);

                desfire.Format();

                desfire.AuthenticateISO_DES(0x00, key._Key);

                byte keysetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.ONLYMASTERKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
                byte keysetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 2);

                desfire.CreateApplication(ApplicationID, keysetting1, keysetting2);

                desfire.SelectApplication(ApplicationID);

                CipherKey key_aes = new CipherKey(CipherType.AES);
                desfire.AuthenticateISO_AES(0x00, key_aes._Key);

                test_successfully = true;

                card.Disconnect();
            };

            reader.CardDiscovered += handler;
            reader.Start();

            Assert.AreEqual(true, test_successfully);

            reader.Stop();
            reader.CardDiscovered -= handler;
        }

        [Test, Order(6)]
        public void ChangeApplicationMasterKey()
        {
            IHardware hardware = new PCSC_Hardware();
            IReader reader = hardware.OpenReader(ReaderID);

            bool test_successfully = false;

            ReaderEventHandler handler = (sender, card) =>
            {
                card.Connect();

                MIFARE_DESFire desfire = new MIFARE_DESFire(card);

                desfire.SelectApplication(0x000000);

                CipherKey key = new CipherKey(CipherType.TDES);
                desfire.AuthenticateISO_DES(0x00, key._Key);

                desfire.Format();

                desfire.AuthenticateISO_DES(0x00, key._Key);

                byte keysetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.ONLYMASTERKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
                byte keysetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 2);

                desfire.CreateApplication(ApplicationID, keysetting1, keysetting2);

                desfire.SelectApplication(ApplicationID);

                CipherKey key_aes = new CipherKey(CipherType.AES);
                desfire.AuthenticateISO_AES(0x00, key_aes._Key);

                CipherKey key_aes_new = new CipherKey(ApplicationMasterKey, CipherType.AES, 0x10);
                desfire.ChangeKey_AES(0x00, key_aes_new._Key, key_aes_new._KeyVersion);

                test_successfully = true;

                card.Disconnect();
            };

            reader.CardDiscovered += handler;
            reader.Start();

            Assert.AreEqual(true, test_successfully);

            reader.Stop();
            reader.CardDiscovered -= handler;
        }

        [Test, Order(7)]
        public void ChangeApplicationKey_1()
        {
            IHardware hardware = new PCSC_Hardware();
            IReader reader = hardware.OpenReader(ReaderID);

            bool test_successfully = false;

            ReaderEventHandler handler = (sender, card) =>
            {
                card.Connect();

                MIFARE_DESFire desfire = new MIFARE_DESFire(card);

                desfire.SelectApplication(0x000000);

                CipherKey key = new CipherKey(CipherType.TDES);
                desfire.AuthenticateISO_DES(0x00, key._Key);

                desfire.Format();

                desfire.AuthenticateISO_DES(0x00, key._Key);

                byte keysetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.ONLYMASTERKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
                byte keysetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 2);

                desfire.CreateApplication(ApplicationID, keysetting1, keysetting2);

                desfire.SelectApplication(ApplicationID);

                CipherKey key_aes = new CipherKey(CipherType.AES);
                desfire.AuthenticateISO_AES(0x00, key_aes._Key);

                CipherKey key_new = new CipherKey(ApplicationKey_1, CipherType.AES, 0x10);
                desfire.ChangeOtherKey_AES(0x01, key_new._Key, key_aes._Key, key_new._KeyVersion);

                test_successfully = true;

                card.Disconnect();
            };

            reader.CardDiscovered += handler;
            reader.Start();

            Assert.AreEqual(true, test_successfully);

            reader.Stop();
            reader.CardDiscovered -= handler;
        }

        [Test, Order(8)]
        public void CreateFile()
        {
            IHardware hardware = new PCSC_Hardware();
            IReader reader = hardware.OpenReader(ReaderID);

            bool test_successfully = false;

            ReaderEventHandler handler = (sender, card) =>
            {
                card.Connect();

                MIFARE_DESFire desfire = new MIFARE_DESFire(card);

                desfire.SelectApplication(0x000000);

                CipherKey key = new CipherKey(CipherType.TDES);
                desfire.AuthenticateISO_DES(0x00, key._Key);

                desfire.Format();

                desfire.AuthenticateISO_DES(0x00, key._Key);

                byte keysetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.ONLYMASTERKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
                byte keysetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 2);

                desfire.CreateApplication(ApplicationID, keysetting1, keysetting2);

                desfire.SelectApplication(ApplicationID);

                CipherKey key_aes = new CipherKey(CipherType.AES);
                desfire.AuthenticateISO_AES(0x00, key_aes._Key);

                UInt16 accesRights = desfire.GenerateFileAccessRights((byte)FileAccessRights.FREE, 0x00, 0x00, 0x00);
                desfire.CreateFile_Standard(FileID, FileCommunication.PLAIN, accesRights, FileSize);

                test_successfully = true;

                card.Disconnect();
            };

            reader.CardDiscovered += handler;
            reader.Start();

            Assert.AreEqual(true, test_successfully);

            reader.Stop();
            reader.CardDiscovered -= handler;
        }

        [Test, Order(9)]
        public void WriteFile()
        {
            IHardware hardware = new PCSC_Hardware();
            IReader reader = hardware.OpenReader(ReaderID);

            bool test_successfully = false;

            ReaderEventHandler handler = (sender, card) =>
            {
                card.Connect();

                MIFARE_DESFire desfire = new MIFARE_DESFire(card);

                desfire.SelectApplication(0x000000);

                CipherKey key = new CipherKey(CipherType.TDES);
                desfire.AuthenticateISO_DES(0x00, key._Key);

                desfire.Format();

                desfire.AuthenticateISO_DES(0x00, key._Key);

                byte keysetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.ONLYMASTERKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
                byte keysetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 2);

                desfire.CreateApplication(ApplicationID, keysetting1, keysetting2);

                desfire.SelectApplication(ApplicationID);

                CipherKey key_aes = new CipherKey(CipherType.AES);
                desfire.AuthenticateISO_AES(0x00, key_aes._Key);

                UInt16 accesRights = desfire.GenerateFileAccessRights((byte)FileAccessRights.FREE, 0x00, 0x00, 0x00);
                desfire.CreateFile_Standard(FileID, FileCommunication.PLAIN, accesRights, FileSize);

                desfire.WriteData(FileID, 0, Encoding.ASCII.GetBytes("Test1234"));

                test_successfully = true;

                card.Disconnect();
            };

            reader.CardDiscovered += handler;
            reader.Start();

            Assert.AreEqual(true, test_successfully);

            reader.Stop();
            reader.CardDiscovered -= handler;
        }

        [Test, Order(10)]
        public void ReadFile()
        {
            IHardware hardware = new PCSC_Hardware();
            IReader reader = hardware.OpenReader(ReaderID);

            bool test_successfully = false;

            ReaderEventHandler handler = (sender, card) =>
            {
                card.Connect();

                MIFARE_DESFire desfire = new MIFARE_DESFire(card);

                desfire.SelectApplication(0x000000);

                CipherKey key = new CipherKey(CipherType.TDES);
                desfire.AuthenticateISO_DES(0x00, key._Key);

                desfire.Format();

                desfire.AuthenticateISO_DES(0x00, key._Key);

                byte keysetting1 = desfire.GenerateKeySetting1(ChangeApplicationKey.MASTERKEY, ChangeMasterKeySettings.WITHMASTERKEY, CreateDeleteFile.ONLYMASTERKEY, FileDirectoryAccess.NOKEY, ChangeMasterKey.CHANGEABLE);
                byte keysetting2 = desfire.GenerateKeySetting2(CryptoOperationsType.AES, FileIdentifies.NOTUSED, 2);

                desfire.CreateApplication(ApplicationID, keysetting1, keysetting2);

                desfire.SelectApplication(ApplicationID);

                CipherKey key_aes = new CipherKey(CipherType.AES);
                desfire.AuthenticateISO_AES(0x00, key_aes._Key);

                UInt16 accesRights = desfire.GenerateFileAccessRights((byte)FileAccessRights.FREE, 0x00, 0x00, 0x00);
                desfire.CreateFile_Standard(FileID, FileCommunication.PLAIN, accesRights, FileSize);

                desfire.WriteData(FileID, 0, Encoding.ASCII.GetBytes("Test1234"));

                byte[] data = desfire.ReadData(FileID, 0, FileSize);
                Console.WriteLine(Encoding.ASCII.GetString(data).Replace("\u0000", ""));

                test_successfully = true;

                card.Disconnect();
            };

            reader.CardDiscovered += handler;
            reader.Start();

            Assert.AreEqual(true, test_successfully);

            reader.Stop();
            reader.CardDiscovered -= handler;
        }
    }
}