/*
 * Commons eID Project.
 * Copyright (C) 2008-2013 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * 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 GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

package test.integ.be.fedict.commons.eid.client.simulation;

import java.util.Random;
import javax.smartcardio.CardException;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;

public class ErrorCapableBeIdCard extends SimulatedBeIDCard {
	protected static final ResponseAPDU WAITWAITWAIT = new ResponseAPDU(
			new byte[]{0x6c, (byte) 0x00});
	protected static final ResponseAPDU WHO_AM_I = new ResponseAPDU(new byte[]{
			(byte) 0x6d, (byte) 0x00});

	private boolean nextTooFast;
	private boolean nextBitError;
	private boolean nextRandomResponse;
	private boolean nextCardException;
	private boolean nextConfused;
	private int delay;
	private Random random;

	public ErrorCapableBeIdCard(final String profile) {
		this(profile, System.currentTimeMillis());
	}

	public ErrorCapableBeIdCard(final String profile, final long seed) {
		super(profile);
		this.random = new Random(seed);
		this.delay = 0;
	}

	public ErrorCapableBeIdCard introduceTooFastError() {
		this.nextTooFast = true;
		return this;
	}

	public ErrorCapableBeIdCard introduceBitError() {
		this.nextBitError = true;
		return this;
	}

	public ErrorCapableBeIdCard introduceRandomResponse() {
		this.nextRandomResponse = true;
		return this;
	}

	public ErrorCapableBeIdCard introduceCardException() {
		this.nextCardException = true;
		return this;
	}

	public ErrorCapableBeIdCard introduceConfusion() {
		this.nextConfused = true;
		return this;
	}

	public int getDelay() {
		return this.delay;
	}

	public void setDelay(final int delay) {
		this.delay = delay;
	}

	@Override
	protected ResponseAPDU transmit(final CommandAPDU apdu)
			throws CardException {
		if (this.nextConfused) {
			this.nextConfused = false;
			try {
				Thread.sleep(40000);
			} catch (final InterruptedException iex) {
			}
			return WHO_AM_I;
		}

		if (this.nextCardException) {
			this.nextCardException = false;
			throw new CardException("Fake CardException Introduced By "
					+ this.getClass().getName());
		}

		if (this.nextTooFast) {
			this.nextTooFast = false;
			return WAITWAITWAIT;
		}

		if (this.nextRandomResponse) {
			this.nextRandomResponse = false;
			final byte[] randomAPDU = new byte[16];
			this.random.nextBytes(randomAPDU);
			return new ResponseAPDU(randomAPDU);
		}

		if (this.delay > 0) {
			try {
				Thread.sleep(this.delay);
			} catch (final InterruptedException iex) {
			}
		}

		if (this.nextBitError) {
			final ResponseAPDU response = super.transmit(apdu);
			final byte[] responseBytes = response.getBytes();

			// flip some bits
			responseBytes[this.random.nextInt(responseBytes.length)] ^= (byte) this.random
					.nextInt();

			return new ResponseAPDU(responseBytes);
		}

		return super.transmit(apdu);
	}
}
