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

namespace CrossProduct.Core
{
    public class DataEncryption
    {
        #region Encrypt
        #region Encrypt String
        public static string EncryptString(string EncryptString)
        {
            return DataEncryption.EncryptBinary(SimpleStringBinaryConverter.GetBytes(EncryptString));
        }
        #endregion

        #region Encrypt Binary
        public static string EncryptBinary(byte[] EncryptBuffer)
        {
            int lStringLen = EncryptBuffer.Length;
            int lAdjust = 17;
            int nIndex;
            int lMid;
            int lTemp;
            byte cTemp;
            byte cXor;

            lTemp = lStringLen;
            cXor = (byte)(0x59 ^ (byte)lStringLen);

            lMid = lStringLen;
            lMid -= lMid % 2;
            lMid = lMid / 2;
            lTemp = lMid;

            // "scramble" the original before encrypting
            // inverse the left half
            for (nIndex = lTemp - 1; nIndex >= 0 && nIndex >= lTemp - nIndex - 1; nIndex--)
            {
                cTemp = EncryptBuffer[nIndex];
                EncryptBuffer[nIndex] = EncryptBuffer[lTemp - nIndex - 1];
                EncryptBuffer[lTemp - nIndex - 1] = cTemp;
            }

            // inverse the left half
            for (nIndex = lTemp - 1; nIndex >= 0 && nIndex >= lTemp - nIndex - 1; nIndex--)
            {
                cTemp = EncryptBuffer[lStringLen - lTemp + nIndex];
                EncryptBuffer[lStringLen - lTemp + nIndex] = EncryptBuffer[lStringLen - nIndex - 1];
                EncryptBuffer[lStringLen - nIndex - 1] = cTemp;
            }

            // encrypt individual values from the center out
            // i.e. Center, Center + 1, Center - 1, Center + 2, Center - 2, etc...
            for (nIndex = 1; ; nIndex++)
            {
                if (nIndex % 2 != 0)
                {
                    lTemp = lMid + (nIndex - 1) / 2;
                    if (lTemp >= lStringLen)
                        continue;
                }
                else
                {
                    lTemp = lMid - nIndex / 2;
                    if (lTemp < 0)
                        break;
                }

                cTemp = EncryptBuffer[lTemp];
                EncryptBuffer[lTemp] = (byte)(EncryptBuffer[lTemp] ^ cXor);
                if (EncryptBuffer[lTemp] == 0)
                    EncryptBuffer[lTemp] = (byte)(EncryptBuffer[lTemp] ^ cXor);

                lAdjust += 17 + cXor;
                lTemp = lAdjust + cXor + cTemp + EncryptBuffer[lTemp];
                cXor = (byte)((byte)lTemp % 223);
            }

            return BinaryEncoder.BinaryToString(EncryptBuffer);
        }
        #endregion
        #endregion

        #region Decrypt
        #region Decrypt String
        public static string DecryptString(string EncryptString)
        {
            byte[] EncryptBuffer = DataEncryption.DecryptBinary(EncryptString);

            return SimpleStringBinaryConverter.GetString(EncryptBuffer);
        }
        #endregion

        #region Decrypt Binary

        public static byte[] DecryptBinary(string EncryptString)
        {
            byte[] EncryptBuffer = BinaryEncoder.StringToBinary(EncryptString);
            return DecryptBinary(EncryptBuffer);
        }

        public static byte[] DecryptBinary(byte[] EncryptBuffer)
        {            
            int lStringLen = EncryptBuffer.Length;
            int lAdjust = 17;
            int nIndex;
            int lMid;
            int lTemp;
            byte cTemp;
            byte cXor;

            lTemp = lStringLen;
            cXor = (byte)(0x59 ^ (byte)lStringLen);

            lMid = lStringLen;
            lMid -= lMid % 2;
            lMid = lMid / 2;

            for (nIndex = 1; ; nIndex++)
            {
                if (nIndex % 2 != 0)
                {
                    lTemp = lMid + (nIndex - 1) / 2;
                    if (lTemp >= lStringLen)
                        continue;
                }
                else
                {
                    lTemp = lMid - nIndex / 2;
                    if (lTemp < 0)
                        break;
                }

                cTemp = EncryptBuffer[lTemp];
                EncryptBuffer[lTemp] = (byte)(EncryptBuffer[lTemp] ^ cXor);
                if (EncryptBuffer[lTemp] == 0)
                    EncryptBuffer[lTemp] = (byte)(EncryptBuffer[lTemp] ^ cXor);

                lAdjust += 17 + cXor;
                lTemp = lAdjust + cXor + cTemp + EncryptBuffer[lTemp];
                cXor = (byte)((byte)lTemp % 223);
            }

            lTemp = lMid;
            for (nIndex = lTemp - 1; nIndex >= 0 && nIndex >= lTemp - nIndex - 1; nIndex--)
            {
                cTemp = EncryptBuffer[nIndex];
                EncryptBuffer[nIndex] = EncryptBuffer[lTemp - nIndex - 1];
                EncryptBuffer[lTemp - nIndex - 1] = cTemp;
            }

            for (nIndex = lTemp - 1; nIndex >= 0 && nIndex >= lTemp - nIndex - 1; nIndex--)
            {
                cTemp = EncryptBuffer[lStringLen - lTemp + nIndex];
                EncryptBuffer[lStringLen - lTemp + nIndex] = EncryptBuffer[lStringLen - nIndex - 1];
                EncryptBuffer[lStringLen - nIndex - 1] = cTemp;
            }

            return EncryptBuffer;
        }

        #endregion
        #endregion
    }
}
