package anoncard;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import javacard.framework.APDU;
import javacard.framework.ISO7816;
import mixconfig.tools.dataretention.smartcard.ApduConstants;

import org.junit.Test;

public class ANONCardAppletSubTest_ProcessDataChannels extends AbtractANONCardAppletSubTest {

	public ANONCardAppletSubTest_ProcessDataChannels() {
		super();
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)}.
	 */
	@Test
	public void testProcessTransmitDataCount1() {
		byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_DATA_TRANSMISSION;
		apduBuffer[ISO7816.OFFSET_P1] = ApduConstants.INSTRUCTION_NOP; // instruction
		apduBuffer[ISO7816.OFFSET_P2] = (byte) 0x01; // packages
		setAPDUData(data);
		assertProcessResponse(new byte[] {});
		byte[] receivedData = mixconfig.tools.dataretention.smartcard.Helpers.copyOfRange(getDataReceiveChannel().getData(), 0, getDataReceiveChannel().length());
		assertTrue("Transmission is complete", getDataReceiveChannel().isTransmissionComplete());
		assertArrayEquals("Wrong data in DataTransmissionChannel: " + mixconfig.tools.dataretention.smartcard.Helpers.bytesToHexDigits(receivedData), data, receivedData);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)}.
	 */
	@Test
	public void testProcessTransmitDataCount4() {
		byte[] data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		byte[] ack = new byte[] { ApduConstants.DATA_TRANSMISSION_PACKAGE_ACK_MAJOR, ApduConstants.DATA_TRANSMISSION_PACKAGE_ACK_MINOR };

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_DATA_TRANSMISSION;
		apduBuffer[ISO7816.OFFSET_P1] = ApduConstants.INSTRUCTION_NOP; // instruction
		apduBuffer[ISO7816.OFFSET_P2] = (byte) 0x04; // packages
		setAPDUData(mixconfig.tools.dataretention.smartcard.Helpers.copyOfRange(data, 0, 3));
		assertProcessResponse(ack);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_DATA_TRANSMISSION;
		setAPDUData(mixconfig.tools.dataretention.smartcard.Helpers.copyOfRange(data, 3, 3));
		assertProcessResponse(ack);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_DATA_TRANSMISSION;
		setAPDUData(mixconfig.tools.dataretention.smartcard.Helpers.copyOfRange(data, 6, 3));
		assertProcessResponse(ack);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_DATA_TRANSMISSION;
		setAPDUData(mixconfig.tools.dataretention.smartcard.Helpers.copyOfRange(data, 9, 3));

		assertProcessResponse(new byte[] {});
		byte[] receivedData = mixconfig.tools.dataretention.smartcard.Helpers.copyOfRange(getDataReceiveChannel().getData(), 0, getDataReceiveChannel().length());
		assertTrue("Transmission is complete", getDataReceiveChannel().isTransmissionComplete());
		assertArrayEquals("Wrong data in DataTransmissionChannel: " + mixconfig.tools.dataretention.smartcard.Helpers.bytesToHexDigits(receivedData), data, receivedData);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)}.
	 */
	@Test
	public void testProcessTransmitDataCount4WithRestart() {
		byte[] ack = new byte[] { ApduConstants.DATA_TRANSMISSION_PACKAGE_ACK_MAJOR, ApduConstants.DATA_TRANSMISSION_PACKAGE_ACK_MINOR };

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_DATA_TRANSMISSION;
		apduBuffer[ISO7816.OFFSET_P1] = ApduConstants.INSTRUCTION_GET_VERSION; // instruction
		apduBuffer[ISO7816.OFFSET_P2] = (byte) 0x04; // packages
		assertProcessResponse(ack);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_DATA_TRANSMISSION;
		assertProcessResponse(ack);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_DATA_TRANSMISSION;
		apduBuffer[ISO7816.OFFSET_P1] = ApduConstants.INSTRUCTION_GET_VERSION; // instruction
		apduBuffer[ISO7816.OFFSET_P2] = (byte) 0x04; // packages
		assertProcessResponse(ack);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_DATA_TRANSMISSION;
		assertProcessResponse(ack);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_DATA_TRANSMISSION;
		assertProcessResponse(ack);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_DATA_TRANSMISSION;
		assertProcessResponse(new byte[] { ANONCardApplet.APPLET_VERSION_MAJOR, ANONCardApplet.APPLET_VERSION_MINOR });
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)}.
	 */
	@Test
	public void testProcessTransmitDataAbort() {
		byte[] ack = new byte[] { ApduConstants.DATA_TRANSMISSION_PACKAGE_ACK_MAJOR, ApduConstants.DATA_TRANSMISSION_PACKAGE_ACK_MINOR };

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_DATA_TRANSMISSION;
		apduBuffer[ISO7816.OFFSET_P1] = ApduConstants.INSTRUCTION_GET_VERSION; // instruction
		apduBuffer[ISO7816.OFFSET_P2] = (byte) 0x04; // packages
		assertProcessResponse(ack);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_DATA_TRANSMISSION;
		assertProcessResponse(ack);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_GET_VERSION;
		assertProcessResponse(new byte[] { ANONCardApplet.APPLET_VERSION_MAJOR, ANONCardApplet.APPLET_VERSION_MINOR });
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)} and
	 * {@link ANONCardApplet#getNextDataPackage(APDU)}.
	 */
	@Test
	public void testProcessGetNextDataPackage() {
		getDataSendChannel().reset();
		assertFalse(getDataSendChannel().isOpen());
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_GET_NEXT_DATA_PACKAGE;
		apduBuffer[ISO7816.OFFSET_P1] = 99;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_OPERATION);

		//three full packages
		byte[] data = new byte[3 * apduBuffer[ISO7816.OFFSET_P1]];
		for (int i = 0; i < data.length; i++) {
			data[i] = (byte) i;
		}
		getDataSendChannel().open(data);
		//out of bound request
		apduBuffer[ISO7816.OFFSET_P1] = 0;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);
		apduBuffer[ISO7816.OFFSET_P1] = 100;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);
		apduBuffer[ISO7816.OFFSET_P1] = 99;
		//get Data
		assertTrue(getDataSendChannel().isOpen());
		for (int i = 0; i < data.length; i += apduBuffer[ISO7816.OFFSET_P1]) {
			assertProcessResponse(mixconfig.tools.dataretention.smartcard.Helpers.copyOfRange(data, i, apduBuffer[ISO7816.OFFSET_P1]));
		}

		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_OPERATION);
		assertFalse(getDataSendChannel().isOpen());

		//half full package
		data = new byte[(int) (apduBuffer[ISO7816.OFFSET_P1] / 2) + 1];
		for (int i = 0; i < data.length; i++) {
			data[i] = (byte) i;
		}
		getDataSendChannel().open(data);
		assertTrue(getDataSendChannel().isOpen());
		for (int i = 0; i < data.length; i += apduBuffer[ISO7816.OFFSET_P1]) {
			assertProcessResponse(mixconfig.tools.dataretention.smartcard.Helpers.copyOfRange(data, i, data.length));
		}
		
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_OPERATION);
		assertFalse(getDataSendChannel().isOpen());
	}

}