package com.android.dvci;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.HashMap;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import android.content.Context;

import com.android.dvci.auto.Cfg;
import com.android.dvci.util.ByteArray;
import com.android.dvci.util.Check;
import com.android.dvci.util.Utils;

public class MessagesDecrypt {
	private static final String TAG = "MessageDecrypt";

	final HashMap<String, String> messages = new HashMap<String, String>();

	String pack = Status.self().getAppContext().getPackageName();
	
	public MessagesDecrypt(Context context) {

		if (Cfg.DEBUG) {
			Check.asserts(context != null, " (init) Assert failed");
		}

		try {

			if (Cfg.DEBUG) {
				Check.log(TAG + " (MessagesDecrypt)");
			}

			InputStream stream = Utils.getAssetStream("mb.data");

			final SecretKey key = produceKey(Cfg.RNDMSG);

			if (Cfg.DEBUG) {
				Check.asserts(key != null, "null key"); //$NON-NLS-1$
			}

			if (Cfg.DEBUG) {

				Check.log(TAG + " (init): key=" + ByteArray.byteArrayToHex(key.getEncoded()));
			}

			final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //$NON-NLS-1$
			final byte[] iv = new byte[16];
			Arrays.fill(iv, (byte) 0);
			final IvParameterSpec ivSpec = new IvParameterSpec(iv);

			cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
			
			final CipherInputStream cis = new CipherInputStream(stream, cipher);
			final BufferedReader br = new BufferedReader(new InputStreamReader(cis));

			while (true) {
				final String line = br.readLine();
				if (line == null) {
					break;
				}

				final String[] kv = line.split("=", 2);
				if (Cfg.DEBUG) {
					Check.asserts(kv.length == 2, "wrong number of tokens"); //$NON-NLS-1$
					//Check.log(TAG + " " + kv[0] + " " + kv[1]); //$NON-NLS-1$ //$NON-NLS-2$
				}
				
				String value = kv[1].replace("$PACK$", pack);
				messages.put(kv[0], value);

				if (Cfg.DEBUG) {
					Check.asserts(messages.containsKey(kv[0]), "strange hashmap behaviour"); //$NON-NLS-1$
				}
			}
			
			if (Cfg.DEBUG) {
				Check.log(TAG + " (MessagesDecrypt), messages.size: " + messages.size());
			}

		} catch (final Exception ex) {
			if (Cfg.EXCEPTION) {
				Check.log(TAG + " Exception");
				Check.log(ex);
			}
		}
	}

	public static SecretKey produceKey(String key) {

		try {
			if (Cfg.DEBUG) {
				Check.log(" key: " + key + " " + key.length()); //$NON-NLS-1$
			}

			final String salt = Cfg.RANDOM;

			final MessageDigest digest = MessageDigest.getInstance("SHA-1");

			for (int i = 0; i < 128; i++) {
				digest.update(salt.getBytes());
				digest.update(key.getBytes());
				digest.update(digest.digest());
			}

			final byte[] sha1 = digest.digest();

			final byte[] aes_key = new byte[16];
			System.arraycopy(sha1, 0, aes_key, 0, aes_key.length);

			final SecretKey secret = new SecretKeySpec(aes_key, "AES");
			if (Cfg.DEBUG) {
				Check.log(" produced key: " + ByteArray.byteArrayToHex(aes_key)); //$NON-NLS-1$
			}

			return secret;
		} catch (final Exception e) {
			if (Cfg.EXCEPTION) {
				Check.log(e);
			}

			if (Cfg.DEBUG) {
				Check.log(TAG + " " + e); //$NON-NLS-1$
			}

			return null;
		}

	}

	public HashMap<String, String> getMessages() {
		return messages;
	}
}
