package com.genymotion.binocle;


import android.app.Activity;
import android.os.Bundle;
import android.provider.Settings.Secure;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.io.*;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class IdSampleFragment extends Fragment implements View.OnClickListener{
    public static final String TAG = "Id";

    public static final String SECRET_MESSAGE = "Genymotion ♥ developpers!";
    private static final String FILE_NAME = "encrypted_data";
    private final Charset UTF8_CHARSET = Charset.forName("UTF-8");

    private TextView tvAndroidId;

    private final byte[] salt = {
            (byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef,
            (byte) 0xba, (byte) 0xad, (byte) 0xca, (byte) 0xfe
    };

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_id_sample, container, false);

        tvAndroidId = (TextView) rootView.findViewById(R.id.tv_androidId);
        String androidId = Secure.getString(getActivity().getContentResolver(), Secure.ANDROID_ID);
        tvAndroidId.setText(getActivity().getResources().getString(R.string.android_id, androidId));
        View btnEncode = rootView.findViewById(R.id.btn_encode);
        btnEncode.setOnClickListener(this);
        View btnDecode = rootView.findViewById(R.id.btn_decode);
        btnDecode.setOnClickListener(this);

        return rootView;
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.btn_encode) {
            doEncode();
        } else if (view.getId() == R.id.btn_decode) {
            doDecode();
        }
    }

    private void doEncode() {
        try {
            // Set up secret key spec for 128-bit AES encryption
            String androidId = Secure.getString(getActivity().getContentResolver(), Secure.ANDROID_ID);
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec spec = new PBEKeySpec(androidId.toCharArray(), salt, 45, 128);
            SecretKeySpec sks = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");

            // Create AES cipher
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, sks);

            // This stream write the encrypted text.
            FileOutputStream fos = getActivity().openFileOutput(FILE_NAME, Activity.MODE_PRIVATE);
            // Wrap the output stream
            CipherOutputStream cos = new CipherOutputStream(fos, cipher);

            // Write bytes
            cos.write(SECRET_MESSAGE.getBytes(UTF8_CHARSET));

            // Flush and close streams.
            cos.flush();
            cos.close();
            fos.close();

            tvAndroidId.setText(getActivity().getResources().getString(R.string.encoding_done, androidId));

        } catch (NoSuchPaddingException
                |NoSuchAlgorithmException
                |IOException
                |InvalidKeyException
                |InvalidKeySpecException e) {
            Log.e(TAG, "Unable to encrypt secret", e);
            tvAndroidId.setText(R.string.encoding_failed);
        }
    }

    private void doDecode(){
        try {
            // Set up secret key spec for 128-bit AES decryption
            String androidId = Secure.getString(getActivity().getContentResolver(), Secure.ANDROID_ID);
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec spec = new PBEKeySpec(androidId.toCharArray(), salt, 45, 128);
            SecretKeySpec sks = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");

            // Create AES cipher
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, sks);

            // This stream read the encrypted text.
            FileInputStream fis = getActivity().openFileInput(FILE_NAME);

            // Wrap the input stream
            CipherInputStream cis = new CipherInputStream(fis, cipher);

            // Read and decrypt file
            int size = SECRET_MESSAGE.getBytes(UTF8_CHARSET).length;
            byte[] message = new byte[size];
            int pos = 0;
            int read;
            do {
                read = cis.read(message, pos, size);
                pos += read;
                size -= read;
            } while (read > 0);
            String secret = new String(message, UTF8_CHARSET);
            String label = getActivity().getResources().getString(R.string.decoding_done, secret);
            tvAndroidId.setText(label);

        } catch (NoSuchPaddingException
        | NoSuchAlgorithmException
        | IOException
        | InvalidKeyException
        | InvalidKeySpecException e) {
            Log.e(TAG, "Unable to decrypt secret", e);
            tvAndroidId.setText(R.string.decoding_failed);
        }
    }
}