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

namespace RogerRud.RUD
{
    class Epso
    {
        //|HEADER	                                        |DATA	                |CHECK      |
        //|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 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>
        ///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, byte[] 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] = 0x5;       
            frame[5] = 0x1;       

            frame[6] = 0x02;

            //Data
            int count = 7;
            for (int i = 0x00; i < cardCode.Length; i++)
            {
                byte[] ascii = new byte[2];
                //Convert id to ascii
                ascii[0] = (byte)((cardCode[i] & 0xF0) >> 0x04);
                ascii[1] = (byte)(cardCode[i] & 0x0F);

                for (int y = 0; y < ascii.Length; y++)
                {
                    if (ascii[y] > 0x09)
                        frame[count] = (byte)(ascii[y] + (0x41)); //'A'
                    else
                        frame[count] = (byte)(ascii[y] + (0x30)); //'0'       

                    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>
        /// 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>
        ///Prepare EPSO 2 function - output on
        /// |0x01  |0x53 |ID1    |ID2    |'b'    |'1'  |0x02  |'2'|'5'|'5'|0x03   |BCC  |
        /// |0x01  |0x53 |ID1    |ID2    |'c'    |'1'  |0x02  |'2'|'5'|'5'|0x03   |BCC  |
        /// |0x01  |0x53 |ID1    |ID2    |'d'    |'1'  |0x02  |'2'|'5'|'5'|0x03   |BCC  |
        /// |0x01  |0x53 |ID1    |ID2    |'d'    |'5'  |0x02  |'2'|'5'|'5'|0x03   |BCC  |
        /// </summary>
        /// <param name="epsoId"> Terminal ID</param>
        /// <returns></returns>
        static public String OutputON(Byte epsoId, byte funCode1, byte funCode2)
        {
            byte[] frame = new byte[12];
            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;                    //'b'
            frame[5] = funCode2;                    //'1'

            frame[6] = 0x02;
            frame[7] = (byte)'2';
            frame[8] = (byte)'5';
            frame[9] = (byte)'5';
            frame[10] = 0x03;

            frame[11] = getBCC(frame, 0x0B);     //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>
        ///Prepare EPSO 2 function - output off
        /// |0x01  |0x53 |ID1    |ID2    |'b'    |'0'  |0x02  |'2'|'5'|'5'|0x03   |BCC  |
        /// |0x01  |0x53 |ID1    |ID2    |'c'    |'0'  |0x02  |'2'|'5'|'5'|0x03   |BCC  |
        /// |0x01  |0x53 |ID1    |ID2    |'d'    |'0'  |0x02  |'2'|'5'|'5'|0x03   |BCC  |
        /// |0x01  |0x53 |ID1    |ID2    |'d'    |'4'  |0x02  |'2'|'5'|'5'|0x03   |BCC  |
        /// </summary>
        /// <param name="epsoId"> Terminal ID</param>
        /// <returns></returns>
        static public String OutputOff(Byte epsoId, byte funCode1, byte funCode2)
        {
            byte[] frame = new byte[9];
            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;                    //'b'
            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  
        /// </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>
        /// 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;
        }
    }
}
