/* 
 * Copyright 2014 by AVM GmbH <info@avm.de>
 *
 * This software contains free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License ("License") as 
 * published by the Free Software Foundation  (version 3 of the License). 
 * This software is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the copy of the 
 * License you received along with this software for more details.
 */

package de.avm.android.security;

import android.content.Context;
import android.os.Build;

public abstract class CipherWrapper
{

	protected static final int JELLY_BEAN_MR2 = 18;
	
	public enum Type
	{
		NONE, LEGACY, AKS
	}
	
	/**
	 * Returns the most recent type available with Android
	 * version running
	 *
	 **/
	public static Type getDesignatedType () {
		return (Build.VERSION.SDK_INT < JELLY_BEAN_MR2) ?
				Type.LEGACY : Type.AKS;
	}
	
	/**
	 * Creates Instance for most recent type available with Android
	 * version running
	 * 
	 * @param context
	 * 		a context of the app
	 * @param alias
	 * 		Name of key (app can use different keys)
	 * @return
	 * 		instance to be used
     * @throws IllegalArgumentException
     * 		context and/or alias null or empty
     * @throws Exception
     * 		failed to generate or load key 
	 */
	public static CipherWrapper createInstance(Context context, String alias)
	{
		return createInstance(context,
				getDesignatedType(),
				alias);
	}

	/**
	 * Creates Instance for selected type
	 * 
	 * @param context
	 * 		a context of the app
	 * @param alias
	 * 		name of key (app can use different keys)
	 * @return
	 * 		instance to be used
     * @throws IllegalArgumentException
     * 		context and/or alias null/empty or type not avaliable
     * @throws Exception
     * 		failed to generate or load key 
	 */
	public static CipherWrapper createInstance(Context context, Type type, String alias)
	{
		Class<?> clazz = null;
//		Log.e("CipherWrapper","createInstance" + type.toString());
		switch (type)
		{
			case LEGACY:
				try
				{
					clazz = Class.forName("de.avm.android.security.CipherWrapperLegacy");
				}
				catch (ClassNotFoundException e)
				{
					e.printStackTrace();
				}
				break;

			case AKS:
				if (Build.VERSION.SDK_INT < JELLY_BEAN_MR2)
					throw new IllegalArgumentException("Type.AKS needs SDK >= JELLY_BEAN_MR2");
				try
				{
					clazz = Class.forName("de.avm.android.security.CipherWrapperAks");
				}
				catch (ClassNotFoundException e)
				{
					e.printStackTrace();
				}
				break;
			
			default:
				throw new IllegalArgumentException("Argument type not supported");
		}

		if (clazz != null)
		{
			try
			{
				return CipherWrapper.class.cast(clazz
						.getDeclaredConstructor(new Class<?>[] { Context.class, String.class } )
						.newInstance(new Object[] { context, alias }));
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}

		//Log.w(TAG, "Failed to create cipher wrapper");
		return null; 
	}
	
    /**
     * Encrypts plain text
     * 
     * @param plain
     * 		String to be encrypted
     * @return
     * 		printable encrypted bytes
     * @throws Exception
     */
    public abstract String encrypt(String plain) throws Exception;
	
    /**
     * Decrypts printable encrypted bytes
     * 
     * @param encrypted
     * 		String to be decrypted
     * @return
     * 		plain string
     * @throws Exception
     */
    public abstract String decrypt(String encrypted) throws Exception;

    /**
     * Gets type of this instance
     * @return
     */
    public abstract Type getType();
    
	protected CipherWrapper(Context context, String alias) throws Exception
	{
	}
}
