package lu.tudor.santec.gecamed.esante.utils.exceptions;

import lu.luxtrust.cryptoti.exceptions.CryptoTI_Exception;
import lu.luxtrust.cryptoti.exceptions.CryptoTI_SessionException;
import lu.tudor.santec.i18n.Translatrix;

/**
 * This exception provides indication and information about an unsuccessful effort to log into a smartcard. It provides besides an error code a general message
 * regarding the error type as well as a more detailed, specific error message.
 * 
 * @author donako
 * 
 * @version <br>
 *          $Log: SmartCardException.java,v $
 *          Revision 1.1  2013-12-24 17:33:15  donak
 *          Changed exception handling to focus assertion related exceptions to gerValidSamlAssertionForPatient()
 *          Included exception handling for SmartCardExceptions
 *          Fixed bug in UserInactivityMonitor which caused inactive sessions
 *          Partially rewrote SamlAssertion to ease and centralize logic
 * Revision 1.5 2013-12-23 18:07:36 donak Stabilized smartcard login - using now the LuxTrust API and should thus
 *          be easily extendible to signing server usage.
 * 
 */

public class SmartCardException extends Exception {

	private static final long serialVersionUID = 6871471938781585876L;

	private int errorCategory = ERROR_CATEGORY_UNKNOWN;
	private int errorCode = -1;

	/** The error code of this exception is currently not grouped in an error category */
	public final static int ERROR_CATEGORY_UNKNOWN = 0;
	/**
	 * The entered password is invalid. The error code itself provides further details about the cause.<br/>
	 * (e.g. invalid length or expired password)
	 */
	public final static int ERROR_CATEGORY_INVALID_PASSWORD = 1;
	/** The smartcard has been blocked due to too many entries of invalid pin codes */
	public final static int ERROR_CATEGORY_SMARTCARD_BLOCKED = 2;
	
	// References to localization strings for error categories
	public final static String MESSAGE_INVALID_PASSWORD = "esante.loginDialog.error.invalidPin";
	public final static String MESSAGE_SMARTCARD_BLOCKED = "esante.loginDialog.error.smartCardBlocked";

	// the following constants are created to make the subsequent code more clean
	public static final int PW_INCORRECT = CryptoTI_SessionException.LTEC_CTI_PW_INCORRECT;
	public static final int PW_INVALID = CryptoTI_SessionException.LTEC_CTI_PW_INVALID;
	public static final int PW_LEN_RANGE = CryptoTI_SessionException.LTEC_CTI_PW_LEN_RANGE;
	public static final int PW_EXPIRED = CryptoTI_SessionException.LTEC_CTI_PW_EXPIRED;
	public static final int PW_LOCKED = CryptoTI_SessionException.LTEC_CTI_PW_LOCKED;

	public SmartCardException(CryptoTI_Exception smartCardException) {
		super(smartCardException.getMessage());
		init(smartCardException.getCode());
	}

	public SmartCardException(int code, String detail) {
		super(detail);

		init(code);
	}

	/**
	 * Determines the error category, the provided error code belongs to. The grouping of several similar error codes to categories eases the treatment of
	 * exceptions with similar cause.
	 * 
	 * @param code
	 *            The error code of the CryptoTI_Exception
	 */
	private void init(int code) {
		if ((code == PW_INCORRECT) || (code == PW_INVALID) || (code == PW_LEN_RANGE) || (code == PW_EXPIRED)) {
			errorCategory = ERROR_CATEGORY_INVALID_PASSWORD;
		} else if (code == PW_LOCKED) {
			errorCategory = ERROR_CATEGORY_SMARTCARD_BLOCKED;
		} else {
			errorCategory = ERROR_CATEGORY_UNKNOWN;
		}

		this.errorCode = code;
	}

	/**
	 * Provides the error category, the code belongs to. Currently, the following error categories are defined:<br/>
	 * <ul>
	 * <li>{@link #ERROR_CATEGORY_INVALID_PASSWORD}</li>
	 * <li>{@link #ERROR_CATEGORY_SMARTCARD_BLOCKED}</li>
	 * <li>{@link #ERROR_CATEGORY_UNKNOWN}</li>
	 * </ul>
	 * 
	 * @return The error category of the exception
	 */
	public int getCategory() {
		return errorCategory;
	}

	/**
	 * Provides the error code of this exception. Error codes are defined in {@link CryptoTI_Exception} and its descendants.
	 * @return The error code
	 */
	public int getCode() {
		return errorCode;
	}

	/**
	 * Provides a message that describes the category of the error. If the category of a specific error is not known, the same text like for the error detail is
	 * provided. In contrary to the error detail text that originates from the initial error message, the error category message is localized.
	 * 
	 * @return The localized message describing the error category of the exception or the same like {@link #getDetail()} if the exception is not assigned to an
	 *         error category.
	 */
	public String getMessage() {
		switch (errorCategory) {
		case ERROR_CATEGORY_INVALID_PASSWORD:
			return Translatrix.getTranslationString(MESSAGE_INVALID_PASSWORD);

		case ERROR_CATEGORY_SMARTCARD_BLOCKED:
			return Translatrix.getTranslationString(MESSAGE_SMARTCARD_BLOCKED);

		default:
			return getDetail();
		}
	}

	/**
	 * Provides an error message that is specific to the error code of this exception. It is usually more specific than {@link #getMessage()} however not
	 * localized.
	 * 
	 * @return The error detail message
	 */
	public String getDetail() {
		return super.getMessage();
	}
}
