using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace SuperCryptEX
{
    public partial class AESForm : Form
    {
        private const int BLOCK_SIZE = (128 / 8);
        private const int KEY_SIZE = (256 / 8);

        // Parameter - Options (Encrypt/Decrypt)
        private enum Options
        {
            Encrypt = 0,
            Decrypt,
        };

        private enum ErrorID
        {
            NullFilePath = 0,
            NUllFileSave,
            NullPWD,
            OtherError,
            Success,
        };
        private string[] ErrorString = new string[]{
            "No File Selected",
            "No File Saved",
            "No Password Input",
            "Other Error",
            "OK"};

        private Class_General g = new Class_General();
        private Options optAESEnDe = Options.Encrypt;
        private string inputPath;

        public AESForm()
        {
            InitializeComponent();
        }

        // ------------------------------------------------------------
        // AES Test Area - Functions
        // ------------------------------------------------------------
        #region AES Test Area - Functions

        private ErrorID CheckParam()
        {
            if ("" == text_aestest_input.Text)
            {
                return ErrorID.NullFilePath;
            }

            if ("" == text_aestest_output.Text)
            {
                return ErrorID.NUllFileSave;
            }

            if ("" == text_aestest_password.Text)
            {
                return ErrorID.NullPWD;
            }

            return ErrorID.Success;
        }

        private string GetErrorString(ErrorID errorID)
        {
            int iIndex = (int)(errorID);

            return ErrorString[iIndex];
        }

        private void AES_InitializeByte(byte[] pByte, int iLength)
        {
            int iIndex = 0;
            for (iIndex = 0; iIndex < iLength; iIndex++)
            {
                pByte[iIndex] = 0;
            }
        }

        private bool Encrypt(string inputFile, string outputFile, string password)
        {
            // Check Param
            if ((inputFile == "") || (outputFile == "") || (password == ""))
            {
                return false;
            }

            if (false == g.fileIsExist(inputFile))
            {
                return false;
            }

            while (true == g.fileIsExist(outputFile))
            {
                outputFile = g.renameIfNameAlreadyExists(outputFile);
            }

            byte[] plainText = new byte[BLOCK_SIZE];
            byte[] cipherText = new byte[BLOCK_SIZE];
            byte[] keyText = new byte[KEY_SIZE];

            // Get Password
            keyText = Encoding.ASCII.GetBytes(password);

            // Get Bytes from File
            FileStream fileStream = new FileStream(inputFile, FileMode.Open);
            fileStream.Seek(0, SeekOrigin.Begin);

            // Create File Stream for Output File
            FileStream saveStream = new FileStream(outputFile, FileMode.Append);

            // Set Length of the File
            long lFileLength = fileStream.Length;

            // Set Position of the File
            long lPostion = fileStream.Position;

            // Read File Every 16 Byte and Encrypt
            while (lPostion < lFileLength)
            {
                // Initialize Plain Buffer
                AES_InitializeByte(plainText, BLOCK_SIZE);

                long lHasRead = fileStream.Read(plainText, 0, BLOCK_SIZE);
                if (0 >= lHasRead)
                {
                    break;
                }
                // Set Current Cursor Position
                lPostion = fileStream.Position;

                // Encrypt
                Class_AES aes = new Class_AES(BlockSize.Bit_256, keyText, BlockSize.Bit_128);

                // Initialize Cipher Buffer
                AES_InitializeByte(cipherText, BLOCK_SIZE);

                aes.Go_Encrypt(plainText, cipherText);

                saveStream.Write(cipherText, 0, BLOCK_SIZE);
            }

            saveStream.Close();
            fileStream.Close();

            return true;
        }

        private bool Decrypt(string inputFile, string outputFile, string password)
        {
            // Check Param
            if (("" == inputFile) || ("" == outputFile) || ("" == password))
            {
                return false;
            }

            if (0 > inputFile.LastIndexOf(".aes"))
            {
                return false;
            }

            if (false == g.fileIsExist(inputFile))
            {
                return false;
            }

            while (true == g.fileIsExist(outputFile))
            {
                outputFile = g.renameIfNameAlreadyExists(outputFile);
            }

            byte[] encryptedText = new byte[BLOCK_SIZE];
            byte[] decryptedText = new byte[BLOCK_SIZE];
            byte[] keyText = new byte[KEY_SIZE];

            // Get Password
            keyText = Encoding.ASCII.GetBytes(password);

            // Get Bytes from File
            FileStream fileStream = new FileStream(inputFile, FileMode.Open);
            fileStream.Seek(0, SeekOrigin.Begin);

            // Create File Stream for Output File
            FileStream saveStream = new FileStream(outputFile, FileMode.Append);

            // Set Length of the File
            long lFileLength = fileStream.Length;

            // Set Position of the File
            long lPostion = fileStream.Position;

            // Read File Every 16 Byte and Decrypt
            while (lPostion < lFileLength)
            {
                // Initialize Encrypted Buffer
                AES_InitializeByte(encryptedText, BLOCK_SIZE);

                long lHasRead = fileStream.Read(encryptedText, 0, BLOCK_SIZE);
                if (0 >= lHasRead)
                {
                    break;
                }
                //set current cursor position
                lPostion = fileStream.Position;

                // Decrypt
                Class_AES aes = new Class_AES(BlockSize.Bit_256, keyText, BlockSize.Bit_128);

                // Initialize Decrypted Buffer
                AES_InitializeByte(decryptedText, BLOCK_SIZE);

                aes.Go_Decrypt(encryptedText, decryptedText);

                saveStream.Write(decryptedText, 0, BLOCK_SIZE);
            }

            saveStream.Close();
            fileStream.Close();

            return true;
        }

        #endregion

        // ------------------------------------------------------------
        // AES Test Area - Components
        // ------------------------------------------------------------
        #region AES Test Area - Components

        private void button_aestest_browse_Click(object sender, EventArgs e)
        {
            OpenFileDialog fileBrowser = new OpenFileDialog();
            fileBrowser.Title = "SuperCryptEX - Browse File";

            // If Mode = Encrypt
            if (optAESEnDe == Options.Encrypt)
            {
                fileBrowser.Filter = "All File|*.*";
                if (fileBrowser.ShowDialog() == DialogResult.OK)
                {
                    inputPath = fileBrowser.FileName;
                    text_aestest_input.Text = inputPath;
                    text_aestest_output.Text = inputPath + ".aes";

                    // Cek Jika File > 10240 KB (10 MB)
                    FileInfo fileInfo = new FileInfo(inputPath);
                    // File Size Default : Bytes
                    double fileLength_KB = fileInfo.Length / Math.Pow(1024, 1);
                    if (fileLength_KB > 10240)
                    {
                        MessageBox.Show("The File That You Choose is Too Large and It will Take a Long Time to Process! (This is Just a Warning)\n" +
                            "File Size : " + String.Format("{0:n}", fileLength_KB) + " KB\n" +
                            "(Expected Time : " + Math.Truncate(fileLength_KB * 0.0004).ToString() + "s)",
                            "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    }
                }
            }
            // If Mode = Decrypt
            else
            {
                fileBrowser.Filter = "AES File|*.aes";
                if (DialogResult.OK == fileBrowser.ShowDialog())
                {
                    inputPath = fileBrowser.FileName;
                    string encryptedName = inputPath;
                    text_aestest_input.Text = encryptedName;
                    int dotLastIndex = encryptedName.LastIndexOf(".");
                    string originalName = encryptedName.Substring(0, dotLastIndex);
                    text_aestest_output.Text = originalName;
                }
            }
        }

        private void button_aestest_save_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveBrowser = new SaveFileDialog();
            saveBrowser.Title = "SuperCryptEX - Save To";

            // If Mode = Encrypt
            if (optAESEnDe == Options.Encrypt)
            {
                saveBrowser.Filter = "AES File|*.aes";
            }
            // If Mode = Decrypt
            else
            {
                saveBrowser.Filter = "All File|*.*";
            }

            DialogResult dialogResult = saveBrowser.ShowDialog();
            // Cek Apakah Nama File Bukan Empty String
            string fileName = saveBrowser.FileName;
            if (("" != fileName) && (dialogResult == DialogResult.OK))
            {
                text_aestest_output.Text = fileName;
            }
        }

        private void radio_aestest_encrypt_CheckedChanged(object sender, EventArgs e)
        {
            inputPath =
                text_aestest_input.Text =
                text_aestest_output.Text =
                text_aestest_password.Text =
                "";
            optAESEnDe = Options.Encrypt;
        }

        private void radio_aestest_decrypt_CheckedChanged(object sender, EventArgs e)
        {
            inputPath =
                text_aestest_input.Text =
                text_aestest_output.Text =
                text_aestest_password.Text =
                "";
            optAESEnDe = Options.Decrypt;
        }

        private void button_aestest_start_Click(object sender, EventArgs e)
        {
            // Check Param
            ErrorID errorID = CheckParam();
            if (ErrorID.Success != errorID)
            {
                string errorString = GetErrorString(errorID);
                MessageBox.Show(errorString, "SuperCryptEX");
                return;
            }

            // Get Param
            string cOpenFile = text_aestest_input.Text;
            string cSaveFile = text_aestest_output.Text;
            string cPassword = text_aestest_password.Text;

            if (Options.Encrypt == optAESEnDe)
            {
                bool bValue = Encrypt(cOpenFile, cSaveFile, cPassword);
                if (false == bValue)
                {
                    MessageBox.Show("Encrypt Fail!", "SuperCryptEX");
                    return;
                }
                else
                {
                    MessageBox.Show("Encrypt Success!", "SuperCryptEX");
                }
            }
            else
            {
                bool bValue = Decrypt(cOpenFile, cSaveFile, cPassword);
                if (false == bValue)
                {
                    MessageBox.Show("Decrypt Fail!", "SuperCryptEX");
                    return;
                }
                else
                {
                    MessageBox.Show("Decrypt Success!", "SuperCryptEX");
                }
            }
        }

        #endregion

    }
}
