package com.cryptomemo.aes_crypto;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatButton;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;

import com.cryptomemo.aeswithintegrity.R;
import com.cryptomemo.crypto.android.AESCrypt;
import com.cryptomemo.crypto.android.AesCbcWithIntegrity;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;

import static com.cryptomemo.crypto.android.AesCbcWithIntegrity.decryptString;
import static com.cryptomemo.crypto.android.AesCbcWithIntegrity.encrypt;
import static com.cryptomemo.crypto.android.AesCbcWithIntegrity.generateKeyFromPassword;
import static com.cryptomemo.crypto.android.AesCbcWithIntegrity.generateSalt;
import static com.cryptomemo.crypto.android.AesCbcWithIntegrity.saltString;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    public static final String TAG = "CryptoMemo";

    private TextView whats_this;
    private TextView ivinfo;
    private TextView inputKey;
    private TextView inpuText;
    private TextView resultText;
    private TextView bitSize;
    private TextView charSize;
    private AppCompatButton encrypt;
    private AppCompatButton decrypt;
    private AppCompatButton clipboardcipher;
    private AppCompatButton clipboardplain;
    private TextView plainText;
    private CheckBox checkboxIv;

    private int keyBitLenght;
    private int textCharLenght;
    private int resultCharLenght;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private void initViews() {
        whats_this = (TextView) findViewById(R.id.whats_this);
        ivinfo = (TextView) findViewById(R.id.ivinfo);
        inputKey = (TextView) findViewById(R.id.inKey);
        inpuText = (TextView) findViewById(R.id.inText);
        resultText = (TextView) findViewById(R.id.txtResult);
        bitSize = (TextView) findViewById(R.id.bit_size);
        charSize = (TextView) findViewById(R.id.char_size);
        encrypt = (AppCompatButton) findViewById(R.id.btEncrypt);
        clipboardcipher = (AppCompatButton) findViewById(R.id.btCipherClip);
        clipboardplain = (AppCompatButton) findViewById(R.id.btPlainClip);
        decrypt = (AppCompatButton) findViewById(R.id.btDecrypt);
        plainText = (TextView) findViewById(R.id.txtPlain);
        checkboxIv = (CheckBox) findViewById(R.id.checkbox_iv);
        TextWatcher keyWatcher = new TextWatcher() {
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            public void onTextChanged(CharSequence s, int start, int before, int count) {
                try {
                    keyBitLenght = (String.valueOf(s).getBytes("UTF-8").length) * 8;
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                bitSize.setText(String.valueOf(keyBitLenght));
                bitSize.setTextColor(getApplicationContext().getResources().getColor(keyBitLenght > 256 ? android.R.color.holo_green_light : R.color.grey));
            }

            public void afterTextChanged(Editable s) {
            }
        };
        TextWatcher textWatcher = new TextWatcher() {
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            public void onTextChanged(CharSequence s, int start, int before, int count) {
                textCharLenght = s.length();
                charSize.setText(String.valueOf(textCharLenght));
                charSize.setTextColor(getApplicationContext().getResources().getColor(textCharLenght > 15 ? android.R.color.holo_orange_light : R.color.grey));
            }

            public void afterTextChanged(Editable s) {
            }
        };
        whats_this.setOnClickListener(this);
        ivinfo.setVisibility(View.GONE);
        encrypt.setOnClickListener(this);
        clipboardcipher.setOnClickListener(this);
        clipboardcipher.setVisibility(View.GONE);
        clipboardplain.setOnClickListener(this);
        clipboardplain.setVisibility(View.GONE);
        decrypt.setOnClickListener(this);
        plainText.setVisibility(View.GONE);
        inputKey.addTextChangedListener(keyWatcher);
        inpuText.addTextChangedListener(textWatcher);
    }


    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btEncrypt:
                encryptData();
                break;
            case R.id.btDecrypt:
                decryptData();
                break;
            case R.id.btCipherClip:
                copyTextToClipBoard(resultText.getText().toString());
                Toast.makeText(getApplicationContext(), R.string.text_copied, Toast.LENGTH_LONG).show();
                break;
            case R.id.btPlainClip:
                copyTextToClipBoard(plainText.getText().toString());
                Toast.makeText(getApplicationContext(), R.string.text_copied, Toast.LENGTH_LONG).show();
                break;
            case R.id.whats_this:
                if (ivinfo.getVisibility() == View.VISIBLE) {
                    ivinfo.setVisibility(View.GONE);
                } else {
                    ivinfo.setVisibility(View.VISIBLE);
                }
                //Toast.makeText(getApplicationContext(), R.string.text_dencrypted, Toast.LENGTH_LONG).show();
                break;
            default:
                throw new RuntimeException("Unknown button ID");
        }
    }

    private void encryptData() {
        String inputKeyText = inputKey.getText().toString().trim();
        String textToEncrypt = inpuText.getText().toString().trim();

        if (keyBitLenght != 0 && keyBitLenght != 8) {
            if (textCharLenght != 0) {
                if (checkboxIv.isChecked()) {
                    fullEncryption(inputKeyText, textToEncrypt);
                } else {
                    shortEncryption(inputKeyText, textToEncrypt);
                }
            } else if (textCharLenght == 0) {
                    Toast.makeText(getApplicationContext(), R.string.fill_text_field, Toast.LENGTH_LONG).show();
            }
        } else if (keyBitLenght == 0 || keyBitLenght == 8) {
                Toast.makeText(getApplicationContext(), R.string.fill_key_field, Toast.LENGTH_LONG).show();
        }

    }

    private void decryptData() {
        String inputKeyText = inputKey.getText().toString().trim();
        String textToDecrypt = resultText.getText().toString().trim();
        resultCharLenght = resultText.length();


        if (keyBitLenght != 0 && keyBitLenght != 8) {
            if (resultCharLenght != 0 ) {
                if (checkboxIv.isChecked()) {
                    fullDecryption(inputKeyText, textToDecrypt);
                } else {
                    if(textToDecrypt.contains(":")) {
                        fullDecryption(inputKeyText, textToDecrypt);
                    } else {
                        shortDecryption(inputKeyText, textToDecrypt);
                    }
                }
            } else if (resultCharLenght == 0) {
                    Toast.makeText(getApplicationContext(), R.string.fill_plaintext_field, Toast.LENGTH_LONG).show();
            }
        } else if (keyBitLenght == 0 || keyBitLenght == 8) {
                Toast.makeText(getApplicationContext(), R.string.fill_key_field, Toast.LENGTH_LONG).show();
        }

    }

    private void fullEncryption(String inputKeyText, String textToEncrypt) {
        // TODO: 1/31/2017 Here i left explenation of - why i made double password
        /*
        String salt = saltString(generateSalt()); - here we are making function generateSalt(), each time we doing this ,
        we generate every time a unique salt, that mean we need to remmember password + salt, because later to generate a key for encryption
        we use salt + password combination.

      If we open (generateSalt()) we will see:
        public static byte[] generateSalt() throws GeneralSecurityException {
        return randomBytes(PBE_SALT_LENGTH_BITS); - here we generating a 128 byte array, and every time it will be another array,
        that mean if we will encrypt some text with salt + password, to decrypt this text we will need same salt and same password,
        but salt is generated randomly and will be different next time you will generate it.(for example during decoding)
    }
        it describes in short - why is salt needed
        https://en.wikipedia.org/wiki/Salt_(cryptography)

        AesCbcWithIntegrity.SecretKeys key = generateKeyFromPassword("your password entered via edittext", salt); - here we generate key (pass+salt)
        AesCbcWithIntegrity.CipherTextIvMac civ = encrypt(textToEncrypt, key); - here we encrypt text(text + key)

        good practice - every time generate new salt ad save it.
        you want to use AesCbcWithIntegrity.class for enctiption, and it have only one function encrypt(salt+pass, text to encrypt),
        we do not store salt nowhere, so i decided to use password again instead of salt, little bit strange, not actually more safe than
        salt + pass, but more unique.

        */
        try {
            AesCbcWithIntegrity.SecretKeys key = generateKeyFromPassword(inputKeyText, inputKeyText);
            AesCbcWithIntegrity.CipherTextIvMac civ = encrypt(textToEncrypt, key);
            resultText.setText(civ.toString());
            clipboardcipher.setVisibility(View.VISIBLE);
            clipboardplain.setVisibility(View.GONE);
            Toast.makeText(getApplicationContext(), R.string.text_encrypted, Toast.LENGTH_LONG).show();
        } catch (GeneralSecurityException e) {
            Log.e(TAG, "GeneralSecurityException", e);
        } catch (UnsupportedEncodingException e) {
            Log.e(TAG, "UnsupportedEncodingException", e);
        }
    }

    private void shortEncryption(String inputKeyText, String textToEncrypt) {
        try {
            String result = AESCrypt.encrypt(inputKeyText, textToEncrypt);
            resultText.setText(result);
            clipboardcipher.setVisibility(View.VISIBLE);
            clipboardplain.setVisibility(View.GONE);
            Toast.makeText(getApplicationContext(), R.string.text_encrypted, Toast.LENGTH_LONG).show();
        } catch (GeneralSecurityException e) {
            Log.e(TAG, "GeneralSecurityException", e);
        }
    }

    private void fullDecryption(String inputKeyText, String textToDecrypt) {
        try {
            AesCbcWithIntegrity.SecretKeys key = generateKeyFromPassword(inputKeyText, inputKeyText);
            AesCbcWithIntegrity.CipherTextIvMac civ = new AesCbcWithIntegrity.CipherTextIvMac(textToDecrypt);
            String decryptedText = decryptString(civ, key);
            plainText.setText(decryptedText.toString());
            plainText.setVisibility(View.VISIBLE);
            clipboardcipher.setVisibility(View.GONE);
            clipboardplain.setVisibility(View.VISIBLE);
            Toast.makeText(getApplicationContext(), R.string.text_decrypted, Toast.LENGTH_LONG).show();
        } catch (GeneralSecurityException e) {
            Log.e(TAG, "GeneralSecurityException", e);
        } catch (UnsupportedEncodingException e) {
            Log.e(TAG, "UnsupportedEncodingException", e);
        }
    }

    private void shortDecryption(String inputKeyText, String textToDecrypt) {
        try {
            String result = AESCrypt.decrypt(inputKeyText, textToDecrypt);
            plainText.setText(result);
            plainText.setVisibility(View.VISIBLE);
            clipboardcipher.setVisibility(View.GONE);
            clipboardplain.setVisibility(View.VISIBLE);
            Toast.makeText(getApplicationContext(), R.string.text_decrypted, Toast.LENGTH_LONG).show();
        } catch (GeneralSecurityException e) {
            Log.e(TAG, "GeneralSecurityException", e);
        }
    }

    private void copyTextToClipBoard(String text) {
        ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
        ClipData clip = ClipData.newPlainText("memo", text);
        clipboard.setPrimaryClip(clip);
    }

}
