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

namespace RogerMfReaderExample.RUD3_v2
{
    class Epso
    {
        //|SOH  |PT	        |ID1    |ID2    |FC1    |FC2    |STX    |DATA   |ETX    |BCC        |
        //|01   |Identify	|Terminal ID	|Function code  |02	    |Data	|03	    |Checksum   |

        /// <summary>
        ///Prepare EPSO 2 function - Read Signature (0xE1)
        /// |0x01  |0x53 |ID1    |ID2    |'E'    |'1'  |0x02    |0x03   |BCC  |
        /// </summary>
        /// <param name="epsoId"> Terminal ID</param>
        /// <returns></returns>
        static public String readSignature(Byte epsoId)
        {
            byte[] frame = new byte[10];
            byte[] IdTab = new byte[2];

            frame[0] = 0x01;
            frame[1] = 0x53;                    //'S'

            //Convert id to ascii
            IdTab[0] = (byte)((epsoId & 0xF0) >> 0x04);
            IdTab[1] = (byte)(epsoId & 0x0F);

            for (int i = 0x00; i < IdTab.Length; i++)
            {
                if (IdTab[i] > 0x09)
                    frame[2 + i] = (byte)(IdTab[i] + (0x41)); //'A'
                else
                    frame[2 + i] = (byte)(IdTab[i] + (0x30)); //'0'                              
            }

            frame[4] = (byte)'E';                    //'E'
            frame[5] = (byte)'1';                    //'1'

            frame[6] = 0x02;
            frame[7] = 0x03;

            frame[8] = getBCC(frame, 0x08);     //BCC

            char[] charFrame = new char[frame.Length];

            for (int i = 0x00; i < charFrame.Length; i++)
            {
                charFrame[i] = Convert.ToChar(frame[i]);
            }

            return new string(charFrame);
        }


        /// <summary>
        /// Parse answer - EPSO 2  function Read Signature (0xE1)
        /// </summary>
        /// <param name="reciveFrame"> Answer frame</param>
        /// <returns>Sygnature</returns>
        static public String getSignature(String reciveFrame)
        {

            char[] reciveFrameChar = reciveFrame.ToCharArray();

            byte[] reciveFrameByte = new byte[reciveFrameChar.Length];

            for (int i = 0x00; i < reciveFrameByte.Length; i++)
            {
                reciveFrameByte[i] = Convert.ToByte(reciveFrameChar[i]);
            }

            //Check frame
            if ((reciveFrameByte[0] == 0x01) && (reciveFrameByte[1] == 0x73) &&
                (reciveFrameByte[4] == (byte)'E') && (reciveFrameByte[5] == (byte)'1') &&
                (getBCC(reciveFrameByte, reciveFrameByte.Length - 0x01) == reciveFrameByte[reciveFrameByte.Length - 0x01]))
            {

                int start = 0x07;
                int end = reciveFrameByte.Length - 0x02;

                return reciveFrame.Substring(start, end - start); //Get Data

            }
            else
                return String.Empty;

        }


        /// <summary>
        ///Prepare EPSO 2 function - Read Card Buffer (0xA1)
        /// |0x01  |0x53 |ID1    |ID2    |'A'    |'1'  |0x02    |0x03   |BCC  |
        /// |0x01  |0x53 |ID1    |ID2    |'A'    |'6'  |0x02    |0x03   |BCC  |
        /// |0x01  |0x53 |ID1    |ID2    |'A'    |'7'  |0x02    |0x03   |BCC  |
        /// </summary>
        /// <param name="epsoId"> Terminal ID</param>
        /// <returns></returns>
        static public String readCardBuffer(Byte epsoId, byte funCode1, byte funCode2 )
        {
            byte[] frame = new byte[10];
            byte[] IdTab = new byte[2];

            frame[0] = 0x01;
            frame[1] = 0x53;                    //'S'

            //Convert id to ascii
            IdTab[0] = (byte)((epsoId & 0xF0)>>0x04);
            IdTab[1] = (byte)(epsoId & 0x0F);

            for(int i =0x00; i< IdTab.Length; i++)
            {
                if(IdTab[i] > 0x09)
                     frame[2 + i] = (byte)(IdTab[i] + (0x41)); //'A'
                else
                    frame[2 + i] = (byte)(IdTab[i] + (0x30)); //'0'                              
            }

            frame[4] = funCode1;                    //'A'
            frame[5] = funCode2;                    //'1'

            frame[6] = 0x02;
            frame[7] = 0x03;

            frame[8] = getBCC(frame, 0x08);     //BCC

            char[] charFrame = new char[frame.Length];

            for (int i = 0x00; i < charFrame.Length; i++)
            {
                charFrame[i] = Convert.ToChar(frame[i]);
            }

            return new string(charFrame);

        }

        
        /// <summary>
        /// Parse answer - EPSO 2  function Read Card Buffer (0xA1)
        /// |0x01  |0x73 |ID1    |ID2    |'A'    |'1'  |0x02 |DATA   |0x03   |BCC  |
        /// |0x01  |0x73 |ID1    |ID2    |'A'    |'6'  |0x02 |DATA   |0x03   |BCC  |
        /// |0x01  |0x73 |ID1    |ID2    |'A'    |'7'  |0x02 |DATA   |0x03   |BCC  |
        /// </summary>
        /// <param name="reciveFrame"> Answer frame</param>
        /// <returns>Card number or empty string</returns>
        static public String getCardBuffer(String reciveFrame, byte funCode1, byte funCode2)
        {
            
            char[] reciveFrameChar = reciveFrame.ToCharArray();

            byte[] reciveFrameByte = new byte[reciveFrameChar.Length];

            for (int i = 0x00; i < reciveFrameByte.Length; i++)
            {
                reciveFrameByte[i] = Convert.ToByte(reciveFrameChar[i]);
            }

            //Check frame
            if ((reciveFrameByte[0] == 0x01) && (reciveFrameByte[1] == 0x73) &&
                (reciveFrameByte[4] == funCode1) && (reciveFrameByte[5] == funCode2) &&
                (getBCC(reciveFrameByte, reciveFrameByte.Length - 0x01) == reciveFrameByte[reciveFrameByte.Length - 0x01]))
            {

                int start = 0x07;
                int end = reciveFrameByte.Length - 0x02;

                return reciveFrame.Substring(start, end - start); //Get Data

            }
            else
                return String.Empty;

        }


