using PCSC;
using PCSC.Iso7816;
using System;
using System.Linq;

namespace NFC.ISO7816_4
{
    public class APDUCommand : CommandApdu
    {
        public APDUCommand(IsoCase isoCase) : base(isoCase, SCardProtocol.Any)
        {

        }

        public override bool Equals(object obj)
        {          
            return obj is APDUCommand command &&
                   Case == command.Case &&
                   Protocol == command.Protocol &&
                   CLA == command.CLA &&
                   INS == command.INS &&
                   P1 == command.P1 &&
                   P2 == command.P2 &&
                   Data.SequenceEqual(command.Data) &&
                   Le == command.Le;
        }

        public override int GetHashCode()
        {
            HashCode hash = new HashCode();
            hash.Add(Case);
            hash.Add(Protocol);
            hash.Add(IsValid);
            hash.Add(CLA);
            hash.Add(INS);
            hash.Add(P1);
            hash.Add(P2);
            hash.Add(P1P2);
            hash.Add(Data);
            hash.Add(Lc);
            hash.Add(P3);
            hash.Add(Le);
            hash.Add(ExpectedResponseLength);
            hash.Add(IsValid);
            return hash.ToHashCode();
        }

        public static bool operator ==(APDUCommand obj1, APDUCommand obj2)
        {
            return obj1.Equals(obj2);
        }

        public static bool operator !=(APDUCommand obj1, APDUCommand obj2)
        {
            return !(obj1.Equals(obj2));
        }

        public override string ToString()
        {
            string pattern_case1 = "(CASE: 1) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x}";
            string pattern_case2 = "(CASE: 2) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x} | LE: 0x{4:x} |";
            string pattern_case3 = "(CASE: 3) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x} | LC: 0x{4:x} | Data: {5:x}";
            string pattern_case4 = "(CASE: 4) CLA: 0x{0:x} | INS: 0x{1:x} | P1: 0x{2:x} | P2: 0x{3:x} | LC: 0x{4:x} | Data: {5:x} | LE: 0x{6:x} |";

            switch (Case)
            {
                case IsoCase.Case1:
                    return string.Format(pattern_case1, CLA, INS, P1, P2);
                case IsoCase.Case2Short:
                case IsoCase.Case2Extended:
                    return string.Format(pattern_case2, CLA, INS, P1, P2, Le);
                case IsoCase.Case3Short:
                case IsoCase.Case3Extended:
                    return string.Format(pattern_case3, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", " "));
                case IsoCase.Case4Short:
                case IsoCase.Case4Extended:
                    return string.Format(pattern_case4, CLA, INS, P1, P2, Lc, BitConverter.ToString(Data).Replace("-", " "), Le);
                default:
                    throw new Exception("Unknown IsoCase");
            }
        }
    }
}