        /// <summary>
        /// Parse answer - EPSO 2  
        /// </summary>
        /// <param name="reciveFrame"> Answer frame</param>
        /// <returns>Card number or empty string</returns>
        static public string getAnswer(String reciveFrame, byte funCode1, byte funCode2)
        {
            char[] reciveFrameChar = reciveFrame.ToCharArray();

            byte[] reciveFrameByte = new byte[reciveFrameChar.Length];

            for (int i = 0x00; i < reciveFrameByte.Length; i++)
            {
                reciveFrameByte[i] = Convert.ToByte(reciveFrameChar[i]);
            }

            //Check frame
            if ((reciveFrameByte[0] == 0x01) && (reciveFrameByte[1] == 0x73) &&
                (reciveFrameByte[4] == funCode1) && (reciveFrameByte[5] == funCode2) &&
                (getBCC(reciveFrameByte, reciveFrameByte.Length - 0x01) == reciveFrameByte[reciveFrameByte.Length - 0x01]))
            {

                int start = 0x07;
                int end = reciveFrameByte.Length - 0x02;

                return reciveFrame.Substring(start, end - start); //Get Data

            }
            else
                return String.Empty;

        }

        /// <summary>
        ///Prepare EPSO 2 function - Write Card Code (0x51)
        /// |0x01  |0x53 |ID1    |ID2    |0x5  |0x1  |0x02 | ..   |0x03   |BCC  |
        /// </summary>
        /// <param name="epsoId"> Terminal ID</param>
        /// <returns></returns>
        static public String writeCardCode(byte epsoId, char[] cardCode)
        {
            byte[] frame = new byte[64];
            byte[] IdTab = new byte[2];

            frame[0] = 0x01;
            frame[1] = 0x53;                    //'S'

            //Convert id to ascii
            IdTab[0] = (byte)((epsoId & 0xF0) >> 0x04);
            IdTab[1] = (byte)(epsoId & 0x0F);

            for (int i = 0x00; i < IdTab.Length; i++)
            {
                if (IdTab[i] > 0x09)
                    frame[2 + i] = (byte)(IdTab[i] + (0x41)); //'A'
                else
                    frame[2 + i] = (byte)(IdTab[i] + (0x30)); //'0'                              
            }

            //Function code
            frame[4] = (byte)'5';
            frame[5] = (byte)'1';

            frame[6] = 0x02;

            //Data
            int count = 7;
            for (int i = 0x00; i < cardCode.Length; i++)
            {
                frame[count] = (byte)cardCode[i];
                count++;
            }

          // count++;
            frame[count] = 0x03;
            count++;
            //BCC
            frame[count] = getBCC(frame, count);     //BCC

            char[] charFrame = new char[frame.Length];

            for (int i = 0x00; i < charFrame.Length; i++)
            {
                charFrame[i] = Convert.ToChar(frame[i]);
            }

            return new string(charFrame);

        }
        /// <summary>
        /// Calculate EPSO 2 checksum
        /// </summary>
        /// <param name="buff"></param>
        /// <param name="length"></param>
        /// <returns> checksum</returns>
        static private byte getBCC(byte[] buff, int length)
        {
            byte bcc = 0x00;
            for (int i = 0x00; i < length; i++)
            {
                bcc ^= buff[i];
            }

            bcc |= 0x20;

            return bcc;
        }
    }
}
